refactor(subagent): split extension into modules
This commit is contained in:
73
src/prompts.ts
Normal file
73
src/prompts.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { parseFrontmatter } from "@mariozechner/pi-coding-agent";
|
||||
import { FINALIZE_TOOL_NAME, PROMPTS_DIR } from "./constants.ts";
|
||||
import type { PromptConfig } from "./types.ts";
|
||||
import { FinalizeStatus } from "./types.ts";
|
||||
|
||||
// Parse Tool List - Frontmatter may use YAML arrays or comma-delimited strings.
|
||||
export function parseToolList(value: unknown): string[] {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
.map(String)
|
||||
.map((tool) => tool.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value
|
||||
.split(",")
|
||||
.map((tool) => tool.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Discover Prompts - Load prompt markdown files from this extension's prompts dir.
|
||||
export function discoverPrompts(): PromptConfig[] {
|
||||
if (!fs.existsSync(PROMPTS_DIR)) return [];
|
||||
|
||||
const prompts: PromptConfig[] = [];
|
||||
const entries = fs.readdirSync(PROMPTS_DIR, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.name.endsWith(".md")) continue;
|
||||
if (!entry.isFile() && !entry.isSymbolicLink()) continue;
|
||||
|
||||
const filePath = path.join(PROMPTS_DIR, entry.name);
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
const { frontmatter, body } =
|
||||
parseFrontmatter<Record<string, unknown>>(content);
|
||||
|
||||
if (
|
||||
typeof frontmatter.name !== "string" ||
|
||||
typeof frontmatter.description !== "string"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
prompts.push({
|
||||
name: frontmatter.name,
|
||||
description: frontmatter.description,
|
||||
approvedTools: parseToolList(
|
||||
frontmatter.approved_tools ?? frontmatter.allowed_tools,
|
||||
),
|
||||
deniedTools: parseToolList(frontmatter.denied_tools),
|
||||
systemPrompt: body.trim(),
|
||||
filePath,
|
||||
});
|
||||
}
|
||||
|
||||
return prompts.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
// Build Finalize Prompt - Child agents must terminate by calling this tool.
|
||||
export function buildSubagentPrompt(agent: PromptConfig): string {
|
||||
const finalizePrompt = [
|
||||
"You are running as a subagent.",
|
||||
`When the task is complete, call ${FINALIZE_TOOL_NAME} as your final action.`,
|
||||
"Do not provide the final answer as normal assistant text.",
|
||||
`${FINALIZE_TOOL_NAME} requires status ${FinalizeStatus.SUCCESS} with result, or status ${FinalizeStatus.ERROR} with error and optional result.`,
|
||||
].join("\n");
|
||||
|
||||
return [agent.systemPrompt, finalizePrompt].filter(Boolean).join("\n\n");
|
||||
}
|
||||
Reference in New Issue
Block a user