The system prompt is made once per session (start, compaction, model switch), kept in session_meta and resent byte for byte; it holds no date. What changes mid-session -- the date, a mode the person chose, a plan or memory or instruction file they edited, a personality, MCP instructions that arrived later -- is a <session-note> on the next user message, stored with it. The tool list is fixed for the session: plan_submit is always offered and answers unavailable outside plan mode, the wrap-up keeps the tools and runs no call, a withdrawn tool stays listed and answers its refusal; the first request waits up to mcp_wait_ms for MCP servers. Compaction asks for its summary as the next turn of the same conversation. Cached input tokens are parsed (incl. llama.cpp timings), stored per request and shown in /context. Spec: context.md §7/§10, loop.json context.note (+ plan_ended, plan_own, personal, empty, mcp_wait_ms), modes.json plan.refused, compact.md without the transcript heading. Conformance area prefix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
36 files changed
+1533
-169
No files matched your search
+14
-2
@@ -25,6 +25,7 @@ import type { ImagePart } from "../provider/types.ts"
|
||||
import { ToolError, truncate, type Tool, type ToolResult } from "../tool/tool.ts"
|
||||
import { match } from "../permission/wildcard.ts"
|
||||
import { codeFrom, forget, OAuthProvider, waitForCallback, CALLBACK_PORT } from "./oauth.ts"
|
||||
import { mcpBlock } from "../session/prefix.ts"
|
||||
|
||||
export type ServerConfig = McpServer & { source: "global" | "project" }
|
||||
export type Status = "disabled" | "connecting" | "connected" | "failed" | "needs_auth"
|
||||
@@ -480,8 +481,13 @@ export class McpManager {
|
||||
|
||||
/** The system prompt's block of server instructions, or "". */
|
||||
instructions(): string {
|
||||
const parts = [...this.servers.values()].filter((s) => s.status === "connected" && s.instructions).map((s) => `<server name="${s.name}">\n${s.instructions}\n</server>`)
|
||||
return parts.length ? `Instructions from the MCP servers you have tools from (their tools are named mcp__<server>__…):\n<mcp_instructions>\n${parts.join("\n")}\n</mcp_instructions>` : ""
|
||||
return mcpInstructions(this.serverInstructions())
|
||||
}
|
||||
|
||||
/** Each connected server's own instructions, by server: what the prompt shows (mcpInstructions),
|
||||
* and what a session note compares (session/prefix.ts). */
|
||||
serverInstructions(): Record<string, string> {
|
||||
return Object.fromEntries([...this.servers.values()].filter((s) => s.status === "connected" && s.instructions).map((s) => [s.name, s.instructions!]))
|
||||
}
|
||||
|
||||
/** Sign in to a remote server: show the page, catch the redirect (or take a pasted one). */
|
||||
@@ -554,3 +560,9 @@ function withTimeout<T>(p: Promise<T>, ms: number, message: string): Promise<T>
|
||||
let t: ReturnType<typeof setTimeout>
|
||||
return Promise.race([p, new Promise<T>((_, reject) => (t = setTimeout(() => reject(new Error(message)), ms)))]).finally(() => clearTimeout(t))
|
||||
}
|
||||
|
||||
/** MCP servers' instructions as the system prompt carries them, "" for none. */
|
||||
export function mcpInstructions(by: Record<string, string>): string {
|
||||
const parts = Object.entries(by).map(([name, text]) => mcpBlock(name, text))
|
||||
return parts.length ? `Instructions from the MCP servers you have tools from (their tools are named mcp__<server>__…):\n<mcp_instructions>\n${parts.join("\n")}\n</mcp_instructions>` : ""
|
||||
}
|
||||
Reference in new issue
Block a user