/** Prompt text for Ultracode's adaptive analysis-depth modes. */ import { ANALYSIS_DEPTHS, DEPTH_CRITERIA, DEPTH_SELECTION_RULES, type ActiveUltracodeMode, type AnalysisDepth } from "./depth.ts"; import { WORKFLOW_EFFORT_GUIDELINES } from "./effort-policy.ts"; /** One-line description shown by `/ultracode status` and the footer. */ export const ULTRACODE_TAGLINE = "semantic-depth workflow orchestration"; /** * The standing system-prompt section body (Pi adds the XML wrapper). Injected * on every active turn. Auto uses Jev when available, otherwise the parent * routes in its normal turn; neither path needs a separate router agent. */ export function ultracodeSystemBlock(mode: ActiveUltracodeMode = "deep", initialDepth?: AnalysisDepth): string { return [ `Configured mode: ${mode}.`, "Analysis depth is a semantic quality decision, never a wall-clock decision. Do not use elapsed time, deadlines, or duration limits to choose, lower, or stop analysis depth.", DEPTH_SELECTION_RULES, "Existing maxAgents/reserveAgents limits are structural admission bounds, not evidence that every available slot should be used.", "Ultracode does not change the parent session's effort; that remains under user control.", "", "Depth applicability and required verification:", ...ANALYSIS_DEPTHS.map((depth) => `- ${depth}: ${DEPTH_CRITERIA[depth]}`), "", ...modeInstructions(mode, initialDepth), "", "Evidence-driven escalation and stopping:", "- Escalate only for material correctness risk, missing direct evidence, conflicting findings, or an unresolved question that can change the answer.", "- Identify concrete failure consequences and the evidence needed to rule them out; a risk keyword alone is not an escalation trigger.", "- Stop when key claims have direct evidence, no material conflict or unresolved high-risk question remains, and another round would only repeat known evidence.", "- Model-reported confidence alone is not sufficient. Prefer concrete citations, reproduction, tests, and independent agreement.", "- If fixed focused/standard is insufficient, report the remaining uncertainty and recommend a deeper mode; in deep, report any irreducible uncertainty. Never silently exceed a fixed mode.", "", "Workflow policy:", "- Use a workflow only when independent decomposition, verification, isolation, or context scale provides real value. Otherwise solve directly in the parent session.", "- Make skeptics conditional: verify high-risk, conflicting, weakly evidenced, or low-confidence claims instead of automatically verifying every branch.", "- Avoid a separate synthesis agent when deterministic merging or parent synthesis is enough. Use an adjudicator only when a material conflict remains.", ...WORKFLOW_EFFORT_GUIDELINES.map((line) => `- ${line}`), "- When a workflow runs, log `analysis-depth: — ` before launching agents, `analysis-escalation: ...` for each semantic escalation, and `analysis-stop: ...` for the final evidence-based stop reason. Never use time as an escalation or stop reason.", ].join("\n"); } function modeInstructions(mode: ActiveUltracodeMode, initialDepth?: AnalysisDepth): string[] { if (mode === "auto") { return [ ...(initialDepth ? [`Initial analysis depth: ${initialDepth} (Jev). Start with its evidence requirements; this is not a fixed mode. Do not repeat initial classification or spawn a router agent.`] : ["Before acting, silently route this task to focused, standard, or deep using the criteria above. Do not spawn a router agent or make an extra model request for classification."]), "Begin at the shallowest sufficient depth and escalate only when evidence triggers an escalation condition below. Relevant conversation or repository evidence unavailable to the initial selector can justify immediate escalation.", ]; } return [ `Fixed analysis depth: ${mode}. Apply its criteria and verification requirements; do not silently switch to another depth.`, ...(mode === "focused" ? ["Prefer the normal parent-agent loop. Delegate only narrowly scoped work when it adds clear value."] : mode === "standard" ? ["Cover the material independent dimensions and use conditional verification, not an automatic adversarial panel."] : [ "Independent evidence can come from a distinct test, reproduction, proof, or source; a second agent is neither necessary nor sufficient.", "Use multi-perspective or adversarial investigation only where it adds evidence. Choose bounded fan-out and round limits if a workflow is needed; stop as soon as the evidence is sufficient, even in one round.", ]), ]; } /** Short reminder appended after the standing block. */ export const ULTRACODE_ACTIVE_REMINDER = "Reminder: Ultracode is active — obey its configured semantic depth, escalate only from evidence, and never use elapsed time as an analysis budget."; /** Tool description for the `workflow` tool. */ export const WORKFLOW_TOOL_DESCRIPTION = [ "Execute a deterministic JavaScript workflow that orchestrates a proportionate set of subagents for independent coverage, targeted verification, or work that exceeds one context.", "Choose the smallest workflow justified by the configured Ultracode depth and current evidence; workflow use and adversarial checks are not automatic.", "Each invocation must provide workflow source via `script`, `scriptPath`, or `name`. Inline `script` must be raw JavaScript (no Markdown fences) beginning with `export const meta = { name, description }` (a pure literal) and should call agent() at least once for useful orchestration.", "Available globals: agent(prompt, opts), parallel(thunks, options?), pipeline(items, ...stages), phase(title), log(message), workflow(name, args), args, cwd. The tool accepts maxAgents (default 128, max 1024) as a lifetime live-agent admission cap across resumes, not a token or depth budget; cache replay is free.", ].join(" "); /** One-line snippet for the Available tools section. */ export const WORKFLOW_PROMPT_SNIPPET = "Run a deterministic JS workflow with proportionate subagent fan-out. Header: export const meta = { name: 'snake_case', description: '...' }. Globals: agent/parallel/pipeline/phase/log/workflow/args/cwd."; /** Guideline bullets appended to the Guidelines section when the tool is active. */ export const WORKFLOW_GUIDELINES: string[] = [ "Use the workflow tool only when independent decomposition, targeted verification, isolation, or context scale adds value; use the parent agent directly for a bounded task.", "For an auto-depth workflow, log `analysis-depth: — ` before launching agents, `analysis-escalation: ...` when evidence requires more depth, and `analysis-stop: ...` when evidence is sufficient. Elapsed time must never determine depth.", "For workflow verification, run skeptics only for high-risk, conflicting, low-confidence, or weakly evidenced claims. Do not automatically attach a skeptic to every branch.", "For workflow synthesis, prefer structured results plus deterministic or parent-session merging. Start a synthesis/adjudication agent only for a material unresolved conflict, and normally give pure synthesis lower effort and no broad source-search mandate.", ...WORKFLOW_EFFORT_GUIDELINES, "For the workflow tool, provide workflow source with `script`, `scriptPath`, or `name`. Inline `script` must be one raw JavaScript string: no Markdown fences, no prose around the script.", "For the workflow tool, the script's first statement must be `export const meta = { name: 'short_snake_case', description: 'non-empty human description' }`. meta must be a pure literal: no variables, function calls, spreads, or template interpolation. meta.phases is optional and should mirror your phase() titles.", "For the workflow tool, write plain JavaScript after the meta export. No TypeScript syntax, imports, require(), fs, network, Date/Intl/Temporal, Math.random(), binary memory constructors, WebAssembly, or dynamic method calls such as value[key](...) (they bypass deterministic checks or resource bounds). Stamp timestamps after the workflow returns; vary randomness by agent index.", "For the workflow tool, a useful workflow should call agent() at least once. Each agent() call should pass a short unique label (2-5 words) so live status and error reporting stay readable.", "For the workflow tool, DEFAULT TO pipeline(items, ...stages): items flow through stages independently with no barrier, so item A can be in stage 3 while item B is still in stage 1. Only use parallel() (a barrier that awaits all thunks) when a later stage genuinely needs ALL prior results together (dedup/merge across the full set, early-exit on zero, cross-item comparison).", "For the workflow tool, parallel() takes functions, not promises: `await parallel(items.map(item => () => agent('...', { label: '...' })))`, never `await parallel(items.map(item => agent(...)))`. It reserves `options.reserveAgents ?? thunks.length` agent slots before any thunk starts; reserveAgents must cover every agent call in the panel because calls beyond it are fatal. Results are returned in input order; a normal thunk throw resolves to null, while policy/cancellation failures are fatal.", "For the workflow tool, pipeline(items, ...stages) passes each stage (previousValue, originalItem, index). A stage that throws drops that item to null and skips its remaining stages.", "For the workflow tool, if agent() needs machine-readable output pass an inline JSON Schema via opts.schema; agent() then returns the validated object. Use only the bounded subset: types, object/array structure, enum/const, anyOf/allOf, length/numeric constraints, and annotations. Unknown keywords, $ref variants, oneOf, format, pattern, and patternProperties are rejected. Keep schemas under 256 KiB / 64 levels and every agent/workflow output under 2 MiB. Use JSON Schema, not TypeScript or TypeBox constructors.", "For the workflow tool, when agent() is called WITHOUT a schema, its return value is the subagent's final assistant text (the last text the subagent produced). With a schema it returns the validated structured_output object. Prefer a schema for machine-readable results; use the text form only for prose summaries.", "Before writing workflow agent() effort suffixes, use the current ultracode_effort capability section: bare :level uses the default child model; an explicit model or agentType model uses its own supported set. Prefer exact provider/model IDs for overrides. Without capability context, supported efforts are unknown, not all seven levels.", "For the workflow tool, agent opts also accept: model (override the subagent model by pattern), agentType (use a custom subagent role/system-prompt), isolation:'worktree' (run the agent in an isolated git worktree — use ONLY when agents mutate files in parallel and would conflict), and phase (assign the agent to a progress group explicitly inside parallel()/pipeline()).", "For the workflow tool, workflow(name, args) runs a trust-aware saved workflow by name as a sub-step, sharing this run's concurrency, maxAgents, active reservations, and agent counter. Explicit nested script paths are not supported. Nesting is one level only. Child subagent sessions do not load ambient extensions or expose workflow/subagent orchestration tools, so they cannot start an independent recursive workflow chain.", "For workflow resumeFromRunId, reuse the exact same script and args. Resume is immutable, successful calls replay by stable structural call path, and maxAgents may only stay the same or increase; changed work must start a new run.", "For the workflow tool, failed agent()/parallel()/pipeline() branches return null and log the failure (unless the whole run is aborted or a policy limit is hit). Check for nulls before synthesizing conclusions, and prefer a final compact JSON-serializable result.", "For the workflow tool, directly await or return every orchestration promise (agent/parallel/pipeline/workflow). Native .then/.catch/.finally chains and Promise.all/allSettled/race/any are rejected; use parallel() or pipeline() so call identity stays deterministic. Unobserved, pending, or native same-scope concurrent orchestration is fatal.", "Workflow helpers that call orchestration must be directly declared functions/function variables or static methods on a declared object/stored class instance. Do not alias them, assign them later, forward through this.otherMethod(), or call them from temporary/awaited factory receivers; rewrite those forms as a direct declared helper so resume identity remains stable.", "For the workflow tool, do not assume subagents share the parent's repository context; include enough task context and relevant file paths in each agent prompt.", ];