feat: in-app Orchestrator (Phase 2) — multi-agent conductor
Brings the deterministic Han-flow conductor into BooCode: launch any read-only flow from BooChat or BooCoder, watch each agent stream live in a Paseo-style run pane, get an evidence-disciplined report — on local Qwen, persisted and resumable. Read-only enforced hard via qwen --approval-mode plan (orchestrator tasks fail closed if qwen is unavailable; never fall to write-capable native). Backend (apps/coder): re-homed conductor defs, flow_runs/flow_steps schema, flow-runner + dispatcher onTaskTerminal hook, restart-resume, runs routes (launch/list/get/cancel), user-channel WS. Contracts: two flow_run_* frames. Web: orchestrator pane kind + OrchestratorPane, Workflow button + slash flows (BooChat/BooCoder parity), FlowLauncherDialog, "New Orchestrator" in the + and split menus, runs history + export. Plan: openspec/changes/orchestrator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
152
apps/coder/src/conductor/flows/discovery.ts
Normal file
152
apps/coder/src/conductor/flows/discovery.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import type { Spine } from '../types.js';
|
||||
import { q, repoLine } from './_util.js';
|
||||
|
||||
/** Han `gap-analysis` — what's missing/conflicting between two artifacts. */
|
||||
export const gapAnalysis: Spine = {
|
||||
name: 'gap-analysis',
|
||||
description: 'gaps between two artifacts (impl vs spec, etc.)',
|
||||
angles: [
|
||||
{
|
||||
id: 'gap',
|
||||
agent: 'gap-analyzer',
|
||||
label: 'Gap analysis (gap-analyzer)',
|
||||
task: (ctx) =>
|
||||
`Perform a gap analysis for the comparison below — what is missing, incomplete, conflicting, or assumed when checking the current state against the desired/reference state. Cite locations.${repoLine(ctx)}\n\nCOMPARISON: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/** Han `project-discovery` — map a repo's stack, structure, and tooling. */
|
||||
export const projectDiscovery: Spine = {
|
||||
name: 'project-discovery',
|
||||
description: 'discover a repo: stack, structure, tooling',
|
||||
angles: [
|
||||
{
|
||||
id: 'scan',
|
||||
agent: 'project-scanner',
|
||||
label: 'Project scan (project-scanner)',
|
||||
task: (ctx) =>
|
||||
`Scan the repository and report its languages, frameworks, build/test tooling, configuration, entry points, and directory structure. Cite files.${repoLine(ctx)}\n\nFOCUS: ${q(ctx)}`,
|
||||
},
|
||||
{
|
||||
id: 'explore',
|
||||
agent: 'codebase-explorer',
|
||||
label: 'Implementation detail (codebase-explorer)',
|
||||
minBand: 'medium',
|
||||
task: (ctx) =>
|
||||
`Discover the implementation details of the feature/system named below — entry points, core logic, data models, config, tests. Cite repo/path:line.${repoLine(ctx)}\n\nFOCUS: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
synthesizer: {
|
||||
agent: 'information-architect',
|
||||
label: 'Structure synthesis (information-architect)',
|
||||
task: (ctx) =>
|
||||
`Organise the findings below into a clear project-discovery map a newcomer could navigate — grouped by concern, with the few orienting facts up front.\n\n----- FINDINGS -----\n${ctx.results.fold ?? ''}`,
|
||||
},
|
||||
};
|
||||
|
||||
/** Han `project-documentation` — draft documentation for a feature/system. */
|
||||
export const projectDocumentation: Spine = {
|
||||
name: 'project-documentation',
|
||||
description: 'draft docs for a feature/system (one-pass)',
|
||||
contracts: ['evidence', 'yagni'],
|
||||
angles: [
|
||||
{
|
||||
id: 'explore',
|
||||
agent: 'codebase-explorer',
|
||||
label: 'Source evidence (codebase-explorer)',
|
||||
task: (ctx) =>
|
||||
`Gather the implementation facts needed to document the subject below — what it does, its inputs/outputs, entry points, configuration, edge cases. Cite repo/path:line.${repoLine(ctx)}\n\nSUBJECT: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
synthesizer: {
|
||||
agent: 'information-architect',
|
||||
label: 'Documentation draft (information-architect)',
|
||||
task: (ctx) =>
|
||||
`Turn the source evidence below into a clear documentation draft for the subject — orient the reader first, then concept/task/reference as fits. Every claim must trace to the evidence; do not invent behaviour.\n\n----- SOURCE EVIDENCE -----\n${ctx.results.fold ?? ''}`,
|
||||
},
|
||||
};
|
||||
|
||||
/** Han `test-planning` — behaviour-focused test plan. */
|
||||
export const testPlanning: Spine = {
|
||||
name: 'test-planning',
|
||||
description: 'behaviour-focused test plan',
|
||||
angles: [
|
||||
{
|
||||
id: 'tests',
|
||||
agent: 'test-engineer',
|
||||
label: 'Test plan (test-engineer)',
|
||||
task: (ctx) =>
|
||||
`Produce a prioritised, behaviour-focused test plan for the subject below — observable inputs/outputs and collaborator interactions, recommended test doubles and test levels. Not internal code paths.${repoLine(ctx)}\n\nSUBJECT: ${q(ctx)}`,
|
||||
},
|
||||
{
|
||||
id: 'edges',
|
||||
agent: 'edge-case-explorer',
|
||||
label: 'Edge cases (edge-case-explorer)',
|
||||
minBand: 'medium',
|
||||
task: (ctx) =>
|
||||
`Catalog the boundary values, type-coercion traps, external-input messiness, and state-dependent failures the test plan must cover for the subject below.${repoLine(ctx)}\n\nSUBJECT: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/** Han data review — schema / query / data-access principled audit. */
|
||||
export const dataReview: Spine = {
|
||||
name: 'data-review',
|
||||
description: 'schema / query / data-access audit',
|
||||
angles: [
|
||||
{
|
||||
id: 'data',
|
||||
agent: 'data-engineer',
|
||||
label: 'Data engineering review (data-engineer)',
|
||||
task: (ctx) =>
|
||||
`Audit the schema/migration/query/data-access target below against normalization, indexing strategy, access patterns, migration safety, and PII/regulated-data handling. Cite the location and the data-level impact for each finding.${repoLine(ctx)}\n\nTARGET: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/** Han devops/runbook readiness review. */
|
||||
export const devopsReview: Spine = {
|
||||
name: 'devops-review',
|
||||
description: 'production-readiness / operability review',
|
||||
angles: [
|
||||
{
|
||||
id: 'devops',
|
||||
agent: 'devops-engineer',
|
||||
label: 'Pre-production readiness (devops-engineer)',
|
||||
task: (ctx) =>
|
||||
`Audit the change/feature below for production readiness — twelve-factor, observability (four golden signals), rollout safety, secrets/PII, scale and cost. Cite the exact location and the blast radius for each finding.${repoLine(ctx)}\n\nTARGET: ${q(ctx)}`,
|
||||
},
|
||||
{
|
||||
id: 'oncall',
|
||||
agent: 'on-call-engineer',
|
||||
label: 'Resilience / 3am risks (on-call-engineer)',
|
||||
minBand: 'medium',
|
||||
task: (ctx) =>
|
||||
`Audit the target below for code-level resilience anti-patterns that page someone — missing timeouts, retries without backoff, catch-and-swallow, unbounded results, blocking I/O in async paths. Cite file:line, name the failure mode.${repoLine(ctx)}\n\nTARGET: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/** Han `issue-triage` — assess and prioritise a reported issue. */
|
||||
export const issueTriage: Spine = {
|
||||
name: 'issue-triage',
|
||||
description: 'assess + prioritise a reported issue',
|
||||
angles: [
|
||||
{
|
||||
id: 'triage',
|
||||
agent: 'evidence-based-investigator',
|
||||
label: 'Triage evidence (evidence-based-investigator)',
|
||||
task: (ctx) =>
|
||||
`Triage the issue below: restate it precisely, gather the minimum evidence to characterise it (repro, affected area, file:line), classify severity, and state what is and isn't yet known. Do NOT attempt a full root-cause fix.${repoLine(ctx)}\n\nISSUE: ${q(ctx)}`,
|
||||
},
|
||||
{
|
||||
id: 'risk',
|
||||
agent: 'risk-analyst',
|
||||
label: 'Risk of inaction (risk-analyst)',
|
||||
minBand: 'medium',
|
||||
task: (ctx) =>
|
||||
`Assess the risk of leaving the issue below unaddressed — likelihood, severity, blast radius, reversibility — to inform its priority.\n\nISSUE: ${q(ctx)}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user