Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
5.9 kB · 179 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180/** * Shared helpers for building the API cache-key prefix (systemPrompt, * userContext, systemContext) for query() calls. * * Lives in its own file because it imports from context.ts and * constants/prompts.ts, which are high in the dependency graph. Putting * these imports in systemPrompt.ts or sideQuestion.ts (both reachable * from commands.ts) would create cycles. Only entrypoint-layer files * import from here (QueryEngine.ts, cli/print.ts). */
import type { Command } from '../commands.js'import { getSystemPrompt } from '../constants/prompts.js'import { getSystemContext, getUserContext } from '../context.js'import type { MCPServerConnection } from '../services/mcp/types.js'import type { AppState } from '../state/AppStateStore.js'import type { Tools, ToolUseContext } from '../Tool.js'import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js'import type { Message } from '../types/message.js'import { createAbortController } from './abortController.js'import type { FileStateCache } from './fileStateCache.js'import type { CacheSafeParams } from './forkedAgent.js'import { getMainLoopModel } from './model/model.js'import { asSystemPrompt } from './systemPromptType.js'import { shouldEnableThinkingByDefault, type ThinkingConfig,} from './thinking.js'
/** * Fetch the three context pieces that form the API cache-key prefix: * systemPrompt parts, userContext, systemContext. * * When customSystemPrompt is set, the default getSystemPrompt build and * getSystemContext are skipped — the custom prompt replaces the default * entirely, and systemContext would be appended to a default that isn't * being used. * * Callers assemble the final systemPrompt from defaultSystemPrompt (or * customSystemPrompt) + optional extras + appendSystemPrompt. QueryEngine * injects coordinator userContext and memory-mechanics prompt on top; * sideQuestion's fallback uses the base result directly. */export async function fetchSystemPromptParts({ tools, mainLoopModel, additionalWorkingDirectories, mcpClients, customSystemPrompt,}: { tools: Tools mainLoopModel: string additionalWorkingDirectories: string[] mcpClients: MCPServerConnection[] customSystemPrompt: string | undefined}): Promise<{ defaultSystemPrompt: string[] userContext: { [k: string]: string } systemContext: { [k: string]: string }}> { const [defaultSystemPrompt, userContext, systemContext] = await Promise.all([ customSystemPrompt !== undefined ? Promise.resolve([]) : getSystemPrompt( tools, mainLoopModel, additionalWorkingDirectories, mcpClients, ), getUserContext(), customSystemPrompt !== undefined ? Promise.resolve({}) : getSystemContext(), ]) return { defaultSystemPrompt, userContext, systemContext }}
/** * Build CacheSafeParams from raw inputs when getLastCacheSafeParams() is null. * * Used by the SDK side_question handler (print.ts) on resume before a turn * completes — there's no stopHooks snapshot yet. Mirrors the system prompt * assembly in QueryEngine.ts:ask() so the rebuilt prefix matches what the * main loop will send, preserving the cache hit in the common case. * * May still miss the cache if the main loop applies extras this path doesn't * know about (coordinator mode, memory-mechanics prompt). That's acceptable — * the alternative is returning null and failing the side question entirely. */export async function buildSideQuestionFallbackParams({ tools, commands, mcpClients, messages, readFileState, getAppState, setAppState, customSystemPrompt, appendSystemPrompt, thinkingConfig, agents,}: { tools: Tools commands: Command[] mcpClients: MCPServerConnection[] messages: Message[] readFileState: FileStateCache getAppState: () => AppState setAppState: (f: (prev: AppState) => AppState) => void customSystemPrompt: string | undefined appendSystemPrompt: string | undefined thinkingConfig: ThinkingConfig | undefined agents: AgentDefinition[]}): Promise<CacheSafeParams> { const mainLoopModel = getMainLoopModel() const appState = getAppState()
const { defaultSystemPrompt, userContext, systemContext } = await fetchSystemPromptParts({ tools, mainLoopModel, additionalWorkingDirectories: Array.from( appState.toolPermissionContext.additionalWorkingDirectories.keys(), ), mcpClients, customSystemPrompt, })
const systemPrompt = asSystemPrompt([ ...(customSystemPrompt !== undefined ? [customSystemPrompt] : defaultSystemPrompt), ...(appendSystemPrompt ? [appendSystemPrompt] : []), ])
// Strip in-progress assistant message (stop_reason === null) — same guard // as btw.tsx. The SDK can fire side_question mid-turn. const last = messages.at(-1) const forkContextMessages = last?.type === 'assistant' && last.message.stop_reason === null ? messages.slice(0, -1) : messages
const toolUseContext: ToolUseContext = { options: { commands, debug: false, mainLoopModel, tools, verbose: false, thinkingConfig: thinkingConfig ?? (shouldEnableThinkingByDefault() !== false ? { type: 'adaptive' } : { type: 'disabled' }), mcpClients, mcpResources: {}, isNonInteractiveSession: true, agentDefinitions: { activeAgents: agents, allAgents: [] }, customSystemPrompt, appendSystemPrompt, }, abortController: createAbortController(), readFileState, getAppState, setAppState, messages: forkContextMessages, setInProgressToolUseIDs: () => {}, setResponseLength: () => {}, updateFileHistoryState: () => {}, updateAttributionState: () => {}, }
return { systemPrompt, userContext, systemContext, toolUseContext, forkContextMessages, }}