oxe-cc 0.9.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/banner.txt +1 -1
- package/bin/lib/oxe-dashboard.cjs +9 -7
- package/bin/lib/oxe-operational.cjs +569 -4
- package/bin/oxe-cc.js +141 -57
- package/lib/runtime/compiler/graph-compiler.d.ts +83 -0
- package/lib/runtime/compiler/graph-compiler.js +135 -0
- package/lib/runtime/compiler/index.d.ts +1 -0
- package/lib/runtime/compiler/index.js +17 -0
- package/lib/runtime/context/context-pack-builder.d.ts +36 -0
- package/lib/runtime/context/context-pack-builder.js +136 -0
- package/lib/runtime/context/index.d.ts +1 -0
- package/lib/runtime/context/index.js +17 -0
- package/lib/runtime/delivery/branch-manager.d.ts +19 -0
- package/lib/runtime/delivery/branch-manager.js +78 -0
- package/lib/runtime/delivery/ci-checks.d.ts +34 -0
- package/lib/runtime/delivery/ci-checks.js +209 -0
- package/lib/runtime/delivery/index.d.ts +3 -0
- package/lib/runtime/delivery/index.js +19 -0
- package/lib/runtime/delivery/pr-manager.d.ts +30 -0
- package/lib/runtime/delivery/pr-manager.js +82 -0
- package/lib/runtime/events/bus.d.ts +9 -0
- package/lib/runtime/events/bus.js +63 -0
- package/lib/runtime/events/catalog.d.ts +3 -0
- package/lib/runtime/events/catalog.js +30 -0
- package/lib/runtime/events/envelope.d.ts +13 -0
- package/lib/runtime/events/envelope.js +2 -0
- package/lib/runtime/events/index.d.ts +3 -0
- package/lib/runtime/events/index.js +19 -0
- package/lib/runtime/evidence/evidence-store.d.ts +22 -0
- package/lib/runtime/evidence/evidence-store.js +106 -0
- package/lib/runtime/evidence/index.d.ts +1 -0
- package/lib/runtime/evidence/index.js +17 -0
- package/lib/runtime/gate/gate-manager.d.ts +39 -0
- package/lib/runtime/gate/gate-manager.js +104 -0
- package/lib/runtime/gate/index.d.ts +1 -0
- package/lib/runtime/gate/index.js +17 -0
- package/lib/runtime/index.d.ts +16 -0
- package/lib/runtime/index.js +40 -0
- package/lib/runtime/models/attempt.d.ts +12 -0
- package/lib/runtime/models/attempt.js +2 -0
- package/lib/runtime/models/evidence.d.ts +9 -0
- package/lib/runtime/models/evidence.js +2 -0
- package/lib/runtime/models/gate-decision.d.ts +10 -0
- package/lib/runtime/models/gate-decision.js +2 -0
- package/lib/runtime/models/index.d.ts +8 -0
- package/lib/runtime/models/index.js +24 -0
- package/lib/runtime/models/run.d.ts +13 -0
- package/lib/runtime/models/run.js +2 -0
- package/lib/runtime/models/session.d.ts +10 -0
- package/lib/runtime/models/session.js +2 -0
- package/lib/runtime/models/verification-result.d.ts +9 -0
- package/lib/runtime/models/verification-result.js +2 -0
- package/lib/runtime/models/work-item.d.ts +15 -0
- package/lib/runtime/models/work-item.js +2 -0
- package/lib/runtime/models/workspace.d.ts +25 -0
- package/lib/runtime/models/workspace.js +2 -0
- package/lib/runtime/plugins/index.d.ts +2 -0
- package/lib/runtime/plugins/index.js +18 -0
- package/lib/runtime/plugins/plugin-abi.d.ts +76 -0
- package/lib/runtime/plugins/plugin-abi.js +2 -0
- package/lib/runtime/plugins/plugin-registry.d.ts +21 -0
- package/lib/runtime/plugins/plugin-registry.js +114 -0
- package/lib/runtime/policy/index.d.ts +1 -0
- package/lib/runtime/policy/index.js +17 -0
- package/lib/runtime/policy/policy-engine.d.ts +40 -0
- package/lib/runtime/policy/policy-engine.js +80 -0
- package/lib/runtime/projection/index.d.ts +1 -0
- package/lib/runtime/projection/index.js +17 -0
- package/lib/runtime/projection/projection-engine.d.ts +11 -0
- package/lib/runtime/projection/projection-engine.js +218 -0
- package/lib/runtime/reducers/debug-reducer.d.ts +10 -0
- package/lib/runtime/reducers/debug-reducer.js +30 -0
- package/lib/runtime/reducers/index.d.ts +2 -0
- package/lib/runtime/reducers/index.js +18 -0
- package/lib/runtime/reducers/run-state-reducer.d.ts +20 -0
- package/lib/runtime/reducers/run-state-reducer.js +110 -0
- package/lib/runtime/scheduler/index.d.ts +1 -0
- package/lib/runtime/scheduler/index.js +17 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +34 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.js +166 -0
- package/lib/runtime/scheduler/scheduler.d.ts +39 -0
- package/lib/runtime/scheduler/scheduler.js +196 -0
- package/lib/runtime/verification/index.d.ts +1 -0
- package/lib/runtime/verification/index.js +17 -0
- package/lib/runtime/verification/verification-compiler.d.ts +56 -0
- package/lib/runtime/verification/verification-compiler.js +147 -0
- package/lib/runtime/workspace/index.d.ts +5 -0
- package/lib/runtime/workspace/index.js +24 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +22 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.js +109 -0
- package/lib/runtime/workspace/strategies/git-worktree.d.ts +12 -0
- package/lib/runtime/workspace/strategies/git-worktree.js +79 -0
- package/lib/runtime/workspace/strategies/inplace.d.ts +10 -0
- package/lib/runtime/workspace/strategies/inplace.js +37 -0
- package/lib/runtime/workspace/workspace-manager.d.ts +13 -0
- package/lib/runtime/workspace/workspace-manager.js +2 -0
- package/lib/sdk/index.cjs +24 -7
- package/lib/sdk/index.d.ts +17 -7
- package/package.json +9 -3
- package/packages/runtime/package.json +17 -0
- package/packages/runtime/src/compiler/graph-compiler.ts +245 -0
- package/packages/runtime/src/compiler/index.ts +1 -0
- package/packages/runtime/src/context/context-pack-builder.ts +193 -0
- package/packages/runtime/src/context/index.ts +1 -0
- package/packages/runtime/src/delivery/branch-manager.ts +84 -0
- package/packages/runtime/src/delivery/ci-checks.ts +252 -0
- package/packages/runtime/src/delivery/index.ts +3 -0
- package/packages/runtime/src/delivery/pr-manager.ts +112 -0
- package/packages/runtime/src/events/bus.ts +92 -0
- package/packages/runtime/src/events/catalog.ts +29 -0
- package/packages/runtime/src/events/envelope.ts +14 -0
- package/packages/runtime/src/events/index.ts +3 -0
- package/packages/runtime/src/evidence/evidence-store.ts +130 -0
- package/packages/runtime/src/evidence/index.ts +1 -0
- package/packages/runtime/src/gate/gate-manager.ts +137 -0
- package/packages/runtime/src/gate/index.ts +1 -0
- package/packages/runtime/src/index.ts +32 -0
- package/packages/runtime/src/models/attempt.ts +19 -0
- package/packages/runtime/src/models/evidence.ts +21 -0
- package/packages/runtime/src/models/gate-decision.ts +21 -0
- package/packages/runtime/src/models/index.ts +8 -0
- package/packages/runtime/src/models/run.ts +24 -0
- package/packages/runtime/src/models/session.ts +11 -0
- package/packages/runtime/src/models/verification-result.ts +10 -0
- package/packages/runtime/src/models/work-item.ts +25 -0
- package/packages/runtime/src/models/workspace.ts +28 -0
- package/packages/runtime/src/plugins/index.ts +2 -0
- package/packages/runtime/src/plugins/plugin-abi.ts +95 -0
- package/packages/runtime/src/plugins/plugin-registry.ts +119 -0
- package/packages/runtime/src/policy/index.ts +1 -0
- package/packages/runtime/src/policy/policy-engine.ts +113 -0
- package/packages/runtime/src/projection/index.ts +1 -0
- package/packages/runtime/src/projection/projection-engine.ts +249 -0
- package/packages/runtime/src/reducers/debug-reducer.ts +36 -0
- package/packages/runtime/src/reducers/index.ts +2 -0
- package/packages/runtime/src/reducers/run-state-reducer.ts +127 -0
- package/packages/runtime/src/scheduler/index.ts +1 -0
- package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +231 -0
- package/packages/runtime/src/scheduler/scheduler.ts +281 -0
- package/packages/runtime/src/verification/index.ts +1 -0
- package/packages/runtime/src/verification/verification-compiler.ts +225 -0
- package/packages/runtime/src/workspace/index.ts +5 -0
- package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +121 -0
- package/packages/runtime/src/workspace/strategies/git-worktree.ts +77 -0
- package/packages/runtime/src/workspace/strategies/inplace.ts +35 -0
- package/packages/runtime/src/workspace/workspace-manager.ts +15 -0
- package/packages/runtime/tsconfig.json +17 -0
- package/vscode-extension/oxe-agents-0.9.2.vsix +0 -0
- package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEmptyRunState = createEmptyRunState;
|
|
4
|
+
exports.reduce = reduce;
|
|
5
|
+
exports.applyEventExported = applyEvent;
|
|
6
|
+
exports.getWorkItemStatus = getWorkItemStatus;
|
|
7
|
+
exports.getAttemptCount = getAttemptCount;
|
|
8
|
+
function createEmptyRunState() {
|
|
9
|
+
return {
|
|
10
|
+
run: null,
|
|
11
|
+
workItems: new Map(),
|
|
12
|
+
attempts: new Map(),
|
|
13
|
+
workspaces: new Map(),
|
|
14
|
+
completedWorkItems: new Set(),
|
|
15
|
+
failedWorkItems: new Set(),
|
|
16
|
+
blockedWorkItems: new Set(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function reduce(events) {
|
|
20
|
+
return events.reduce(applyEvent, createEmptyRunState());
|
|
21
|
+
}
|
|
22
|
+
function applyEvent(state, event) {
|
|
23
|
+
switch (event.type) {
|
|
24
|
+
case 'RunStarted': {
|
|
25
|
+
const run = event.payload;
|
|
26
|
+
return { ...state, run };
|
|
27
|
+
}
|
|
28
|
+
case 'RunCompleted': {
|
|
29
|
+
if (!state.run)
|
|
30
|
+
return state;
|
|
31
|
+
const status = event.payload.status ?? 'completed';
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
run: { ...state.run, status, ended_at: event.timestamp },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case 'WorkItemReady': {
|
|
38
|
+
if (!event.work_item_id)
|
|
39
|
+
return state;
|
|
40
|
+
const workItems = new Map(state.workItems);
|
|
41
|
+
const existing = workItems.get(event.work_item_id);
|
|
42
|
+
if (existing) {
|
|
43
|
+
workItems.set(event.work_item_id, { ...existing, status: 'ready' });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// First time we see this work item — create from payload
|
|
47
|
+
const item = event.payload;
|
|
48
|
+
workItems.set(event.work_item_id, { ...item, work_item_id: event.work_item_id, status: 'ready' });
|
|
49
|
+
}
|
|
50
|
+
return { ...state, workItems };
|
|
51
|
+
}
|
|
52
|
+
case 'AttemptStarted': {
|
|
53
|
+
if (!event.work_item_id || !event.attempt_id)
|
|
54
|
+
return state;
|
|
55
|
+
const attempts = new Map(state.attempts);
|
|
56
|
+
const attempt = {
|
|
57
|
+
attempt_id: event.attempt_id,
|
|
58
|
+
work_item_id: event.work_item_id,
|
|
59
|
+
attempt_number: event.payload.attempt_number ?? 1,
|
|
60
|
+
workspace_id: null,
|
|
61
|
+
agent_profile: null,
|
|
62
|
+
model: null,
|
|
63
|
+
started_at: event.timestamp,
|
|
64
|
+
ended_at: null,
|
|
65
|
+
outcome: null,
|
|
66
|
+
};
|
|
67
|
+
const existing = attempts.get(event.work_item_id) ?? [];
|
|
68
|
+
attempts.set(event.work_item_id, [...existing, attempt]);
|
|
69
|
+
return { ...state, attempts };
|
|
70
|
+
}
|
|
71
|
+
case 'WorkspaceAllocated': {
|
|
72
|
+
const ws = event.payload;
|
|
73
|
+
if (!ws.workspace_id)
|
|
74
|
+
return state;
|
|
75
|
+
const workspaces = new Map(state.workspaces);
|
|
76
|
+
workspaces.set(ws.workspace_id, { ...ws, status: 'ready' });
|
|
77
|
+
return { ...state, workspaces };
|
|
78
|
+
}
|
|
79
|
+
case 'WorkItemCompleted': {
|
|
80
|
+
if (!event.work_item_id)
|
|
81
|
+
return state;
|
|
82
|
+
const workItems = new Map(state.workItems);
|
|
83
|
+
const item = workItems.get(event.work_item_id);
|
|
84
|
+
if (item)
|
|
85
|
+
workItems.set(event.work_item_id, { ...item, status: 'completed' });
|
|
86
|
+
const completedWorkItems = new Set(state.completedWorkItems);
|
|
87
|
+
completedWorkItems.add(event.work_item_id);
|
|
88
|
+
return { ...state, workItems, completedWorkItems };
|
|
89
|
+
}
|
|
90
|
+
case 'WorkItemBlocked': {
|
|
91
|
+
if (!event.work_item_id)
|
|
92
|
+
return state;
|
|
93
|
+
const workItems = new Map(state.workItems);
|
|
94
|
+
const item = workItems.get(event.work_item_id);
|
|
95
|
+
if (item)
|
|
96
|
+
workItems.set(event.work_item_id, { ...item, status: 'blocked' });
|
|
97
|
+
const blockedWorkItems = new Set(state.blockedWorkItems);
|
|
98
|
+
blockedWorkItems.add(event.work_item_id);
|
|
99
|
+
return { ...state, workItems, blockedWorkItems };
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
return state;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function getWorkItemStatus(state, workItemId) {
|
|
106
|
+
return state.workItems.get(workItemId)?.status ?? null;
|
|
107
|
+
}
|
|
108
|
+
function getAttemptCount(state, workItemId) {
|
|
109
|
+
return state.attempts.get(workItemId)?.length ?? 0;
|
|
110
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './scheduler';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./scheduler"), exports);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ExecutionGraph } from '../compiler/graph-compiler';
|
|
2
|
+
import type { WorkspaceManager } from '../workspace/workspace-manager';
|
|
3
|
+
import type { TaskExecutor, SchedulerContext } from './scheduler';
|
|
4
|
+
export type CoordinationMode = 'parallel' | 'competitive' | 'cooperative';
|
|
5
|
+
export interface AgentSpec {
|
|
6
|
+
id: string;
|
|
7
|
+
executor: TaskExecutor;
|
|
8
|
+
workspaceManager: WorkspaceManager;
|
|
9
|
+
/** Task IDs this agent is responsible for (used in parallel mode) */
|
|
10
|
+
assignedTaskIds?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface CoordinationOptions {
|
|
13
|
+
mode: CoordinationMode;
|
|
14
|
+
agents: AgentSpec[];
|
|
15
|
+
projectRoot: string;
|
|
16
|
+
sessionId: string | null;
|
|
17
|
+
runId: string;
|
|
18
|
+
onEvent?: SchedulerContext['onEvent'];
|
|
19
|
+
}
|
|
20
|
+
export interface CoordinationResult {
|
|
21
|
+
mode: CoordinationMode;
|
|
22
|
+
run_id: string;
|
|
23
|
+
completed: string[];
|
|
24
|
+
failed: string[];
|
|
25
|
+
blocked: string[];
|
|
26
|
+
agent_results: Array<{
|
|
27
|
+
agent_id: string;
|
|
28
|
+
completed: string[];
|
|
29
|
+
failed: string[];
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
export declare class MultiAgentCoordinator {
|
|
33
|
+
run(graph: ExecutionGraph, opts: CoordinationOptions): Promise<CoordinationResult>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultiAgentCoordinator = void 0;
|
|
4
|
+
const bus_1 = require("../events/bus");
|
|
5
|
+
const scheduler_1 = require("./scheduler");
|
|
6
|
+
// ─── Parallel mode ───────────────────────────────────────────────────────────
|
|
7
|
+
// Tasks are partitioned across agents. Each agent runs its own Scheduler
|
|
8
|
+
// on a sub-graph. Results are merged.
|
|
9
|
+
async function runParallel(graph, opts) {
|
|
10
|
+
const { agents, projectRoot, sessionId, runId } = opts;
|
|
11
|
+
// Partition tasks across agents (round-robin if assignedTaskIds not set)
|
|
12
|
+
const partitions = agents.map((a) => a.assignedTaskIds ?? []);
|
|
13
|
+
if (partitions.every((p) => p.length === 0)) {
|
|
14
|
+
const allIds = [...graph.nodes.keys()];
|
|
15
|
+
allIds.forEach((id, i) => {
|
|
16
|
+
partitions[i % agents.length].push(id);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, {
|
|
20
|
+
type: 'RunStarted',
|
|
21
|
+
run_id: runId,
|
|
22
|
+
payload: { mode: 'parallel', agent_count: agents.length },
|
|
23
|
+
});
|
|
24
|
+
const agentResults = await Promise.all(agents.map(async (agent, idx) => {
|
|
25
|
+
const subGraph = subGraphFor(graph, partitions[idx]);
|
|
26
|
+
if (subGraph.nodes.size === 0) {
|
|
27
|
+
return { agent_id: agent.id, completed: [], failed: [] };
|
|
28
|
+
}
|
|
29
|
+
const ctx = {
|
|
30
|
+
projectRoot,
|
|
31
|
+
sessionId,
|
|
32
|
+
runId: `${runId}-agent${idx}`,
|
|
33
|
+
executor: agent.executor,
|
|
34
|
+
workspaceManager: agent.workspaceManager,
|
|
35
|
+
onEvent: opts.onEvent,
|
|
36
|
+
};
|
|
37
|
+
const scheduler = new scheduler_1.Scheduler();
|
|
38
|
+
const result = await scheduler.run(subGraph, ctx);
|
|
39
|
+
return { agent_id: agent.id, completed: result.completed, failed: result.failed };
|
|
40
|
+
}));
|
|
41
|
+
const completed = agentResults.flatMap((r) => r.completed);
|
|
42
|
+
const failed = agentResults.flatMap((r) => r.failed);
|
|
43
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, {
|
|
44
|
+
type: 'RunCompleted',
|
|
45
|
+
run_id: runId,
|
|
46
|
+
payload: { mode: 'parallel', completed: completed.length, failed: failed.length },
|
|
47
|
+
});
|
|
48
|
+
return { mode: 'parallel', run_id: runId, completed, failed, blocked: [], agent_results: agentResults };
|
|
49
|
+
}
|
|
50
|
+
// ─── Competitive mode ────────────────────────────────────────────────────────
|
|
51
|
+
// Two agents attempt the same task. First success wins; the loser's workspace
|
|
52
|
+
// is disposed. Requires exactly 2 agents.
|
|
53
|
+
async function runCompetitive(graph, opts) {
|
|
54
|
+
if (opts.agents.length < 2) {
|
|
55
|
+
throw new Error('Competitive mode requires at least 2 agents');
|
|
56
|
+
}
|
|
57
|
+
const [agentA, agentB] = opts.agents;
|
|
58
|
+
const { projectRoot, sessionId, runId } = opts;
|
|
59
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, {
|
|
60
|
+
type: 'RunStarted',
|
|
61
|
+
run_id: runId,
|
|
62
|
+
payload: { mode: 'competitive' },
|
|
63
|
+
});
|
|
64
|
+
const completed = [];
|
|
65
|
+
const failed = [];
|
|
66
|
+
for (const wave of graph.waves) {
|
|
67
|
+
for (const nodeId of wave.node_ids) {
|
|
68
|
+
const node = graph.nodes.get(nodeId);
|
|
69
|
+
const result = await competeTwoAgents(nodeId, node, agentA, agentB, opts);
|
|
70
|
+
if (result.success)
|
|
71
|
+
completed.push(nodeId);
|
|
72
|
+
else
|
|
73
|
+
failed.push(nodeId);
|
|
74
|
+
if (failed.length > 0)
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
if (failed.length > 0)
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, {
|
|
81
|
+
type: 'RunCompleted',
|
|
82
|
+
run_id: runId,
|
|
83
|
+
payload: { mode: 'competitive', completed: completed.length },
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
mode: 'competitive',
|
|
87
|
+
run_id: runId,
|
|
88
|
+
completed,
|
|
89
|
+
failed,
|
|
90
|
+
blocked: [],
|
|
91
|
+
agent_results: [
|
|
92
|
+
{ agent_id: agentA.id, completed, failed },
|
|
93
|
+
{ agent_id: agentB.id, completed: [], failed: [] },
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function competeTwoAgents(nodeId, node, agentA, agentB, opts) {
|
|
98
|
+
const { projectRoot, sessionId, runId } = opts;
|
|
99
|
+
const allocA = await agentA.workspaceManager.allocate({
|
|
100
|
+
work_item_id: nodeId, attempt_number: 1, strategy: node.workspace_strategy, mutation_scope: node.mutation_scope,
|
|
101
|
+
});
|
|
102
|
+
const allocB = await agentB.workspaceManager.allocate({
|
|
103
|
+
work_item_id: nodeId, attempt_number: 1, strategy: node.workspace_strategy, mutation_scope: node.mutation_scope,
|
|
104
|
+
});
|
|
105
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, {
|
|
106
|
+
type: 'AttemptStarted',
|
|
107
|
+
run_id: runId,
|
|
108
|
+
work_item_id: nodeId,
|
|
109
|
+
payload: { mode: 'competitive', agents: [agentA.id, agentB.id] },
|
|
110
|
+
});
|
|
111
|
+
// Race both agents — first success wins
|
|
112
|
+
const [resultA, resultB] = await Promise.all([
|
|
113
|
+
agentA.executor.execute(node, allocA, runId, 1).catch((e) => ({
|
|
114
|
+
success: false, failure_class: 'env', evidence: [], output: String(e),
|
|
115
|
+
})),
|
|
116
|
+
agentB.executor.execute(node, allocB, runId, 1).catch((e) => ({
|
|
117
|
+
success: false, failure_class: 'env', evidence: [], output: String(e),
|
|
118
|
+
})),
|
|
119
|
+
]);
|
|
120
|
+
// Clean up both workspaces
|
|
121
|
+
await Promise.all([
|
|
122
|
+
agentA.workspaceManager.dispose(allocA.workspace_id).catch(() => { }),
|
|
123
|
+
agentB.workspaceManager.dispose(allocB.workspace_id).catch(() => { }),
|
|
124
|
+
]);
|
|
125
|
+
// Pick winner: prefer success; if both succeed, prefer A (primary agent)
|
|
126
|
+
const winner = resultA.success ? resultA : resultB.success ? resultB : resultA;
|
|
127
|
+
if (winner.success) {
|
|
128
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, { type: 'WorkItemCompleted', run_id: runId, work_item_id: nodeId, payload: { mode: 'competitive' } });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
(0, bus_1.appendEvent)(projectRoot, sessionId, { type: 'WorkItemBlocked', run_id: runId, work_item_id: nodeId, payload: { mode: 'competitive', failure_class: winner.failure_class } });
|
|
132
|
+
}
|
|
133
|
+
return winner;
|
|
134
|
+
}
|
|
135
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
136
|
+
class MultiAgentCoordinator {
|
|
137
|
+
async run(graph, opts) {
|
|
138
|
+
switch (opts.mode) {
|
|
139
|
+
case 'parallel': return runParallel(graph, opts);
|
|
140
|
+
case 'competitive': return runCompetitive(graph, opts);
|
|
141
|
+
case 'cooperative':
|
|
142
|
+
// Cooperative mode: planner (agent[0]) prepares context,
|
|
143
|
+
// executor (agent[1]) implements. For R3, delegate to sequential parallel.
|
|
144
|
+
return runParallel(graph, { ...opts, mode: 'parallel' });
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Unknown coordination mode: ${opts.mode}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.MultiAgentCoordinator = MultiAgentCoordinator;
|
|
151
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
152
|
+
function subGraphFor(graph, nodeIds) {
|
|
153
|
+
const ids = new Set(nodeIds);
|
|
154
|
+
const nodes = new Map([...graph.nodes].filter(([id]) => ids.has(id)));
|
|
155
|
+
const edges = graph.edges.filter((e) => ids.has(e.from) && ids.has(e.to));
|
|
156
|
+
const waves = graph.waves.map((w) => ({
|
|
157
|
+
wave_number: w.wave_number,
|
|
158
|
+
node_ids: w.node_ids.filter((id) => ids.has(id)),
|
|
159
|
+
})).filter((w) => w.node_ids.length > 0);
|
|
160
|
+
return {
|
|
161
|
+
nodes,
|
|
162
|
+
edges,
|
|
163
|
+
waves,
|
|
164
|
+
metadata: { ...graph.metadata, node_count: nodes.size, wave_count: waves.length },
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OxeEvent } from '../events/envelope';
|
|
2
|
+
import type { ExecutionGraph, GraphNode } from '../compiler/graph-compiler';
|
|
3
|
+
import type { WorkspaceManager } from '../workspace/workspace-manager';
|
|
4
|
+
import type { WorkspaceLease } from '../models/workspace';
|
|
5
|
+
export interface TaskResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
failure_class: 'env' | 'policy' | 'test' | 'timeout' | null;
|
|
8
|
+
evidence: string[];
|
|
9
|
+
output: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TaskExecutor {
|
|
12
|
+
execute(node: GraphNode, lease: WorkspaceLease, runId: string, attemptNumber: number): Promise<TaskResult>;
|
|
13
|
+
}
|
|
14
|
+
export interface SchedulerContext {
|
|
15
|
+
projectRoot: string;
|
|
16
|
+
sessionId: string | null;
|
|
17
|
+
runId: string;
|
|
18
|
+
executor: TaskExecutor;
|
|
19
|
+
workspaceManager: WorkspaceManager;
|
|
20
|
+
onEvent?: (event: OxeEvent) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface RunResult {
|
|
23
|
+
run_id: string;
|
|
24
|
+
status: 'completed' | 'failed' | 'cancelled';
|
|
25
|
+
completed: string[];
|
|
26
|
+
failed: string[];
|
|
27
|
+
blocked: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare class Scheduler {
|
|
30
|
+
private cancelled;
|
|
31
|
+
private paused;
|
|
32
|
+
run(graph: ExecutionGraph, ctx: SchedulerContext): Promise<RunResult>;
|
|
33
|
+
private runWave;
|
|
34
|
+
private runNode;
|
|
35
|
+
pause(): void;
|
|
36
|
+
resume(): void;
|
|
37
|
+
cancel(): void;
|
|
38
|
+
private emit;
|
|
39
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Scheduler = void 0;
|
|
4
|
+
const bus_1 = require("../events/bus");
|
|
5
|
+
class Scheduler {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.cancelled = false;
|
|
8
|
+
this.paused = false;
|
|
9
|
+
}
|
|
10
|
+
async run(graph, ctx) {
|
|
11
|
+
this.cancelled = false;
|
|
12
|
+
this.paused = false;
|
|
13
|
+
const status = new Map();
|
|
14
|
+
for (const id of graph.nodes.keys())
|
|
15
|
+
status.set(id, 'pending');
|
|
16
|
+
const completed = [];
|
|
17
|
+
const failed = [];
|
|
18
|
+
const blocked = [];
|
|
19
|
+
this.emit(ctx, { type: 'RunStarted', payload: { run_id: ctx.runId } });
|
|
20
|
+
for (const wave of graph.waves) {
|
|
21
|
+
if (this.cancelled)
|
|
22
|
+
break;
|
|
23
|
+
const waveFailed = await this.runWave(wave.node_ids, graph, ctx, status, completed, failed, blocked);
|
|
24
|
+
if (waveFailed)
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
// Any remaining pending nodes become blocked
|
|
28
|
+
for (const [id, s] of status) {
|
|
29
|
+
if (s === 'pending') {
|
|
30
|
+
status.set(id, 'blocked');
|
|
31
|
+
blocked.push(id);
|
|
32
|
+
this.emit(ctx, {
|
|
33
|
+
type: 'WorkItemBlocked',
|
|
34
|
+
work_item_id: id,
|
|
35
|
+
payload: { reason: 'upstream_wave_failed' },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const finalStatus = this.cancelled
|
|
40
|
+
? 'cancelled'
|
|
41
|
+
: failed.length > 0
|
|
42
|
+
? 'failed'
|
|
43
|
+
: 'completed';
|
|
44
|
+
this.emit(ctx, {
|
|
45
|
+
type: 'RunCompleted',
|
|
46
|
+
payload: { run_id: ctx.runId, status: finalStatus },
|
|
47
|
+
});
|
|
48
|
+
return { run_id: ctx.runId, status: finalStatus, completed, failed, blocked };
|
|
49
|
+
}
|
|
50
|
+
async runWave(nodeIds, graph, ctx, status, completed, failed, blocked) {
|
|
51
|
+
// Partition: eligible vs blocked-by-dep
|
|
52
|
+
const eligible = [];
|
|
53
|
+
const depsNotMet = [];
|
|
54
|
+
for (const id of nodeIds) {
|
|
55
|
+
const node = graph.nodes.get(id);
|
|
56
|
+
const depsMet = node.depends_on.every((dep) => status.get(dep) === 'completed');
|
|
57
|
+
if (depsMet) {
|
|
58
|
+
eligible.push(id);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
depsNotMet.push(id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Nodes whose deps weren't met in this wave → blocked
|
|
65
|
+
for (const id of depsNotMet) {
|
|
66
|
+
status.set(id, 'blocked');
|
|
67
|
+
blocked.push(id);
|
|
68
|
+
this.emit(ctx, {
|
|
69
|
+
type: 'WorkItemBlocked',
|
|
70
|
+
work_item_id: id,
|
|
71
|
+
payload: { reason: 'dependency_not_met' },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Separate read-only (no mutation_scope) from mutation nodes
|
|
75
|
+
const readOnly = eligible.filter((id) => {
|
|
76
|
+
const node = graph.nodes.get(id);
|
|
77
|
+
return node.mutation_scope.length === 0;
|
|
78
|
+
});
|
|
79
|
+
const mutations = eligible.filter((id) => !readOnly.includes(id));
|
|
80
|
+
// Run read-only nodes in parallel
|
|
81
|
+
if (readOnly.length > 0) {
|
|
82
|
+
await Promise.all(readOnly.map((id) => this.runNode(id, graph, ctx, status, completed, failed)));
|
|
83
|
+
}
|
|
84
|
+
// Run mutation nodes sequentially to avoid scope conflicts
|
|
85
|
+
for (const id of mutations) {
|
|
86
|
+
if (this.cancelled)
|
|
87
|
+
break;
|
|
88
|
+
await this.runNode(id, graph, ctx, status, completed, failed);
|
|
89
|
+
}
|
|
90
|
+
return failed.length > 0;
|
|
91
|
+
}
|
|
92
|
+
async runNode(nodeId, graph, ctx, status, completed, failed) {
|
|
93
|
+
const node = graph.nodes.get(nodeId);
|
|
94
|
+
status.set(nodeId, 'running');
|
|
95
|
+
this.emit(ctx, {
|
|
96
|
+
type: 'WorkItemReady',
|
|
97
|
+
work_item_id: nodeId,
|
|
98
|
+
payload: { title: node.title, wave: node.wave },
|
|
99
|
+
});
|
|
100
|
+
let lease = null;
|
|
101
|
+
let lastResult = null;
|
|
102
|
+
const maxAttempts = node.policy.max_retries + 1;
|
|
103
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
104
|
+
const attemptId = `${nodeId}-a${attempt}`;
|
|
105
|
+
this.emit(ctx, {
|
|
106
|
+
type: 'AttemptStarted',
|
|
107
|
+
work_item_id: nodeId,
|
|
108
|
+
attempt_id: attemptId,
|
|
109
|
+
payload: { attempt_number: attempt },
|
|
110
|
+
});
|
|
111
|
+
try {
|
|
112
|
+
const wsReq = {
|
|
113
|
+
work_item_id: nodeId,
|
|
114
|
+
attempt_number: attempt,
|
|
115
|
+
strategy: node.workspace_strategy,
|
|
116
|
+
mutation_scope: node.mutation_scope,
|
|
117
|
+
};
|
|
118
|
+
lease = await ctx.workspaceManager.allocate(wsReq);
|
|
119
|
+
this.emit(ctx, {
|
|
120
|
+
type: 'WorkspaceAllocated',
|
|
121
|
+
work_item_id: nodeId,
|
|
122
|
+
attempt_id: attemptId,
|
|
123
|
+
payload: { workspace_id: lease.workspace_id, strategy: lease.strategy },
|
|
124
|
+
});
|
|
125
|
+
lastResult = await ctx.executor.execute(node, lease, ctx.runId, attempt);
|
|
126
|
+
if (lastResult.success) {
|
|
127
|
+
this.emit(ctx, {
|
|
128
|
+
type: 'WorkItemCompleted',
|
|
129
|
+
work_item_id: nodeId,
|
|
130
|
+
attempt_id: attemptId,
|
|
131
|
+
payload: { attempt_number: attempt, evidence: lastResult.evidence },
|
|
132
|
+
});
|
|
133
|
+
status.set(nodeId, 'completed');
|
|
134
|
+
completed.push(nodeId);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Policy failures never retry
|
|
138
|
+
if (lastResult.failure_class === 'policy')
|
|
139
|
+
break;
|
|
140
|
+
if (attempt < maxAttempts) {
|
|
141
|
+
this.emit(ctx, {
|
|
142
|
+
type: 'RetryScheduled',
|
|
143
|
+
work_item_id: nodeId,
|
|
144
|
+
payload: { next_attempt: attempt + 1, reason: lastResult.failure_class },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
lastResult = {
|
|
150
|
+
success: false,
|
|
151
|
+
failure_class: 'env',
|
|
152
|
+
evidence: [],
|
|
153
|
+
output: String(err),
|
|
154
|
+
};
|
|
155
|
+
if (attempt < maxAttempts) {
|
|
156
|
+
this.emit(ctx, {
|
|
157
|
+
type: 'RetryScheduled',
|
|
158
|
+
work_item_id: nodeId,
|
|
159
|
+
payload: { next_attempt: attempt + 1, reason: 'env' },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
if (lease) {
|
|
165
|
+
await ctx.workspaceManager.dispose(lease.workspace_id).catch(() => { });
|
|
166
|
+
lease = null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// All attempts exhausted
|
|
171
|
+
this.emit(ctx, {
|
|
172
|
+
type: 'WorkItemBlocked',
|
|
173
|
+
work_item_id: nodeId,
|
|
174
|
+
payload: { failure_class: lastResult?.failure_class ?? 'env', max_attempts: maxAttempts },
|
|
175
|
+
});
|
|
176
|
+
status.set(nodeId, 'failed');
|
|
177
|
+
failed.push(nodeId);
|
|
178
|
+
}
|
|
179
|
+
pause() {
|
|
180
|
+
this.paused = true;
|
|
181
|
+
}
|
|
182
|
+
resume() {
|
|
183
|
+
this.paused = false;
|
|
184
|
+
}
|
|
185
|
+
cancel() {
|
|
186
|
+
this.cancelled = true;
|
|
187
|
+
}
|
|
188
|
+
emit(ctx, input) {
|
|
189
|
+
const event = (0, bus_1.appendEvent)(ctx.projectRoot, ctx.sessionId, {
|
|
190
|
+
run_id: ctx.runId,
|
|
191
|
+
...input,
|
|
192
|
+
});
|
|
193
|
+
ctx.onEvent?.(event);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.Scheduler = Scheduler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './verification-compiler';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./verification-compiler"), exports);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { EvidenceType } from '../models/evidence';
|
|
2
|
+
import type { VerificationStatus } from '../models/verification-result';
|
|
3
|
+
export type CheckType = 'unit' | 'integration' | 'contract' | 'smoke' | 'policy' | 'security' | 'ux_snapshot' | 'performance_baseline' | 'custom';
|
|
4
|
+
export interface AcceptanceCheck {
|
|
5
|
+
id: string;
|
|
6
|
+
type: CheckType;
|
|
7
|
+
command: string | null;
|
|
8
|
+
evidence_type_expected: EvidenceType;
|
|
9
|
+
acceptance_ref: string | null;
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AcceptanceCheckSuite {
|
|
13
|
+
checks: AcceptanceCheck[];
|
|
14
|
+
compiled_at: string;
|
|
15
|
+
spec_hash: string;
|
|
16
|
+
plan_hash: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CheckResult {
|
|
19
|
+
check_id: string;
|
|
20
|
+
acceptance_ref: string | null;
|
|
21
|
+
status: VerificationStatus;
|
|
22
|
+
stdout: string;
|
|
23
|
+
stderr: string;
|
|
24
|
+
exit_code: number | null;
|
|
25
|
+
duration_ms: number;
|
|
26
|
+
error: string | null;
|
|
27
|
+
}
|
|
28
|
+
interface Criterion {
|
|
29
|
+
id: string;
|
|
30
|
+
criterion: string;
|
|
31
|
+
howToVerify: string;
|
|
32
|
+
}
|
|
33
|
+
interface ParsedSpecLike {
|
|
34
|
+
objective: string | null;
|
|
35
|
+
criteria: Criterion[];
|
|
36
|
+
}
|
|
37
|
+
interface ParsedTaskLike {
|
|
38
|
+
id: string;
|
|
39
|
+
verifyCommand: string | null;
|
|
40
|
+
aceite: string[];
|
|
41
|
+
}
|
|
42
|
+
interface ParsedPlanLike {
|
|
43
|
+
tasks: ParsedTaskLike[];
|
|
44
|
+
}
|
|
45
|
+
export declare function compile(spec: ParsedSpecLike, plan: ParsedPlanLike): AcceptanceCheckSuite;
|
|
46
|
+
export declare function runCheck(check: AcceptanceCheck, cwd: string, timeoutMs?: number): Promise<CheckResult>;
|
|
47
|
+
export declare function runSuite(suite: AcceptanceCheckSuite, cwd: string, timeoutMs?: number): Promise<CheckResult[]>;
|
|
48
|
+
export declare function summarizeSuite(results: CheckResult[]): {
|
|
49
|
+
total: number;
|
|
50
|
+
pass: number;
|
|
51
|
+
fail: number;
|
|
52
|
+
skip: number;
|
|
53
|
+
error: number;
|
|
54
|
+
allPassed: boolean;
|
|
55
|
+
};
|
|
56
|
+
export {};
|