Files
oh-my-pi/packages/coding-agent/src/task/agents.ts
T
can1357 6240e7bb03 refactor(prompts): clarified agent and system guidance
- Standardized prompt format, removing XML-like tags.
- Emphasized RFC 2119 keywords using bolding across all prompts.
- Rewrote the core system prompt with enhanced structure and directives.
2026-02-24 02:50:20 +01:00

163 lines
4.5 KiB
TypeScript

/**
* Bundled agent definitions.
*
* Agents are embedded at build time via Bun's import with { type: "text" }.
*/
import { renderPromptTemplate } from "../config/prompt-templates";
import { parseAgentFields } from "../discovery/helpers";
import designerMd from "../prompts/agents/designer.md" with { type: "text" };
import exploreMd from "../prompts/agents/explore.md" with { type: "text" };
// Embed agent markdown files at build time
import agentFrontmatterTemplate from "../prompts/agents/frontmatter.md" with { type: "text" };
import planMd from "../prompts/agents/plan.md" with { type: "text" };
import reviewerMd from "../prompts/agents/reviewer.md" with { type: "text" };
import taskMd from "../prompts/agents/task.md" with { type: "text" };
import { parseFrontmatter } from "../utils/frontmatter";
import type { AgentDefinition, AgentSource } from "./types";
interface AgentFrontmatter {
name: string;
description: string;
tools?: string[];
spawns?: string;
model?: string | string[];
thinkingLevel?: string;
blocking?: boolean;
}
interface EmbeddedAgentDef {
fileName: string;
frontmatter?: AgentFrontmatter;
template: string;
}
function buildAgentContent(def: EmbeddedAgentDef): string {
const body = renderPromptTemplate(def.template);
if (!def.frontmatter) return body;
return renderPromptTemplate(agentFrontmatterTemplate, { ...def.frontmatter, body });
}
const EMBEDDED_AGENT_DEFS: EmbeddedAgentDef[] = [
{ fileName: "explore.md", template: exploreMd },
{ fileName: "plan.md", template: planMd },
{ fileName: "designer.md", template: designerMd },
{ fileName: "reviewer.md", template: reviewerMd },
{
fileName: "task.md",
frontmatter: {
name: "task",
description: "General-purpose subagent with full capabilities for delegated multi-step tasks",
spawns: "*",
model: "default",
thinkingLevel: "medium",
},
template: taskMd,
},
{
fileName: "quick_task.md",
frontmatter: {
name: "quick_task",
description: "Low-reasoning agent for strictly mechanical updates or data collection only",
model: "pi/smol",
thinkingLevel: "minimal",
},
template: taskMd,
},
];
const EMBEDDED_AGENTS: { name: string; content: string }[] = EMBEDDED_AGENT_DEFS.map(def => ({
name: def.fileName,
content: buildAgentContent(def),
}));
export class AgentParsingError extends Error {
constructor(
error: Error,
readonly source?: unknown,
) {
super(`Failed to parse agent: ${error.message}`, { cause: error });
this.name = "AgentParsingError";
}
toString(): string {
const details: string[] = [this.message];
if (this.source !== undefined) {
details.push(`Source: ${JSON.stringify(this.source)}`);
}
if (this.cause && typeof this.cause === "object" && "stack" in this.cause && this.cause.stack) {
details.push(`Stack:\n${this.cause.stack}`);
} else if (this.stack) {
details.push(`Stack:\n${this.stack}`);
}
return details.join("\n\n");
}
}
/**
* Parse an agent from embedded content.
*/
export function parseAgent(
filePath: string,
content: string,
source: AgentSource,
level: "fatal" | "warn" | "off" = "fatal",
): AgentDefinition {
const { frontmatter, body } = parseFrontmatter(content, {
location: filePath,
level,
});
const fields = parseAgentFields(frontmatter);
if (!fields) {
throw new AgentParsingError(new Error(`Invalid agent field: ${filePath}\n${content}`), filePath);
}
return {
...fields,
systemPrompt: body,
source,
filePath,
};
}
/** Cache for bundled agents */
let bundledAgentsCache: AgentDefinition[] | null = null;
/**
* Load all bundled agents from embedded content.
* Results are cached after first load.
*/
export function loadBundledAgents(): AgentDefinition[] {
if (bundledAgentsCache !== null) {
return bundledAgentsCache;
}
bundledAgentsCache = EMBEDDED_AGENTS.map(({ name, content }) => parseAgent(`embedded:${name}`, content, "bundled"));
return bundledAgentsCache;
}
/**
* Get a bundled agent by name.
*/
export function getBundledAgent(name: string): AgentDefinition | undefined {
return loadBundledAgents().find(a => a.name === name);
}
/**
* Get all bundled agents as a map keyed by name.
*/
export function getBundledAgentsMap(): Map<string, AgentDefinition> {
const map = new Map<string, AgentDefinition>();
for (const agent of loadBundledAgents()) {
map.set(agent.name, agent);
}
return map;
}
/**
* Clear the bundled agents cache (for testing).
*/
export function clearBundledAgentsCache(): void {
bundledAgentsCache = null;
}
// Re-export for backward compatibility
export const BUNDLED_AGENTS = loadBundledAgents;