fix(server): 修复内置 agent 切换时系统提示未注入及 @agent 出现在用户消息中的问题

- set_agent 控制消息处理中,查找对应 AgentDefinition 并将其 getSystemPrompt()
  写入 options.systemPrompt,使 QueryEngine.ask() 能正确使用 agent 系统提示
- 将 "build"(前端默认模式的显示名称)处理为 undefined,切换回默认模式时
  同步清空 options.systemPrompt 和 mainThreadAgentType
- /prompt 和 /prompt_async 接口不再将 agentMentions (@agent-*) 拼入 content,
  该语法仅用于 REPL 命令模式,出现在 server 模式的 prompt 中会被模型误解

Co-Authored-By: Sonnet-4.6-CoStrict <noreply@anthropic.com>
This commit is contained in:
Askhz 2026-05-12 17:50:07 +08:00
parent b6c353977d
commit e7c384bca5
2 changed files with 30 additions and 7 deletions

View File

@ -3100,9 +3100,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') {

View File

@ -382,8 +382,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')
@ -435,8 +437,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')