Something went wrong. Try again.
fork of prime agent with changes i want but are not upstreamable probqbly (and some fixes)
Something went wrong. Try again.
7.2 kB · 203 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204/** * System prompt construction and project context loading */
import { buildChildAgentDoctrine, buildRlmPrompt, buildSubagentGuidance } from "./prompts/index.js";import { REFINE_SKILL_NAME } from "./refinement/index.js";import { formatSkillsForPrompt, getPythonSkillRuntimeInfo, type Skill } from "./skills.js";
export interface BuildSystemPromptOptions { /** Custom system prompt (replaces default). */ customPrompt?: string; /** Active tools. Tool schemas carry tool descriptions outside the prompt body. */ selectedTools?: string[]; /** Optional one-line tool snippets keyed by tool name. Used only for custom prompts. */ toolSnippets?: Record<string, string>; /** Additional guideline bullets appended to the system prompt. */ promptGuidelines?: string[]; /** Text to append to system prompt. */ appendSystemPrompt?: string; /** Working directory. */ cwd: string; /** Conversation log path. */ messagesPath?: string; /** Pre-loaded context files. */ contextFiles?: Array<{ path: string; content: string }>; /** Pre-loaded skills. */ skills?: Skill[]; /** Whether to include the model-facing rlm recursion guidance. */ allowRecursion?: boolean; /** Fixed recursive-agent depth for this session. */ rlmDepth?: number; /** Human-readable parent name or id for child communication doctrine. */ rlmParentAgent?: string; /** Enabled user-configured servers available through the generic kernel MCP API. */ genericMcpServers?: string[]; /** Remote execution host over SSH when running on a remote host. */ remoteHost?: string; /** Generated skill-surface digest published by the runtime, one line per call. */ skillDigest?: string;}
/** Build the system prompt with tools, guidelines, and context */export function buildSystemPrompt(options: BuildSystemPromptOptions): string { const { customPrompt, selectedTools, promptGuidelines, appendSystemPrompt, cwd, messagesPath, contextFiles: providedContextFiles, skills: providedSkills, allowRecursion, } = options; const promptCwd = cwd.replace(/\\/g, "/"); const promptMessagesPath = (messagesPath ?? "not persisted").replace(/\\/g, "/");
const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, "0"); const day = String(now.getDate()).padStart(2, "0"); const date = `${year}-${month}-${day}`;
const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
const contextFiles = providedContextFiles ?? []; const skills = providedSkills ?? []; const tools = selectedTools ?? ["ipython"]; const hasIpython = tools.includes("ipython"); const visibleSkills = skills.filter((skill) => !skill.disableModelInvocation); const visiblePythonSkillImportNames = getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName); const hasRefineSkill = visibleSkills.some((skill) => skill.name === REFINE_SKILL_NAME); const genericMcpSection = hasIpython ? formatGenericMcpGuidance(options.genericMcpServers) : "";
if (customPrompt) { let prompt = customPrompt;
// Append project context files if (contextFiles.length > 0) { prompt += "\n\n# Project Context\n\n"; prompt += "Project-specific instructions and guidelines:\n\n"; for (const { path: filePath, content } of contextFiles) { prompt += `## ${filePath}\n\n${content}\n\n`; } }
// Append skills section only when the model has a way to inspect skill files. const customPromptHasFileAccess = !selectedTools || selectedTools.includes("ipython") || selectedTools.includes("bash"); if (customPromptHasFileAccess && skills.length > 0) { prompt += formatSkillsForPrompt(skills); }
// Add date and working directory last prompt += `\nCurrent date: ${date}`; prompt += `\nCurrent working directory: ${promptCwd}`;
const childDoctrine = buildChildAgentDoctrine({ depth: options.rlmDepth, parentAgent: options.rlmParentAgent, installedSkills: visiblePythonSkillImportNames, activeTools: tools, }); if (childDoctrine) { prompt += `\n\n${childDoctrine}`; }
if (genericMcpSection) { prompt += `\n\n${genericMcpSection}`; }
if (appendSection) { prompt += appendSection; }
return prompt; }
let prompt = buildRlmPrompt({ cwd: promptCwd, messagesPath: promptMessagesPath, installedSkills: visiblePythonSkillImportNames, activeTools: tools.filter((name) => name === "ipython" || name === "bash" || name === "edit"), allowRecursion, depth: options.rlmDepth, parentAgent: options.rlmParentAgent, remoteHost: options.remoteHost, skillDigest: options.skillDigest, });
// Appended AFTER the trained buildRlmPrompt prefix: delegation doctrine precedes the subagent specs delivered via the harness digest. if ((allowRecursion ?? true) && hasIpython) { const visiblePythonSkillNames = new Set( getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName), ); prompt += `\n\n${buildSubagentGuidance({ includeRefineExamples: hasRefineSkill, hasAgentMessage: visiblePythonSkillNames.has("agent_message"), hasAgentObserve: visiblePythonSkillNames.has("agent_observe"), })}`; }
if (genericMcpSection) { prompt += `\n\n${genericMcpSection}`; }
const guidelines = formatPromptGuidelines(promptGuidelines); if (guidelines) { prompt += `\n\n# Additional Guidance\n\n${guidelines}`; }
// Append project context files if (contextFiles.length > 0) { prompt += "\n\n# Project Context\n\n"; prompt += "Project-specific instructions and guidelines:\n\n"; for (const { path: filePath, content } of contextFiles) { prompt += `## ${filePath}\n\n${content}\n\n`; } }
// Append skills section only when the model has a way to inspect skill files. const hasFileAccess = tools.includes("ipython") || tools.includes("bash"); if (hasFileAccess && skills.length > 0) { prompt += formatSkillsForPrompt(skills); }
if (appendSection) { prompt += appendSection; }
return prompt;}
function formatGenericMcpGuidance(servers: string[] | undefined): string { const enabledServers = [...new Set(servers ?? [])].sort((left, right) => left.localeCompare(right)); if (enabledServers.length === 0) return "";
return [ "# Generic MCP Connections", "", "Generic MCP connections are accessed through the pre-imported Python `mcp` object in the Python REPL, not as top-level native tool namespaces or installed Python skills.", `Enabled generic MCP servers: ${enabledServers.map((server) => `\`${server}\``).join(", ")}.`, ...enabledServers.map( (server) => `For \`${server}\`, first discover its tools with \`await mcp.list_tools("${server}")\`, then call one with \`await mcp.call_tool("${server}", "<tool>", arguments)\`.`, ), ].join("\n");}
function formatPromptGuidelines(promptGuidelines: string[] | undefined): string { const guidelinesList: string[] = []; const guidelinesSet = new Set<string>();
for (const guideline of promptGuidelines ?? []) { const normalized = guideline.trim(); if (normalized.length > 0 && !guidelinesSet.has(normalized)) { guidelinesSet.add(normalized); guidelinesList.push(normalized); } }
return guidelinesList.map((guideline) => `- ${guideline}`).join("\n");}