Config split: agent.json (connection) + config.json (LLM)
- loadAgentConfig() reads both files with priority: env > config.json > agent.json - Remote config merge from auth.ok (model, provider, prompt) - Local config.json overrides remote values - Transport default changed to 'ws'
This commit is contained in:
parent
1c7fdf8d77
commit
6871fdb443
@ -116,7 +116,7 @@ export function hasAgentConfig(): boolean {
|
||||
export function loadAgentConfig(): AgentConfig {
|
||||
const { configPath, agentHome } = resolveConfig();
|
||||
|
||||
// Load file if available, otherwise empty object
|
||||
// Load agent.json (connection config)
|
||||
let file: Record<string, unknown> = {};
|
||||
if (configPath) {
|
||||
if (!fs.existsSync(configPath)) {
|
||||
@ -125,6 +125,17 @@ export function loadAgentConfig(): AgentConfig {
|
||||
file = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
}
|
||||
|
||||
// Load config.json (LLM config) — separate file, optional
|
||||
let llm: Record<string, unknown> = {};
|
||||
const llmConfigPath = configPath
|
||||
? path.join(path.dirname(configPath), 'config.json')
|
||||
: agentHome
|
||||
? path.join(agentHome, 'config.json')
|
||||
: null;
|
||||
if (llmConfigPath && fs.existsSync(llmConfigPath)) {
|
||||
llm = JSON.parse(fs.readFileSync(llmConfigPath, 'utf-8'));
|
||||
}
|
||||
|
||||
const trackerUrl = process.env.TRACKER_URL || (file.tracker_url as string) || '';
|
||||
const token = process.env.AGENT_TOKEN || (file.token as string) || '';
|
||||
|
||||
@ -144,22 +155,23 @@ export function loadAgentConfig(): AgentConfig {
|
||||
|
||||
const wsUrl = process.env.AGENT_WS_URL || (file.ws_url as string) || '';
|
||||
|
||||
// Priority: env > config.json (LLM) > agent.json (legacy compat) > defaults
|
||||
return {
|
||||
name: (file.name as string) || process.env.AGENT_NAME || 'Agent',
|
||||
slug: (file.slug as string) || process.env.AGENT_SLUG || 'agent',
|
||||
prompt: (file.prompt as string) || process.env.AGENT_PROMPT || '',
|
||||
prompt: (llm.prompt as string) || (file.prompt as string) || process.env.AGENT_PROMPT || '',
|
||||
trackerUrl,
|
||||
wsUrl,
|
||||
token,
|
||||
transport: (process.env.AGENT_TRANSPORT || (file.transport as string) || 'http') as 'http' | 'ws',
|
||||
transport: (process.env.AGENT_TRANSPORT || (file.transport as string) || 'ws') as 'http' | 'ws',
|
||||
listenPort: parseInt(process.env.AGENT_PORT || String(file.listen_port || '3200'), 10),
|
||||
workDir,
|
||||
agentHome: resolvedHome || workDir,
|
||||
capabilities: (file.capabilities as string[]) || ['coding'],
|
||||
maxConcurrentTasks: (file.max_concurrent_tasks as number) || 2,
|
||||
model: process.env.PICOGENT_MODEL || (file.model as string) || 'sonnet',
|
||||
provider: process.env.PICOGENT_PROVIDER || (file.provider as string) || 'anthropic',
|
||||
apiKey: process.env.PICOGENT_API_KEY || process.env.ANTHROPIC_API_KEY || (file.api_key as string) || '',
|
||||
maxConcurrentTasks: (llm.max_concurrent_tasks as number) || (file.max_concurrent_tasks as number) || 2,
|
||||
model: process.env.PICOGENT_MODEL || (llm.model as string) || (file.model as string) || 'sonnet',
|
||||
provider: process.env.PICOGENT_PROVIDER || (llm.provider as string) || (file.provider as string) || 'anthropic',
|
||||
apiKey: process.env.PICOGENT_API_KEY || process.env.ANTHROPIC_API_KEY || (llm.api_key as string) || (file.api_key as string) || '',
|
||||
heartbeatIntervalSec: (file.heartbeat_interval_sec as number) || 30,
|
||||
allowedPaths: (file.allowed_paths as string[]) || [],
|
||||
sessionId: ensureSessionId(file, configPath),
|
||||
|
||||
19
src/index.ts
19
src/index.ts
@ -51,6 +51,25 @@ async function startAgentWs(config: AgentConfig, client: TrackerClient): Promise
|
||||
router.setProjectMappings(wsTransport.projects);
|
||||
}
|
||||
|
||||
// Merge remote config (Tracker is source of truth, local config.json overrides)
|
||||
if (wsTransport.remoteConfig) {
|
||||
const rc = wsTransport.remoteConfig;
|
||||
// Only apply remote values if local config.json didn't set them
|
||||
// (loadAgentConfig already prioritized config.json > agent.json)
|
||||
if (rc.model && !process.env.PICOGENT_MODEL && config.model === 'sonnet') {
|
||||
config.model = rc.model;
|
||||
logger.info('Applied remote model: %s', rc.model);
|
||||
}
|
||||
if (rc.provider && !process.env.PICOGENT_PROVIDER && config.provider === 'anthropic') {
|
||||
config.provider = rc.provider;
|
||||
logger.info('Applied remote provider: %s', rc.provider);
|
||||
}
|
||||
if (rc.prompt && !config.prompt) {
|
||||
config.prompt = rc.prompt;
|
||||
logger.info('Applied remote prompt (%d chars)', rc.prompt.length);
|
||||
}
|
||||
}
|
||||
|
||||
const shutdown = () => {
|
||||
logger.info('Shutting down agent (ws)...');
|
||||
wsTransport.stop().then(() => {
|
||||
|
||||
@ -36,6 +36,14 @@ export class WsClientTransport implements TaskTracker {
|
||||
projects: Array<{ id: string; slug: string; name: string; chat_id?: string }> = [];
|
||||
/** Online members from auth.ok */
|
||||
online: string[] = [];
|
||||
/** Remote agent config from auth.ok (if agent) */
|
||||
remoteConfig: {
|
||||
model?: string;
|
||||
provider?: string;
|
||||
prompt?: string;
|
||||
max_concurrent_tasks?: number;
|
||||
capabilities?: string[];
|
||||
} | null = null;
|
||||
|
||||
constructor(private config: AgentConfig) {}
|
||||
|
||||
@ -205,11 +213,25 @@ export class WsClientTransport implements TaskTracker {
|
||||
this.projects = (data.projects as Array<{ id: string; slug: string; name: string; chat_id?: string }>) || [];
|
||||
this.online = (data.online as string[]) || (data.agents_online as string[]) || [];
|
||||
|
||||
// Remote agent config (if present)
|
||||
const agentConfig = data.agent_config as Record<string, unknown> | undefined;
|
||||
if (agentConfig) {
|
||||
this.remoteConfig = {
|
||||
model: agentConfig.model as string | undefined,
|
||||
provider: agentConfig.provider as string | undefined,
|
||||
prompt: agentConfig.prompt as string | undefined,
|
||||
max_concurrent_tasks: agentConfig.max_concurrent_tasks as number | undefined,
|
||||
capabilities: agentConfig.capabilities as string[] | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
this.log.info('━━━ AUTH OK ━━━');
|
||||
this.log.info(' Lobby chat: %s', this.lobbyChatId || '(none)');
|
||||
this.log.info(' Projects: %s', this.projects.map(p => `${p.slug}(${p.id})`).join(', ') || '(none)');
|
||||
this.log.info(' Online: %s', this.online.join(', ') || '(nobody)');
|
||||
this.log.info(' Full auth data: %s', JSON.stringify(data, null, 2));
|
||||
if (this.remoteConfig) {
|
||||
this.log.info(' Remote config: model=%s provider=%s', this.remoteConfig.model || '-', this.remoteConfig.provider || '-');
|
||||
}
|
||||
|
||||
this.authenticated = true;
|
||||
this.reconnectDelay = 1000;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user