feat(P04): pipeline stage delegation — EXECUTE=3 agents, TEST=tester, VERIFY=verifier, COMPLETE=doc-writer+ship
---ci--- phase: 4 milestone: v1.0 plan: 04 task: PIPE-01-04 status: execute ---/ci---
This commit is contained in:
+96
-18
@@ -44,12 +44,13 @@ export class OrchestratorAgent extends BaseAgent {
|
||||
private phaseResults: PhaseResult[] = [];
|
||||
private totalPhases: number = 1;
|
||||
|
||||
private static readonly STAGE_AGENT_MAP: Partial<Record<PipelineStage, AgentName>> = {
|
||||
research: "researcher",
|
||||
plan: "planner",
|
||||
execute: "executor",
|
||||
test: "tester",
|
||||
verify: "verifier",
|
||||
private static readonly STAGE_AGENT_MAP: Partial<Record<PipelineStage, AgentName[]>> = {
|
||||
research: ["researcher"],
|
||||
plan: ["planner"],
|
||||
execute: ["executor", "code-reviewer", "security-auditor"],
|
||||
test: ["tester"],
|
||||
verify: ["verifier"],
|
||||
complete: ["doc-writer"],
|
||||
};
|
||||
|
||||
constructor(config?: CIAgentConfig) {
|
||||
@@ -331,29 +332,82 @@ export class OrchestratorAgent extends BaseAgent {
|
||||
context: AgentContext
|
||||
): Promise<PhaseResult> {
|
||||
const stageStart = Date.now();
|
||||
const agentName = OrchestratorAgent.STAGE_AGENT_MAP[stage];
|
||||
const agentNames = OrchestratorAgent.STAGE_AGENT_MAP[stage];
|
||||
|
||||
if (agentName && context.backend) {
|
||||
this.log(`Delegating ${stage} to ${agentName} agent via backend...`);
|
||||
if (agentNames && agentNames.length > 0 && context.backend) {
|
||||
this.log(`Delegating ${stage} to ${agentNames.join(", ")} agent(s) via backend...`);
|
||||
try {
|
||||
const agent = getAgent(agentName);
|
||||
const gitContext = this.buildGitAgentContext(context);
|
||||
const result = await agent.execute(gitContext);
|
||||
let primaryResult: AgentResult | null = null;
|
||||
const allArtifacts: string[] = [];
|
||||
let totalDecisions = 0;
|
||||
let totalEscalations = 0;
|
||||
let lastError: string | undefined;
|
||||
|
||||
for (let i = 0; i < agentNames.length; i++) {
|
||||
const agentName = agentNames[i];
|
||||
const agent = getAgent(agentName);
|
||||
const gitContext = this.buildGitAgentContext(context);
|
||||
|
||||
if (i === 0) {
|
||||
const result = await agent.execute(gitContext);
|
||||
primaryResult = result;
|
||||
if (Array.isArray(result.artifacts_created)) {
|
||||
allArtifacts.push(...result.artifacts_created);
|
||||
}
|
||||
totalDecisions += result.decisions;
|
||||
totalEscalations += result.escalations;
|
||||
|
||||
if (!result.success) {
|
||||
this.warn(`Primary agent ${agentName} failed for ${stage}`);
|
||||
return {
|
||||
phase: this.pipelineState!.current_phase,
|
||||
stage,
|
||||
success: false,
|
||||
artifacts_created: allArtifacts,
|
||||
decisions_made: totalDecisions,
|
||||
escalations_raised: totalEscalations,
|
||||
duration_ms: Date.now() - stageStart,
|
||||
error: result.error || `Primary agent ${agentName} failed`,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const reviewContext: AgentContext = {
|
||||
...gitContext,
|
||||
specification: `${context.specification}\n\nPrimary agent (${agentNames[0]}) completed. Review context:\n- Success: ${primaryResult!.success}\n- Output: ${primaryResult!.output}\n- Artifacts: ${Array.isArray(primaryResult!.artifacts_created) ? primaryResult!.artifacts_created.join(", ") : String(primaryResult!.artifacts_created)}`,
|
||||
};
|
||||
const result = await agent.execute(reviewContext);
|
||||
if (Array.isArray(result.artifacts_created)) {
|
||||
allArtifacts.push(...result.artifacts_created);
|
||||
}
|
||||
totalDecisions += result.decisions;
|
||||
totalEscalations += result.escalations;
|
||||
|
||||
if (!result.success) {
|
||||
this.warn(`Review agent ${agentName} reported issues for ${stage}: ${result.error || "unspecified"}`);
|
||||
lastError = result.error;
|
||||
}
|
||||
} catch (err) {
|
||||
this.warn(`Review agent ${agentName} failed for ${stage}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
phase: this.pipelineState!.current_phase,
|
||||
stage,
|
||||
success: result.success,
|
||||
artifacts_created: Array.isArray(result.artifacts_created) ? result.artifacts_created : [],
|
||||
decisions_made: result.decisions,
|
||||
escalations_raised: result.escalations,
|
||||
success: primaryResult?.success ?? false,
|
||||
artifacts_created: allArtifacts,
|
||||
decisions_made: totalDecisions,
|
||||
escalations_raised: totalEscalations,
|
||||
duration_ms: Date.now() - stageStart,
|
||||
error: result.error,
|
||||
error: lastError,
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof BackendUnavailableError) {
|
||||
this.warn(`Backend unavailable for ${stage}, falling back to mechanical execution`);
|
||||
} else {
|
||||
this.warn(`Agent ${agentName} failed for ${stage}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
this.warn(`Agents failed for ${stage}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -609,6 +663,30 @@ export class OrchestratorAgent extends BaseAgent {
|
||||
}
|
||||
}
|
||||
|
||||
const versionTag = `${this.currentMilestone}-P${String(this.pipelineState!.current_phase).padStart(2, "0")}`;
|
||||
try {
|
||||
execSync(`git tag "${versionTag}"`, {
|
||||
cwd: context.project_path,
|
||||
stdio: "pipe",
|
||||
});
|
||||
this.log(`Created version tag: ${versionTag}`);
|
||||
artifactsCreated.push(`tag:${versionTag}`);
|
||||
} catch (err) {
|
||||
this.warn(`Version tag creation failed: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
|
||||
if (this.config.git.auto_push && this.gitContext!.isGitRepo()) {
|
||||
try {
|
||||
execSync(`git push origin ${versionTag}`, {
|
||||
cwd: context.project_path,
|
||||
stdio: "pipe",
|
||||
});
|
||||
this.log(`Pushed version tag: ${versionTag}`);
|
||||
} catch (err) {
|
||||
this.warn(`Version tag push failed: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user