diff --git a/src/cli/print.ts b/src/cli/print.ts index 5abf2d7ae..0fbfd9517 100644 --- a/src/cli/print.ts +++ b/src/cli/print.ts @@ -3108,9 +3108,28 @@ function runHeadlessStreaming( sendControlResponseSuccess(msg) } else if (msg.request.subtype === 'set_agent') { const agent = typeof msg.request.agent === 'string' ? msg.request.agent : undefined - if (agent) { - setMainThreadAgentType(agent) - saveAgentSetting(agent) + // 'build' is the frontend display name for the default (no-agent) mode. + // Treat it as clearing the agent, same as undefined. + const resolvedAgent = agent === 'build' ? undefined : agent + setMainThreadAgentType(resolvedAgent) + saveAgentSetting(resolvedAgent ?? '') + if (resolvedAgent) { + // Apply the agent's system prompt so QueryEngine picks it up on the next turn. + // QueryEngine.ask() uses options.systemPrompt (customSystemPrompt) directly, + // bypassing buildEffectiveSystemPrompt/mainThreadAgentDefinition. For built-in + // agents the getSystemPrompt params are ignored; pass a minimal stub. + const agentDef = currentAgents.find(a => a.agentType === resolvedAgent) + if (agentDef) { + const agentSystemPrompt = isBuiltInAgent(agentDef) + ? agentDef.getSystemPrompt({ toolUseContext: { options: {} as never } }) + : agentDef.getSystemPrompt() + if (agentSystemPrompt) { + options.systemPrompt = agentSystemPrompt + } + } + } else { + // Switching back to default mode: clear any previously applied agent system prompt. + options.systemPrompt = undefined } sendControlResponseSuccess(msg) } else if (msg.request.subtype === 'set_max_thinking_tokens') { diff --git a/src/server/routes/session.ts b/src/server/routes/session.ts index 82f42d34e..28bebc0a8 100644 --- a/src/server/routes/session.ts +++ b/src/server/routes/session.ts @@ -393,8 +393,10 @@ export function createSessionRoutes( .join('\n') ?? '' const agentParts = body.parts?.filter((p) => p.type === 'agent' && p.name) ?? [] - const agentMentions = agentParts.map((p) => `@agent-${p.name}`).join(' ') - const content = [textContent, agentMentions].filter(Boolean).join('\n') + // Agent switching is handled via setAgent() control message below. + // Do not append @agent-* mentions to content — they are REPL-only syntax + // and would be sent verbatim to the model in server mode. + const content = textContent if (!content) throw badRequest('content is required') if (handle.prompting) throw conflict('session is already processing a prompt') @@ -432,8 +434,10 @@ export function createSessionRoutes( .join('\n') ?? '' const agentParts = body.parts?.filter((p) => p.type === 'agent' && p.name) ?? [] - const agentMentions = agentParts.map((p) => `@agent-${p.name}`).join(' ') - const content = [textContent, agentMentions].filter(Boolean).join('\n') + // Agent switching is handled via setAgent() control message below. + // Do not append @agent-* mentions to content — they are REPL-only syntax + // and would be sent verbatim to the model in server mode. + const content = textContent if (!content) { throw badRequest('content is required')