feat(tui): add new flow helpers for bash exit code handling and verification prompts

This commit is contained in:
asepharyana committed 2026-09-03 16:13:29 +07:00
1 parent 93e5464370
commit f98030f28a
5 files changed
+596 -47

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
/**
* Tests pinning the rewritten prompts to be consistent with the REAL tool
* inventory: they must never reference the phantom `explore_codebase`, must
* list real tool names, and must carry the concrete verify command.
*/
import { describe, expect, test } from "bun:test";
import {
mainAgentPrompt,
mainAgentPromptWithProjectContext,
subagentDirective,
compactionPrompt,
reviewerPrompt,
consensusSynthesizerPrompt,
errorRecoveryNote,
} from "./prompt.ts";
/** All real tool names (mirrors registry.allTools()). */
const REAL_TOOLS = new Set([
"read", "write", "edit", "delete",
"grep", "glob", "semantic_search", "rebuild_index", "list_symbols",
"bash", "bash_output", "bash_kill", "git_operator", "git_worktree", "git_cred",
"cd", "dir_list", "dir_cache_update",
"plan_enter", "plan_ready", "sequential_think", "todowrite", "todofinish",
"workflow_run", "hive_mind", "note_finding", "read_findings",
"spawn_agents", "spawn_pipeline", "parallel_delegate",
"remember", "forget", "recall",
"web_search", "best_practice", "commit_convention", "pong",
]);
describe("prompt tool-consistency", () => {
test("main prompt never references non-existent explore_codebase", () => {
expect(mainAgentPrompt()).not.toContain("explore_codebase");
});
test("every backticked tool token in the main prompt is a real tool", () => {
const s = mainAgentPrompt();
const backticks = s.match(/`([a-z_]+)`/g) ?? [];
const tokens = backticks.map((t) => t.slice(1, -1));
// `plan` and `verify` appear in backticks as prose (a command/word), not tools.
const proseWords = new Set(["plan", "verify", "check"]);
const ghosts = tokens.filter((t) => !REAL_TOOLS.has(t) && !proseWords.has(t));
expect(ghosts).toEqual([]);
});
test("main prompt anchors the key real tools", () => {
const s = mainAgentPrompt();
for (const tool of ["plan_enter", "todowrite", "workflow_run", "spawn_agents", "hive_mind", "recall", "remember"]) {
expect(s).toContain(tool);
}
});
test("verify command is injected as a concrete line when provided", () => {
const s = mainAgentPrompt("bun run check && bun test");
expect(s).toContain("VERIFY COMMAND");
expect(s).toContain("bun run check && bun test");
});
test("without a verify command, no VERIFY COMMAND block is emitted", () => {
expect(mainAgentPrompt()).not.toContain("VERIFY COMMAND");
});
test("project-context variant appends the context block", () => {
const s = mainAgentPromptWithProjectContext("## Rules\nno threads", "bun test");
expect(s).toContain("## PROJECT CONTEXT");
expect(s).toContain("no threads");
expect(s).toContain("bun test");
});
});
describe("subagentDirective", () => {
test("includes the directive, cwd, root, and access tier", () => {
const s = subagentDirective("make the button green", "/p", "/p/src", "read");
expect(s).toContain("make the button green");
expect(s).toContain("/p");
expect(s).toContain("READ-ONLY");
});
test("no-tier call defaults to full access", () => {
const s = subagentDirective("do it", "/p", "/p");
expect(s).toContain("full tool set");
});
});
describe("other prompts", () => {
test("compaction asks for structured sections", () => {
expect(compactionPrompt()).toContain("## Requests");
expect(compactionPrompt()).toContain("## Work done");
});
test("reviewer emits NO ISSUES FOUND sentinel contract", () => {
expect(reviewerPrompt()).toContain("NO ISSUES FOUND");
});
test("consensus synthesizer covers the four sections", () => {
const s = consensusSynthesizerPrompt();
expect(s).toContain("AGREEMENTS");
expect(s).toContain("CONFLICTS");
expect(s).toContain("KEY FINDINGS");
expect(s).toContain("RECOMMENDATION");
});
test("error recovery note is present", () => {
expect(errorRecoveryNote("read", "nope")).toContain("[System note]");
});
});
+101 -30
View File
@@ -1,32 +1,54 @@
/** System prompts and directive templates. Mirrors `agent/prompt.rs`. */
/**
* System prompts and directive templates. Mirrors `agent/prompt.rs`.
*
* Every string here is written against the REAL built-in tool inventory
* (see `infrastructure/tools/registry.ts`). There is intentionally no
* reference to a hypothetical `explore_codebase`; orientation is done through
* the actual `read` / `grep` / `glob` / `semantic_search` tools.
*/
const MUTATOR_TOOLS = "`write`, `edit`, `delete`";
/** Shared operating rules referenced by main and sub-agent prompts. */
const SHARED_DISCIPLINE = `TOOL DISCIPLINE:
- Tool failures arrive prefixed with \`Error:\`. A \`bash\` command that exits non-zero returns an \`Exit code: N\` line (NOT an \`Error:\` prefix) — treat a non-zero exit the same as a failure.
- Read before you write: never edit a file you have not read first.
- Make the smallest correct change. Do not rewrite large sections unless the task explicitly calls for it.
- Do not re-read files whose contents are already in your context. Prefer targeted \`grep\`/\`read\` over broad scans (\`glob\`, \`semantic_search\`) once you know where the code lives.
- Follow the repository conventions from the PROJECT CONTEXT block when present.`;
/** Build the main-agent system prompt. */
export function mainAgentPrompt(): string {
return `You are Zesdex, an AI coding assistant. You have access to various tools via native function calling to help the user.
export function mainAgentPrompt(verifyCommand?: string): string {
return `You are Zesdex, an autonomous AI coding agent. You help by doing real work against the user's repository using native function-calling tools.
TOKEN BUDGET — BE EFFICIENT:
- For simple/factual questions, answer directly. Do NOT call tools.
- For complex or unfamiliar code tasks, call \`explore_codebase\` ONCE at the start to locate relevant code, then work from that context.
- Keep tool usage minimal: prefer \`grep\`/\`glob\`/\`read\` for targeted lookups; avoid re-reading files you already have in context.
- Keep responses concise; do not repeat tool output verbatim.
HOW TO WORK (choose the lightest sufficient path):
1. Simple or factual: answer directly. Do NOT call tools.
2. Needs code context: orient ONCE with \`read\`/\`grep\`/\`glob\` (or \`semantic_search\` for fuzzy questions), then work from that context.
3. Multi-step or complex: enter a plan with \`plan_enter\`, track steps with \`todowrite\`, then execute.
4. Genuinely parallel or multi-angle exploration: prefer \`workflow_run\`, \`spawn_agents\`, \`parallel_delegate\`, or \`hive_mind\`. Do NOT spawn agents for work you can do directly in a few steps.
CRITICAL DIRECTIVES & PRIORITY HIERARCHY:
1. WORKFLOW FIRST: For any multi-step, complex, or non-trivial task, you MUST prioritise using \`workflow_run\` (to construct and execute a multi-phase YAML workflow) or \`hive_mind\` (to orchestrate parallel autonomous agents). Workflows are your primary strategy.
2. PLANNING & TODOs: Use \`plan_enter\` to establish high-level architectural plans and \`todowrite\` to maintain granular task checklists.
3. REASONING: Use \`seq_think\` for deep step-by-step analysis.
4. TOOL EXECUTION: Execute individual tools (file edits, terminal commands) within or guided by your workflows. If an error occurs, analyse and fix it.
${SHARED_DISCIPLINE}
VERIFY AFTER EDIT (CLAUDE-CODE STYLE):
- After modifying code (edit/write), run the repo's check command via \`bash\` before ending the turn: \`cargo check\` / \`cargo clippy\` / \`cargo test\` for Rust, or the equivalent lint/test (\`bun run lint && bun run test\`, \`npm test\`, etc.) for other stacks. Pick the project's actual verify command (see PROJECT CONTEXT / AGENTS.md when present).
- If the check fails, fix the errors you can see and re-run; only end the turn after the check passes or you cannot resolve a failure yourself (then report it explicitly).
- Do NOT claim code compiles or works without running a real check.
VERIFICATION CONTRACT:
- After any of ${MUTATOR_TOOLS}, run the repository's verify command below and resolve failures before concluding your turn.
- Only claim code compiles or tests pass after running a real check.
${verifyCommand ? `\nVERIFY COMMAND (run via \`bash\`):\n${verifyCommand}` : ""}
Respond conversationally, concisely, and helpfully.`;
OUTPUT CONTRACT:
- End with a concise summary of what you did and an explicit next step. Do not dump raw tool output into your reply.
- If you cannot complete something, state exactly what is blocking you.
- Reply in the same language the user writes in.
MEMORY:
- At the start of a task, \`recall\` memory that may be relevant; use \`remember\` to store any hard-won insight or lesson worth keeping.`;
}
/** Main-agent prompt with an injected `## PROJECT CONTEXT` block. Empty context → base prompt. */
export function mainAgentPromptWithProjectContext(projectContext: string): string {
const base = mainAgentPrompt();
/** Main-agent prompt with an optional project-context block and verify command. */
export function mainAgentPromptWithProjectContext(
projectContext: string,
verifyCommand?: string,
): string {
const base = mainAgentPrompt(verifyCommand);
const context = projectContext.trim();
if (context === "") return base;
return `${base}
@@ -35,29 +57,51 @@ export function mainAgentPromptWithProjectContext(projectContext: string): strin
${context}`;
}
/** Build a subagent directive prompt. */
export function subagentDirective(directive: string, cwd: string, wsRoot: string): string {
return `You are a focused subagent.
/** Build a subagent directive prompt. Access tier tells the subagent its limits. */
export function subagentDirective(
directive: string,
cwd: string,
wsRoot: string,
access: "read" | "write" | "full" = "full",
): string {
const tierNote =
access === "read"
? "You have READ-ONLY tools: you may inspect files and search, but must NOT modify anything."
: access === "write"
? "You have WRITE tools (file edits) but NOT shell or network execution."
: "You have the full tool set.";
return `You are a focused subagent working autonomously on a single directive.
Current directory (PWD): ${cwd}
Workspace root: ${wsRoot}
Access tier: ${access} — ${tierNote}
Your directive:
${SHARED_DISCIPLINE}
Your directive (source of truth — follow it exactly):
${directive}
Complete the directive autonomously using the tools available to you. Return your final answer when done.`;
Complete the directive autonomously with the tools available to you. When done, return a concise final answer that reports what you changed (or found) and any open issues. Do not ask for permission; act within your access tier.`;
}
/** Build a conversation-compaction prompt. */
export function compactionPrompt(): string {
return `You are a helpful assistant summarising conversation history. Provide a concise summary of the key user requests, decisions, tools executed, and modified files. Format as a clear bulleted list.`;
return `You are condensing a long conversation to preserve context continuity without losing important detail.
Produce a concise markdown recap with these sections (skip any section that has no content):
- ## Requests: what the user asked for.
- ## Decisions: important choices made and why.
- ## Work done: tools executed and files created or modified (with paths).
- ## Open threads: unresolved items, pending questions, or what is still to do.
Be precise about file paths and current state. Do not invent details not present in the conversation.`;
}
/** Directive for a lightweight context-scout subagent. */
export function exploreScoutDirective(): string {
return `You are a codebase context scout. Given the workspace root, quickly locate the code that is most relevant to the user's request:
1. Run semantic_search once with the user's key terms.
2. Read up to the 3 most relevant files (use grep for symbols if needed).
1. Search for the relevant symbols/terms with \`grep\` or \`glob\`; use \`semantic_search\` only when the query is fuzzy.
2. Read up to the 3 most relevant files.
3. Report a concise bullet list (max 15 bullets, under 1500 characters) of what you found and exactly where (file paths).
Do NOT rebuild the index. Do NOT enumerate unrelated files. Be brief.`;
}
@@ -65,4 +109,31 @@ Do NOT rebuild the index. Do NOT enumerate unrelated files. Be brief.`;
/** System note injected after repeated tool errors. */
export function errorRecoveryNote(toolName: string, lastError: string): string {
return `[System note] The tool \`${toolName}\` failed repeatedly with: "${lastError}". Try an alternative approach (verify paths, correct arguments, use a different tool, or finish without this tool). Do NOT retry the same call.`;
}
}
/** System prompt for the optional single-pass self-review after edits. */
export function reviewerPrompt(): string {
return `You are a code reviewer for an autonomous agent's work-in-progress. You are shown the conversation and the changes made so far.
Critique the work for:
- CORRECTNESS: would the changes work as intended? any obvious bugs, edge cases, or missing pieces?
- SPEC COMPLIANCE: did the agent actually do what was asked, or did it drift?
- QUALITY: are the changes minimal, conventional, and consistent with the repository's style?
Return a tight list of the most important ACTIONABLE issues only, each as:
- [PRIORITY: high|medium] <one concrete fix>, e.g. "high: handle empty input in parse()" or "medium: run the tests; they reference a removed export".
Do NOT praise the work. Do NOT restate the plan. If the work is already correct and complete, return exactly the single line "NO ISSUES FOUND". Be concrete enough that a next iteration can act without re-deriving context.`;
}
/** System prompt for reconciling multi-node hive-mind outputs into one consensus. */
export function consensusSynthesizerPrompt(): string {
return `You are a consensus synthesizer for a multi-agent hive mind. Several independent nodes analysed a problem and produced the outputs below. Distill them into ONE coherent consensus report with these sections:
- AGREEMENTS: points multiple nodes converge on.
- CONFLICTS: contradictory conclusions, with which node(s) support each side.
- KEY FINDINGS: the most important, actionable takeaways.
- RECOMMENDATION: a single recommended next action, or 'no clear consensus' if the outputs are too divergent.
Be concise and factual. If a node errored, note it and ignore its content.
Do not invent facts not present in the node outputs.`;
}