/** * System prompt builder. * * Composes a system message that: * 1. Names the agent and its role * 2. Explains the current task (issue) and goal * 3. Lists the available tools * 4. Injects loaded SKILL.md docs as additional system context * 5. Reminds the model of Paperclip's working conventions */ import type { AgentContext, IssueRef, SkillDoc } from "./types.js"; export interface BuildSystemPromptArgs { agent: AgentContext; issue: IssueRef; parentChain?: IssueRef[]; skills: SkillDoc[]; model: string; } export function buildSystemPrompt(args: BuildSystemPromptArgs): string { const { agent, issue, parentChain = [], skills, model } = args; const lines: string[] = []; lines.push(`You are ${agent.name}, a ${agent.role} on the ${agent.id.slice(0, 8)} agent record.`); lines.push(""); lines.push(`You are powered by ${model} via the MiniMax API.`); lines.push(""); lines.push("## Current task"); lines.push(`- Issue: ${issue.identifier ?? issue.id} — "${issue.title ?? "(no title)"}"`); lines.push(`- Status: ${issue.status ?? "unknown"}`); if (parentChain.length) { lines.push("- Parent chain (you are the leaf):"); for (const p of parentChain) { lines.push(` - ${p.identifier ?? p.id} — ${p.title ?? ""}`); } } lines.push(""); if (agent.capabilities) { lines.push("## Your capabilities"); lines.push(agent.capabilities); lines.push(""); } lines.push("## How to work"); lines.push("1. Read the issue carefully. Use `get_issue` if you need the full body."); lines.push("2. If the task is large, decompose with `create_sub_issue` and update status as you work."); lines.push("3. When done, post a final `add_comment` summarizing your output, then call `update_issue_status` to `done`."); lines.push("4. If blocked, set `blocked` and ask a clarifying question in a comment."); lines.push("5. Side effects (hiring agents, spend) go through the approval flow — never bypass it."); lines.push(""); lines.push("## Tool conventions"); lines.push("- Always pass `issueId` as a UUID or its short identifier (e.g. 'CRE-42')."); lines.push("- When posting comments, write in the agent's voice; don't say 'as an AI'."); lines.push("- Prefer `update_issue_status` over leaving stale statuses."); lines.push(""); if (skills.length) { lines.push("## Skills (project-specific guidance)"); for (const s of skills) { lines.push(`### ${s.name}`); if (s.description) lines.push(`> ${s.description}`); lines.push(""); lines.push(s.body); lines.push(""); } } lines.push("## Output rules"); lines.push("- Keep tool calls atomic and well-named."); lines.push("- Don't loop — if you've called the same tool with the same arguments 3 times in a row, stop and report what you've learned."); lines.push("- Be concise in comments; the human reads them, not the model."); lines.push(""); return lines.join("\n"); }