940b85bfae
Add IntelligenceBackend abstraction with two categories: - LLMBackend (OllamaLocal, OllamaCloud): CI runs tool loop, provides tools, constructs prompts - AgentBackend (Opencode): agent runs own tool loop, CI serializes request Refactor all 18 agents from hardcoded stubs to persona loaders that delegate to the active backend or fail honestly when no backend is available. Refactor OrchestratorAgent.executeStage() from monolithic switch to agent delegation via STAGE_AGENT_MAP for intelligent stages (research, plan, execute, verify), with mechanical stages (specify, clarify, complete) staying inline. Wire CLI commands with --backend flag and auto-detection (opencode → ollama-local → ollama-cloud). Harden rollback/ship with real git operations. No command returns fake success.
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
import { IntelligenceBackend, BackendRequest, BackendResult, BackendUnavailableError, emptyBackendResult } from "../backends/types.js";
|
|
import { AgentName, AutonomyLevel } from "../types/config.js";
|
|
|
|
export interface AgentResult {
|
|
success: boolean;
|
|
output: string;
|
|
artifacts_created: string[] | number;
|
|
decisions: number;
|
|
escalations: number;
|
|
duration_ms: number;
|
|
error?: string;
|
|
}
|
|
|
|
export interface AgentContext {
|
|
project_path: string;
|
|
phase: number;
|
|
stage: string;
|
|
specification: string;
|
|
config_path: string;
|
|
backend?: IntelligenceBackend;
|
|
}
|
|
|
|
export function backendResultToAgentResult(result: BackendResult): AgentResult {
|
|
return {
|
|
success: result.success,
|
|
output: result.output,
|
|
artifacts_created: result.artifacts.map((a) => a.path),
|
|
decisions: result.decisions.length,
|
|
escalations: result.escalations.length,
|
|
duration_ms: 0,
|
|
error: result.error,
|
|
};
|
|
}
|
|
|
|
export abstract class BaseAgent {
|
|
abstract readonly name: AgentName;
|
|
abstract readonly description: string;
|
|
abstract readonly workflow: string;
|
|
|
|
abstract execute(context: AgentContext): Promise<AgentResult>;
|
|
|
|
protected async executeViaBackend(context: AgentContext, task: string): Promise<AgentResult> {
|
|
if (!context.backend) {
|
|
throw new BackendUnavailableError("none", this.name);
|
|
}
|
|
const request: BackendRequest = {
|
|
persona: this.name,
|
|
workflow: this.workflow,
|
|
task,
|
|
context,
|
|
autonomy: "full",
|
|
};
|
|
const result = await context.backend.execute(request);
|
|
return backendResultToAgentResult(result);
|
|
}
|
|
|
|
protected log(message: string): void {
|
|
console.log(`[${this.name}] ${message}`);
|
|
}
|
|
|
|
protected warn(message: string): void {
|
|
console.warn(`[${this.name}] ⚠ ${message}`);
|
|
}
|
|
|
|
protected error(message: string): void {
|
|
console.error(`[${this.name}] ✗ ${message}`);
|
|
}
|
|
} |