@aman_asmuei/aman-agent 0.40.0 → 0.41.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/dist/index.js +1227 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -731,17 +731,17 @@ var init_types = __esm({
|
|
|
731
731
|
// src/orchestrator/dag.ts
|
|
732
732
|
function validateDAG(dag) {
|
|
733
733
|
const nodeIds = /* @__PURE__ */ new Set();
|
|
734
|
-
for (const
|
|
735
|
-
if (nodeIds.has(
|
|
736
|
-
throw new DAGValidationError(`Duplicate node id: "${
|
|
734
|
+
for (const node2 of dag.nodes) {
|
|
735
|
+
if (nodeIds.has(node2.id)) {
|
|
736
|
+
throw new DAGValidationError(`Duplicate node id: "${node2.id}"`);
|
|
737
737
|
}
|
|
738
|
-
nodeIds.add(
|
|
738
|
+
nodeIds.add(node2.id);
|
|
739
739
|
}
|
|
740
|
-
for (const
|
|
741
|
-
for (const dep of
|
|
740
|
+
for (const node2 of dag.nodes) {
|
|
741
|
+
for (const dep of node2.dependencies) {
|
|
742
742
|
if (!nodeIds.has(dep)) {
|
|
743
743
|
throw new DAGValidationError(
|
|
744
|
-
`Node "${
|
|
744
|
+
`Node "${node2.id}" depends on nonexistent node "${dep}"`
|
|
745
745
|
);
|
|
746
746
|
}
|
|
747
747
|
}
|
|
@@ -764,14 +764,14 @@ function validateDAG(dag) {
|
|
|
764
764
|
}
|
|
765
765
|
const inDegree = /* @__PURE__ */ new Map();
|
|
766
766
|
const adj = /* @__PURE__ */ new Map();
|
|
767
|
-
for (const
|
|
768
|
-
inDegree.set(
|
|
769
|
-
adj.set(
|
|
767
|
+
for (const node2 of dag.nodes) {
|
|
768
|
+
inDegree.set(node2.id, 0);
|
|
769
|
+
adj.set(node2.id, []);
|
|
770
770
|
}
|
|
771
|
-
for (const
|
|
772
|
-
for (const dep of
|
|
773
|
-
adj.get(dep).push(
|
|
774
|
-
inDegree.set(
|
|
771
|
+
for (const node2 of dag.nodes) {
|
|
772
|
+
for (const dep of node2.dependencies) {
|
|
773
|
+
adj.get(dep).push(node2.id);
|
|
774
|
+
inDegree.set(node2.id, inDegree.get(node2.id) + 1);
|
|
775
775
|
}
|
|
776
776
|
}
|
|
777
777
|
const queue = [];
|
|
@@ -794,6 +794,32 @@ function validateDAG(dag) {
|
|
|
794
794
|
);
|
|
795
795
|
}
|
|
796
796
|
}
|
|
797
|
+
function getReadyNodes(dag, taskStatuses, resolvedGates) {
|
|
798
|
+
const gateBlocked = /* @__PURE__ */ new Set();
|
|
799
|
+
for (const gate of dag.gates) {
|
|
800
|
+
if (resolvedGates?.has(gate.id)) continue;
|
|
801
|
+
const allAfterDone = gate.afterNodes.every(
|
|
802
|
+
(id) => taskStatuses.get(id) === "completed"
|
|
803
|
+
);
|
|
804
|
+
if (allAfterDone) {
|
|
805
|
+
for (const id of gate.beforeNodes) {
|
|
806
|
+
gateBlocked.add(id);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
const ready = [];
|
|
811
|
+
for (const node2 of dag.nodes) {
|
|
812
|
+
if (taskStatuses.get(node2.id) !== "pending") continue;
|
|
813
|
+
if (gateBlocked.has(node2.id)) continue;
|
|
814
|
+
const allDepsCompleted = node2.dependencies.every(
|
|
815
|
+
(dep) => taskStatuses.get(dep) === "completed"
|
|
816
|
+
);
|
|
817
|
+
if (allDepsCompleted) {
|
|
818
|
+
ready.push(node2.id);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return ready;
|
|
822
|
+
}
|
|
797
823
|
var DAGValidationError;
|
|
798
824
|
var init_dag = __esm({
|
|
799
825
|
"src/orchestrator/dag.ts"() {
|
|
@@ -3756,6 +3782,9 @@ var ORCHESTRATOR_PROFILES = [
|
|
|
3756
3782
|
testerProfile,
|
|
3757
3783
|
reviewerProfile
|
|
3758
3784
|
];
|
|
3785
|
+
function getOrchestratorProfile(name) {
|
|
3786
|
+
return ORCHESTRATOR_PROFILES.find((p5) => p5.name === name);
|
|
3787
|
+
}
|
|
3759
3788
|
|
|
3760
3789
|
// src/profile-templates.ts
|
|
3761
3790
|
var BUILT_IN_PROFILES = [
|
|
@@ -6074,21 +6103,950 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
|
|
|
6074
6103
|
|
|
6075
6104
|
// src/orchestrator/index.ts
|
|
6076
6105
|
init_types();
|
|
6106
|
+
|
|
6107
|
+
// src/orchestrator/state-machine.ts
|
|
6108
|
+
var ORCHESTRATION_TRANSITIONS = {
|
|
6109
|
+
pending: ["running", "cancelled"],
|
|
6110
|
+
running: ["awaiting_approval", "paused", "completed", "failed", "cancelled"],
|
|
6111
|
+
awaiting_approval: ["approved", "cancelled", "failed"],
|
|
6112
|
+
approved: ["running", "cancelled"],
|
|
6113
|
+
paused: ["running", "cancelled", "failed"],
|
|
6114
|
+
completed: [],
|
|
6115
|
+
failed: [],
|
|
6116
|
+
cancelled: []
|
|
6117
|
+
};
|
|
6118
|
+
var TASK_TRANSITIONS = {
|
|
6119
|
+
pending: ["ready", "skipped", "blocked"],
|
|
6120
|
+
ready: ["running", "skipped", "blocked"],
|
|
6121
|
+
running: ["completed", "failed"],
|
|
6122
|
+
completed: [],
|
|
6123
|
+
failed: ["ready"],
|
|
6124
|
+
skipped: [],
|
|
6125
|
+
blocked: ["ready", "skipped"]
|
|
6126
|
+
};
|
|
6127
|
+
var TERMINAL_ORCHESTRATION = /* @__PURE__ */ new Set([
|
|
6128
|
+
"completed",
|
|
6129
|
+
"failed",
|
|
6130
|
+
"cancelled"
|
|
6131
|
+
]);
|
|
6132
|
+
var InvalidTransitionError = class extends Error {
|
|
6133
|
+
constructor(from, to, entity = "orchestration") {
|
|
6134
|
+
super(
|
|
6135
|
+
`Invalid ${entity} transition: ${from} \u2192 ${to}`
|
|
6136
|
+
);
|
|
6137
|
+
this.from = from;
|
|
6138
|
+
this.to = to;
|
|
6139
|
+
this.entity = entity;
|
|
6140
|
+
this.name = "InvalidTransitionError";
|
|
6141
|
+
}
|
|
6142
|
+
from;
|
|
6143
|
+
to;
|
|
6144
|
+
entity;
|
|
6145
|
+
};
|
|
6146
|
+
function createOrchestrationState(dag) {
|
|
6147
|
+
const now = Date.now();
|
|
6148
|
+
const taskStatuses = /* @__PURE__ */ new Map();
|
|
6149
|
+
for (const node2 of dag.nodes) {
|
|
6150
|
+
taskStatuses.set(node2.id, "pending");
|
|
6151
|
+
}
|
|
6152
|
+
return {
|
|
6153
|
+
dag,
|
|
6154
|
+
status: "pending",
|
|
6155
|
+
taskStatuses,
|
|
6156
|
+
taskResults: /* @__PURE__ */ new Map(),
|
|
6157
|
+
activeGate: null,
|
|
6158
|
+
startedAt: now,
|
|
6159
|
+
updatedAt: now
|
|
6160
|
+
};
|
|
6161
|
+
}
|
|
6162
|
+
function canTransition(state, to) {
|
|
6163
|
+
return ORCHESTRATION_TRANSITIONS[state.status].includes(to);
|
|
6164
|
+
}
|
|
6165
|
+
function cloneState(state) {
|
|
6166
|
+
return {
|
|
6167
|
+
...state,
|
|
6168
|
+
taskStatuses: new Map(state.taskStatuses),
|
|
6169
|
+
taskResults: new Map(state.taskResults),
|
|
6170
|
+
updatedAt: Date.now()
|
|
6171
|
+
};
|
|
6172
|
+
}
|
|
6173
|
+
function transition(state, to, error) {
|
|
6174
|
+
if (!canTransition(state, to)) {
|
|
6175
|
+
throw new InvalidTransitionError(state.status, to);
|
|
6176
|
+
}
|
|
6177
|
+
const next = cloneState(state);
|
|
6178
|
+
next.status = to;
|
|
6179
|
+
if (TERMINAL_ORCHESTRATION.has(to)) {
|
|
6180
|
+
next.completedAt = next.updatedAt;
|
|
6181
|
+
}
|
|
6182
|
+
if (error !== void 0) {
|
|
6183
|
+
next.error = error;
|
|
6184
|
+
}
|
|
6185
|
+
return next;
|
|
6186
|
+
}
|
|
6187
|
+
function transitionTask(state, taskId, to) {
|
|
6188
|
+
const current = state.taskStatuses.get(taskId);
|
|
6189
|
+
if (current === void 0) {
|
|
6190
|
+
throw new Error(`Unknown task id: ${taskId}`);
|
|
6191
|
+
}
|
|
6192
|
+
if (!TASK_TRANSITIONS[current].includes(to)) {
|
|
6193
|
+
throw new InvalidTransitionError(current, to, "task");
|
|
6194
|
+
}
|
|
6195
|
+
const next = cloneState(state);
|
|
6196
|
+
next.taskStatuses.set(taskId, to);
|
|
6197
|
+
return next;
|
|
6198
|
+
}
|
|
6199
|
+
|
|
6200
|
+
// src/orchestrator/index.ts
|
|
6077
6201
|
init_dag();
|
|
6202
|
+
|
|
6203
|
+
// src/orchestrator/model-router.ts
|
|
6204
|
+
function createModelRouter(clients) {
|
|
6205
|
+
return {
|
|
6206
|
+
getClient(tier) {
|
|
6207
|
+
if (tier === "fast") return clients.fast ?? clients.standard;
|
|
6208
|
+
if (tier === "advanced") return clients.advanced ?? clients.standard;
|
|
6209
|
+
return clients.standard;
|
|
6210
|
+
}
|
|
6211
|
+
};
|
|
6212
|
+
}
|
|
6213
|
+
|
|
6214
|
+
// src/orchestrator/audit.ts
|
|
6215
|
+
function createAuditLog(orchestrationId) {
|
|
6216
|
+
return { orchestrationId, events: [] };
|
|
6217
|
+
}
|
|
6218
|
+
function recordAuditEvent(log5, event) {
|
|
6219
|
+
log5.events.push({ ...event, timestamp: Date.now() });
|
|
6220
|
+
}
|
|
6221
|
+
|
|
6222
|
+
// src/orchestrator/index.ts
|
|
6078
6223
|
init_decompose();
|
|
6079
6224
|
|
|
6080
6225
|
// src/orchestrator/scheduler.ts
|
|
6081
6226
|
init_dag();
|
|
6227
|
+
async function runScheduler(dag, router, options, callbacks) {
|
|
6228
|
+
const startTime = Date.now();
|
|
6229
|
+
const maxParallel = options?.maxParallelTasks ?? 4;
|
|
6230
|
+
const mcpManager = options?.mcpManager ?? null;
|
|
6231
|
+
validateDAG(dag);
|
|
6232
|
+
let state = createOrchestrationState(dag);
|
|
6233
|
+
const auditLog = createAuditLog(dag.id);
|
|
6234
|
+
state = transition(state, "running");
|
|
6235
|
+
recordAuditEvent(auditLog, {
|
|
6236
|
+
type: "orchestration_started",
|
|
6237
|
+
message: `Orchestration "${dag.name}" started`
|
|
6238
|
+
});
|
|
6239
|
+
const resolvedGates = /* @__PURE__ */ new Set();
|
|
6240
|
+
const running = /* @__PURE__ */ new Map();
|
|
6241
|
+
async function transitionOrch(to, error) {
|
|
6242
|
+
const from = state.status;
|
|
6243
|
+
state = transition(state, to, error);
|
|
6244
|
+
if (callbacks?.onPhaseTransition) {
|
|
6245
|
+
await callbacks.onPhaseTransition(from, to);
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
6248
|
+
function dispatchTask(nodeId) {
|
|
6249
|
+
const node2 = dag.nodes.find((n) => n.id === nodeId);
|
|
6250
|
+
state = transitionTask(state, nodeId, "ready");
|
|
6251
|
+
state = transitionTask(state, nodeId, "running");
|
|
6252
|
+
const taskPromise = (async () => {
|
|
6253
|
+
if (callbacks?.onTaskStarted) {
|
|
6254
|
+
await callbacks.onTaskStarted(nodeId, node2.name);
|
|
6255
|
+
}
|
|
6256
|
+
recordAuditEvent(auditLog, {
|
|
6257
|
+
type: "task_started",
|
|
6258
|
+
message: `Task "${node2.name}" started`,
|
|
6259
|
+
taskId: nodeId
|
|
6260
|
+
});
|
|
6261
|
+
const startedAt = Date.now();
|
|
6262
|
+
const client = router.getClient(node2.tier);
|
|
6263
|
+
const taskDesc = [node2.name, node2.description, node2.context].filter(Boolean).join(": ");
|
|
6264
|
+
try {
|
|
6265
|
+
const delegationResult = await delegateTask(
|
|
6266
|
+
taskDesc,
|
|
6267
|
+
node2.profile,
|
|
6268
|
+
client,
|
|
6269
|
+
mcpManager,
|
|
6270
|
+
{ silent: true }
|
|
6271
|
+
);
|
|
6272
|
+
const completedAt = Date.now();
|
|
6273
|
+
if (delegationResult.success) {
|
|
6274
|
+
const taskResult = {
|
|
6275
|
+
nodeId,
|
|
6276
|
+
status: "completed",
|
|
6277
|
+
output: delegationResult.response,
|
|
6278
|
+
toolsUsed: delegationResult.toolsUsed,
|
|
6279
|
+
turns: delegationResult.turns,
|
|
6280
|
+
startedAt,
|
|
6281
|
+
completedAt,
|
|
6282
|
+
tier: node2.tier
|
|
6283
|
+
};
|
|
6284
|
+
state = transitionTask(state, nodeId, "completed");
|
|
6285
|
+
state.taskResults.set(nodeId, taskResult);
|
|
6286
|
+
recordAuditEvent(auditLog, {
|
|
6287
|
+
type: "task_completed",
|
|
6288
|
+
message: `Task "${node2.name}" completed`,
|
|
6289
|
+
taskId: nodeId
|
|
6290
|
+
});
|
|
6291
|
+
if (callbacks?.onTaskCompleted) {
|
|
6292
|
+
await callbacks.onTaskCompleted(nodeId, node2.name, taskResult);
|
|
6293
|
+
}
|
|
6294
|
+
} else {
|
|
6295
|
+
const taskResult = {
|
|
6296
|
+
nodeId,
|
|
6297
|
+
status: "failed",
|
|
6298
|
+
error: delegationResult.error ?? "Task failed",
|
|
6299
|
+
toolsUsed: delegationResult.toolsUsed,
|
|
6300
|
+
turns: delegationResult.turns,
|
|
6301
|
+
startedAt,
|
|
6302
|
+
completedAt,
|
|
6303
|
+
tier: node2.tier
|
|
6304
|
+
};
|
|
6305
|
+
state = transitionTask(state, nodeId, "failed");
|
|
6306
|
+
state.taskResults.set(nodeId, taskResult);
|
|
6307
|
+
recordAuditEvent(auditLog, {
|
|
6308
|
+
type: "task_failed",
|
|
6309
|
+
message: `Task "${node2.name}" failed: ${delegationResult.error}`,
|
|
6310
|
+
taskId: nodeId
|
|
6311
|
+
});
|
|
6312
|
+
if (callbacks?.onTaskFailed) {
|
|
6313
|
+
await callbacks.onTaskFailed(nodeId, node2.name, delegationResult.error ?? "Task failed");
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
} catch (err) {
|
|
6317
|
+
const completedAt = Date.now();
|
|
6318
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
6319
|
+
const taskResult = {
|
|
6320
|
+
nodeId,
|
|
6321
|
+
status: "failed",
|
|
6322
|
+
error: errorMsg,
|
|
6323
|
+
toolsUsed: [],
|
|
6324
|
+
turns: 0,
|
|
6325
|
+
startedAt,
|
|
6326
|
+
completedAt,
|
|
6327
|
+
tier: node2.tier
|
|
6328
|
+
};
|
|
6329
|
+
state = transitionTask(state, nodeId, "failed");
|
|
6330
|
+
state.taskResults.set(nodeId, taskResult);
|
|
6331
|
+
recordAuditEvent(auditLog, {
|
|
6332
|
+
type: "task_failed",
|
|
6333
|
+
message: `Task "${node2.name}" threw: ${errorMsg}`,
|
|
6334
|
+
taskId: nodeId
|
|
6335
|
+
});
|
|
6336
|
+
if (callbacks?.onTaskFailed) {
|
|
6337
|
+
await callbacks.onTaskFailed(nodeId, node2.name, errorMsg);
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
})();
|
|
6341
|
+
running.set(nodeId, taskPromise);
|
|
6342
|
+
taskPromise.then(() => running.delete(nodeId));
|
|
6343
|
+
}
|
|
6344
|
+
try {
|
|
6345
|
+
while (true) {
|
|
6346
|
+
if (["completed", "failed", "cancelled"].includes(state.status)) {
|
|
6347
|
+
break;
|
|
6348
|
+
}
|
|
6349
|
+
const hasFailed = [...state.taskStatuses.values()].some((s) => s === "failed");
|
|
6350
|
+
if (hasFailed) {
|
|
6351
|
+
await transitionOrch("failed", "A task failed");
|
|
6352
|
+
recordAuditEvent(auditLog, {
|
|
6353
|
+
type: "orchestration_failed",
|
|
6354
|
+
message: "Orchestration failed due to task failure"
|
|
6355
|
+
});
|
|
6356
|
+
break;
|
|
6357
|
+
}
|
|
6358
|
+
let gateHandled = false;
|
|
6359
|
+
for (const gate of dag.gates) {
|
|
6360
|
+
if (resolvedGates.has(gate.id)) continue;
|
|
6361
|
+
const allAfterDone = gate.afterNodes.every(
|
|
6362
|
+
(id) => state.taskStatuses.get(id) === "completed"
|
|
6363
|
+
);
|
|
6364
|
+
if (!allAfterDone) continue;
|
|
6365
|
+
gateHandled = true;
|
|
6366
|
+
await transitionOrch("awaiting_approval");
|
|
6367
|
+
recordAuditEvent(auditLog, {
|
|
6368
|
+
type: "approval_requested",
|
|
6369
|
+
message: `Gate "${gate.name}" requires approval`,
|
|
6370
|
+
gateId: gate.id
|
|
6371
|
+
});
|
|
6372
|
+
let approved = false;
|
|
6373
|
+
if (callbacks?.onApprovalRequired) {
|
|
6374
|
+
approved = await callbacks.onApprovalRequired(gate.id, gate.name);
|
|
6375
|
+
}
|
|
6376
|
+
if (approved) {
|
|
6377
|
+
resolvedGates.add(gate.id);
|
|
6378
|
+
await transitionOrch("approved");
|
|
6379
|
+
recordAuditEvent(auditLog, {
|
|
6380
|
+
type: "approval_granted",
|
|
6381
|
+
message: `Gate "${gate.name}" approved`,
|
|
6382
|
+
gateId: gate.id
|
|
6383
|
+
});
|
|
6384
|
+
await transitionOrch("running");
|
|
6385
|
+
recordAuditEvent(auditLog, {
|
|
6386
|
+
type: "gate_resolved",
|
|
6387
|
+
message: `Gate "${gate.name}" resolved, resuming`,
|
|
6388
|
+
gateId: gate.id
|
|
6389
|
+
});
|
|
6390
|
+
} else {
|
|
6391
|
+
await transitionOrch("cancelled");
|
|
6392
|
+
recordAuditEvent(auditLog, {
|
|
6393
|
+
type: "approval_denied",
|
|
6394
|
+
message: `Gate "${gate.name}" denied, cancelling`,
|
|
6395
|
+
gateId: gate.id
|
|
6396
|
+
});
|
|
6397
|
+
break;
|
|
6398
|
+
}
|
|
6399
|
+
}
|
|
6400
|
+
if (["completed", "failed", "cancelled"].includes(state.status)) {
|
|
6401
|
+
break;
|
|
6402
|
+
}
|
|
6403
|
+
const readyNodes = getReadyNodes(dag, state.taskStatuses, resolvedGates);
|
|
6404
|
+
if (readyNodes.length === 0 && running.size === 0) {
|
|
6405
|
+
const allCompleted = [...state.taskStatuses.values()].every(
|
|
6406
|
+
(s) => s === "completed" || s === "skipped"
|
|
6407
|
+
);
|
|
6408
|
+
if (allCompleted) {
|
|
6409
|
+
await transitionOrch("completed");
|
|
6410
|
+
recordAuditEvent(auditLog, {
|
|
6411
|
+
type: "orchestration_completed",
|
|
6412
|
+
message: `Orchestration "${dag.name}" completed successfully`
|
|
6413
|
+
});
|
|
6414
|
+
break;
|
|
6415
|
+
} else {
|
|
6416
|
+
await transitionOrch("failed", "Scheduler stuck: no ready or running tasks");
|
|
6417
|
+
recordAuditEvent(auditLog, {
|
|
6418
|
+
type: "orchestration_failed",
|
|
6419
|
+
message: "Orchestration stuck with no progress possible"
|
|
6420
|
+
});
|
|
6421
|
+
break;
|
|
6422
|
+
}
|
|
6423
|
+
}
|
|
6424
|
+
const availableSlots = maxParallel - running.size;
|
|
6425
|
+
const toDispatch = readyNodes.slice(0, availableSlots);
|
|
6426
|
+
for (const nodeId of toDispatch) {
|
|
6427
|
+
dispatchTask(nodeId);
|
|
6428
|
+
}
|
|
6429
|
+
if (running.size > 0) {
|
|
6430
|
+
await Promise.race(running.values());
|
|
6431
|
+
}
|
|
6432
|
+
}
|
|
6433
|
+
} catch (err) {
|
|
6434
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
6435
|
+
if (!["completed", "failed", "cancelled"].includes(state.status)) {
|
|
6436
|
+
try {
|
|
6437
|
+
state = transition(state, "failed", errorMsg);
|
|
6438
|
+
} catch {
|
|
6439
|
+
}
|
|
6440
|
+
}
|
|
6441
|
+
recordAuditEvent(auditLog, {
|
|
6442
|
+
type: "orchestration_failed",
|
|
6443
|
+
message: `Orchestration error: ${errorMsg}`
|
|
6444
|
+
});
|
|
6445
|
+
}
|
|
6446
|
+
return {
|
|
6447
|
+
status: state.status,
|
|
6448
|
+
taskResults: state.taskResults,
|
|
6449
|
+
auditLog,
|
|
6450
|
+
error: state.error,
|
|
6451
|
+
durationMs: Date.now() - startTime
|
|
6452
|
+
};
|
|
6453
|
+
}
|
|
6454
|
+
|
|
6455
|
+
// src/orchestrator/review-loop.ts
|
|
6456
|
+
function buildReviewDAG(originalDAG, taskResults) {
|
|
6457
|
+
let context = "Review the following completed work:\n\n";
|
|
6458
|
+
for (const node2 of originalDAG.nodes) {
|
|
6459
|
+
const result = taskResults.get(node2.id);
|
|
6460
|
+
context += `## Task: ${node2.name}
|
|
6461
|
+
`;
|
|
6462
|
+
context += `Profile: ${node2.profile}
|
|
6463
|
+
`;
|
|
6464
|
+
context += `Output: ${result?.output ?? "(no output)"}
|
|
6465
|
+
|
|
6466
|
+
`;
|
|
6467
|
+
}
|
|
6468
|
+
return {
|
|
6469
|
+
id: `review-${originalDAG.id}`,
|
|
6470
|
+
name: `Review: ${originalDAG.name}`,
|
|
6471
|
+
goal: `Review the completed work from "${originalDAG.name}"`,
|
|
6472
|
+
nodes: [
|
|
6473
|
+
{
|
|
6474
|
+
id: "code-review",
|
|
6475
|
+
name: "Code Review",
|
|
6476
|
+
profile: "reviewer",
|
|
6477
|
+
tier: "standard",
|
|
6478
|
+
dependencies: [],
|
|
6479
|
+
context
|
|
6480
|
+
},
|
|
6481
|
+
{
|
|
6482
|
+
id: "test-review",
|
|
6483
|
+
name: "Test Review",
|
|
6484
|
+
profile: "tester",
|
|
6485
|
+
tier: "standard",
|
|
6486
|
+
dependencies: [],
|
|
6487
|
+
context
|
|
6488
|
+
}
|
|
6489
|
+
],
|
|
6490
|
+
gates: []
|
|
6491
|
+
};
|
|
6492
|
+
}
|
|
6493
|
+
async function runReviewLoop(originalDAG, taskResults, options) {
|
|
6494
|
+
const reviewDAG = buildReviewDAG(originalDAG, taskResults);
|
|
6495
|
+
const schedulerResult = await runScheduler(
|
|
6496
|
+
reviewDAG,
|
|
6497
|
+
options.router,
|
|
6498
|
+
{},
|
|
6499
|
+
options.callbacks
|
|
6500
|
+
);
|
|
6501
|
+
if (schedulerResult.status === "completed") {
|
|
6502
|
+
return {
|
|
6503
|
+
passed: true,
|
|
6504
|
+
iterations: 1,
|
|
6505
|
+
reviewResult: schedulerResult
|
|
6506
|
+
};
|
|
6507
|
+
}
|
|
6508
|
+
return {
|
|
6509
|
+
passed: false,
|
|
6510
|
+
iterations: 1,
|
|
6511
|
+
reason: schedulerResult.error,
|
|
6512
|
+
reviewResult: schedulerResult
|
|
6513
|
+
};
|
|
6514
|
+
}
|
|
6515
|
+
|
|
6516
|
+
// src/orchestrator/circuit-breaker.ts
|
|
6517
|
+
var DEFAULTS = {
|
|
6518
|
+
failureThreshold: 3,
|
|
6519
|
+
resetTimeoutMs: 6e4,
|
|
6520
|
+
halfOpenMaxAttempts: 1
|
|
6521
|
+
};
|
|
6522
|
+
function createCircuitBreaker(name, options) {
|
|
6523
|
+
const opts = { ...DEFAULTS, ...options };
|
|
6524
|
+
let state = "closed";
|
|
6525
|
+
let failures = 0;
|
|
6526
|
+
let lastFailureAt = null;
|
|
6527
|
+
let openedAt = null;
|
|
6528
|
+
let halfOpenAttempts = 0;
|
|
6529
|
+
function checkHalfOpen() {
|
|
6530
|
+
if (state === "open" && openedAt !== null && Date.now() - openedAt >= opts.resetTimeoutMs) {
|
|
6531
|
+
state = "half-open";
|
|
6532
|
+
halfOpenAttempts = 0;
|
|
6533
|
+
}
|
|
6534
|
+
}
|
|
6535
|
+
return {
|
|
6536
|
+
get name() {
|
|
6537
|
+
return name;
|
|
6538
|
+
},
|
|
6539
|
+
get state() {
|
|
6540
|
+
checkHalfOpen();
|
|
6541
|
+
return state;
|
|
6542
|
+
},
|
|
6543
|
+
get failures() {
|
|
6544
|
+
return failures;
|
|
6545
|
+
},
|
|
6546
|
+
get lastFailureAt() {
|
|
6547
|
+
return lastFailureAt;
|
|
6548
|
+
},
|
|
6549
|
+
canExecute() {
|
|
6550
|
+
checkHalfOpen();
|
|
6551
|
+
if (state === "closed") return true;
|
|
6552
|
+
if (state === "open") return false;
|
|
6553
|
+
if (halfOpenAttempts >= opts.halfOpenMaxAttempts) return false;
|
|
6554
|
+
halfOpenAttempts++;
|
|
6555
|
+
return true;
|
|
6556
|
+
},
|
|
6557
|
+
recordSuccess() {
|
|
6558
|
+
if (state === "half-open") {
|
|
6559
|
+
state = "closed";
|
|
6560
|
+
failures = 0;
|
|
6561
|
+
lastFailureAt = null;
|
|
6562
|
+
openedAt = null;
|
|
6563
|
+
halfOpenAttempts = 0;
|
|
6564
|
+
}
|
|
6565
|
+
},
|
|
6566
|
+
recordFailure() {
|
|
6567
|
+
failures++;
|
|
6568
|
+
lastFailureAt = Date.now();
|
|
6569
|
+
if (state === "half-open") {
|
|
6570
|
+
state = "open";
|
|
6571
|
+
openedAt = Date.now();
|
|
6572
|
+
halfOpenAttempts = 0;
|
|
6573
|
+
} else if (failures >= opts.failureThreshold) {
|
|
6574
|
+
state = "open";
|
|
6575
|
+
openedAt = Date.now();
|
|
6576
|
+
}
|
|
6577
|
+
},
|
|
6578
|
+
reset() {
|
|
6579
|
+
state = "closed";
|
|
6580
|
+
failures = 0;
|
|
6581
|
+
lastFailureAt = null;
|
|
6582
|
+
openedAt = null;
|
|
6583
|
+
halfOpenAttempts = 0;
|
|
6584
|
+
}
|
|
6585
|
+
};
|
|
6586
|
+
}
|
|
6587
|
+
function createCircuitBreakerRegistry(options) {
|
|
6588
|
+
const breakers = /* @__PURE__ */ new Map();
|
|
6589
|
+
return {
|
|
6590
|
+
get(name) {
|
|
6591
|
+
let cb = breakers.get(name);
|
|
6592
|
+
if (!cb) {
|
|
6593
|
+
cb = createCircuitBreaker(name, options);
|
|
6594
|
+
breakers.set(name, cb);
|
|
6595
|
+
}
|
|
6596
|
+
return cb;
|
|
6597
|
+
},
|
|
6598
|
+
getAll() {
|
|
6599
|
+
return [...breakers.values()];
|
|
6600
|
+
},
|
|
6601
|
+
resetAll() {
|
|
6602
|
+
for (const cb of breakers.values()) {
|
|
6603
|
+
cb.reset();
|
|
6604
|
+
}
|
|
6605
|
+
},
|
|
6606
|
+
formatStatus() {
|
|
6607
|
+
if (breakers.size === 0) {
|
|
6608
|
+
return "No circuit breakers registered.";
|
|
6609
|
+
}
|
|
6610
|
+
const lines = [...breakers.values()].map(
|
|
6611
|
+
(cb) => ` ${cb.name}: state=${cb.state} failures=${cb.failures}`
|
|
6612
|
+
);
|
|
6613
|
+
return `Circuit breakers (${breakers.size}):
|
|
6614
|
+
${lines.join("\n")}`;
|
|
6615
|
+
}
|
|
6616
|
+
};
|
|
6617
|
+
}
|
|
6082
6618
|
|
|
6083
6619
|
// src/orchestrator/checkpoint.ts
|
|
6084
6620
|
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
6085
6621
|
import { join } from "path";
|
|
6086
6622
|
|
|
6623
|
+
// src/orchestrator/cost-tracker.ts
|
|
6624
|
+
var DEFAULT_TIER_COSTS = {
|
|
6625
|
+
fast: {
|
|
6626
|
+
inputTokensPerDollar: 5e6,
|
|
6627
|
+
outputTokensPerDollar: 125e4
|
|
6628
|
+
},
|
|
6629
|
+
// ~$0.20/$0.80 per 1M
|
|
6630
|
+
standard: {
|
|
6631
|
+
inputTokensPerDollar: 333333,
|
|
6632
|
+
outputTokensPerDollar: 66667
|
|
6633
|
+
},
|
|
6634
|
+
// ~$3/$15 per 1M
|
|
6635
|
+
advanced: {
|
|
6636
|
+
inputTokensPerDollar: 66667,
|
|
6637
|
+
outputTokensPerDollar: 13333
|
|
6638
|
+
}
|
|
6639
|
+
// ~$15/$75 per 1M
|
|
6640
|
+
};
|
|
6641
|
+
function createCostTracker(options) {
|
|
6642
|
+
const budgetLimit = options?.budgetLimit ?? null;
|
|
6643
|
+
const tierCosts = {
|
|
6644
|
+
...DEFAULT_TIER_COSTS,
|
|
6645
|
+
...options?.tierCosts
|
|
6646
|
+
};
|
|
6647
|
+
const _entries = [];
|
|
6648
|
+
function estimateCost(tier, inputTokens, outputTokens) {
|
|
6649
|
+
const rates = tierCosts[tier];
|
|
6650
|
+
return inputTokens / rates.inputTokensPerDollar + outputTokens / rates.outputTokensPerDollar;
|
|
6651
|
+
}
|
|
6652
|
+
function record(taskId, tier, inputTokens, outputTokens) {
|
|
6653
|
+
_entries.push({
|
|
6654
|
+
tier,
|
|
6655
|
+
taskId,
|
|
6656
|
+
inputTokens,
|
|
6657
|
+
outputTokens,
|
|
6658
|
+
estimatedCost: estimateCost(tier, inputTokens, outputTokens),
|
|
6659
|
+
timestamp: Date.now()
|
|
6660
|
+
});
|
|
6661
|
+
}
|
|
6662
|
+
function totalCost() {
|
|
6663
|
+
return _entries.reduce((sum, e) => sum + e.estimatedCost, 0);
|
|
6664
|
+
}
|
|
6665
|
+
function costByTier() {
|
|
6666
|
+
const result = {
|
|
6667
|
+
fast: 0,
|
|
6668
|
+
standard: 0,
|
|
6669
|
+
advanced: 0
|
|
6670
|
+
};
|
|
6671
|
+
for (const entry of _entries) {
|
|
6672
|
+
result[entry.tier] += entry.estimatedCost;
|
|
6673
|
+
}
|
|
6674
|
+
return result;
|
|
6675
|
+
}
|
|
6676
|
+
function entries() {
|
|
6677
|
+
return [..._entries];
|
|
6678
|
+
}
|
|
6679
|
+
function isOverBudget() {
|
|
6680
|
+
if (budgetLimit === null) return false;
|
|
6681
|
+
return totalCost() > budgetLimit;
|
|
6682
|
+
}
|
|
6683
|
+
function remainingBudget() {
|
|
6684
|
+
if (budgetLimit === null) return null;
|
|
6685
|
+
return budgetLimit - totalCost();
|
|
6686
|
+
}
|
|
6687
|
+
function formatSummary() {
|
|
6688
|
+
const total = totalCost();
|
|
6689
|
+
const byTier = costByTier();
|
|
6690
|
+
const lines = [];
|
|
6691
|
+
lines.push(`Total: $${total.toFixed(4)}`);
|
|
6692
|
+
for (const tier of ["fast", "standard", "advanced"]) {
|
|
6693
|
+
if (byTier[tier] > 0) {
|
|
6694
|
+
lines.push(` ${tier}: $${byTier[tier].toFixed(4)}`);
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
if (budgetLimit !== null) {
|
|
6698
|
+
const remaining = remainingBudget();
|
|
6699
|
+
lines.push(
|
|
6700
|
+
`Budget: $${budgetLimit.toFixed(2)} | Remaining: $${remaining.toFixed(4)}`
|
|
6701
|
+
);
|
|
6702
|
+
}
|
|
6703
|
+
lines.push(`Entries: ${_entries.length}`);
|
|
6704
|
+
return lines.join("\n");
|
|
6705
|
+
}
|
|
6706
|
+
return {
|
|
6707
|
+
record,
|
|
6708
|
+
totalCost,
|
|
6709
|
+
costByTier,
|
|
6710
|
+
entries,
|
|
6711
|
+
isOverBudget,
|
|
6712
|
+
remainingBudget,
|
|
6713
|
+
formatSummary
|
|
6714
|
+
};
|
|
6715
|
+
}
|
|
6716
|
+
|
|
6717
|
+
// src/orchestrator/policy.ts
|
|
6718
|
+
var maxTaskCount = {
|
|
6719
|
+
name: "max-task-count",
|
|
6720
|
+
description: "DAG has more than 20 tasks",
|
|
6721
|
+
severity: "warning",
|
|
6722
|
+
check: (dag) => {
|
|
6723
|
+
if (dag.nodes.length > 20) {
|
|
6724
|
+
return [
|
|
6725
|
+
{
|
|
6726
|
+
rule: "max-task-count",
|
|
6727
|
+
severity: "warning",
|
|
6728
|
+
message: `DAG has ${dag.nodes.length} tasks (limit: 20)`
|
|
6729
|
+
}
|
|
6730
|
+
];
|
|
6731
|
+
}
|
|
6732
|
+
return [];
|
|
6733
|
+
}
|
|
6734
|
+
};
|
|
6735
|
+
var requiresReview = {
|
|
6736
|
+
name: "requires-review",
|
|
6737
|
+
description: 'No node with profile "reviewer" exists',
|
|
6738
|
+
severity: "warning",
|
|
6739
|
+
check: (dag) => {
|
|
6740
|
+
const hasReviewer = dag.nodes.some((n) => n.profile === "reviewer");
|
|
6741
|
+
if (!hasReviewer) {
|
|
6742
|
+
return [
|
|
6743
|
+
{
|
|
6744
|
+
rule: "requires-review",
|
|
6745
|
+
severity: "warning",
|
|
6746
|
+
message: "DAG has no reviewer node \u2014 consider adding a code review step"
|
|
6747
|
+
}
|
|
6748
|
+
];
|
|
6749
|
+
}
|
|
6750
|
+
return [];
|
|
6751
|
+
}
|
|
6752
|
+
};
|
|
6753
|
+
var requiresTesting = {
|
|
6754
|
+
name: "requires-testing",
|
|
6755
|
+
description: 'No node with profile "tester" exists',
|
|
6756
|
+
severity: "warning",
|
|
6757
|
+
check: (dag) => {
|
|
6758
|
+
const hasTester = dag.nodes.some((n) => n.profile === "tester");
|
|
6759
|
+
if (!hasTester) {
|
|
6760
|
+
return [
|
|
6761
|
+
{
|
|
6762
|
+
rule: "requires-testing",
|
|
6763
|
+
severity: "warning",
|
|
6764
|
+
message: "DAG has no tester node \u2014 consider adding a testing step"
|
|
6765
|
+
}
|
|
6766
|
+
];
|
|
6767
|
+
}
|
|
6768
|
+
return [];
|
|
6769
|
+
}
|
|
6770
|
+
};
|
|
6771
|
+
var noOrphanNodes = {
|
|
6772
|
+
name: "no-orphan-nodes",
|
|
6773
|
+
description: "Every node is either a root or has valid dependencies",
|
|
6774
|
+
severity: "error",
|
|
6775
|
+
check: (dag) => {
|
|
6776
|
+
const nodeIds = new Set(dag.nodes.map((n) => n.id));
|
|
6777
|
+
const violations = [];
|
|
6778
|
+
for (const node2 of dag.nodes) {
|
|
6779
|
+
for (const dep of node2.dependencies) {
|
|
6780
|
+
if (!nodeIds.has(dep)) {
|
|
6781
|
+
violations.push({
|
|
6782
|
+
rule: "no-orphan-nodes",
|
|
6783
|
+
severity: "error",
|
|
6784
|
+
message: `Node "${node2.id}" depends on "${dep}" which does not exist`,
|
|
6785
|
+
nodeId: node2.id
|
|
6786
|
+
});
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
return violations;
|
|
6791
|
+
}
|
|
6792
|
+
};
|
|
6793
|
+
var approvalBeforeDeploy = {
|
|
6794
|
+
name: "approval-before-deploy",
|
|
6795
|
+
description: "If any node name contains 'deploy' or 'release', an approval gate should exist",
|
|
6796
|
+
severity: "warning",
|
|
6797
|
+
check: (dag) => {
|
|
6798
|
+
const deployNodes = dag.nodes.filter((n) => {
|
|
6799
|
+
const lower = n.name.toLowerCase();
|
|
6800
|
+
return lower.includes("deploy") || lower.includes("release");
|
|
6801
|
+
});
|
|
6802
|
+
if (deployNodes.length === 0) return [];
|
|
6803
|
+
const hasApprovalGate = dag.gates.some((g) => g.type === "approval");
|
|
6804
|
+
if (hasApprovalGate) return [];
|
|
6805
|
+
return deployNodes.map((n) => ({
|
|
6806
|
+
rule: "approval-before-deploy",
|
|
6807
|
+
severity: "warning",
|
|
6808
|
+
message: `Node "${n.name}" looks like a deploy/release step but no approval gate exists`,
|
|
6809
|
+
nodeId: n.id
|
|
6810
|
+
}));
|
|
6811
|
+
}
|
|
6812
|
+
};
|
|
6813
|
+
var noAdvancedWithoutJustification = {
|
|
6814
|
+
name: "no-advanced-without-justification",
|
|
6815
|
+
description: 'Nodes with tier "advanced" flagged for cost awareness',
|
|
6816
|
+
severity: "info",
|
|
6817
|
+
check: (dag) => dag.nodes.filter((n) => n.tier === "advanced").map((n) => ({
|
|
6818
|
+
rule: "no-advanced-without-justification",
|
|
6819
|
+
severity: "info",
|
|
6820
|
+
message: `Node "${n.id}" uses advanced tier \u2014 ensure this is justified for cost`,
|
|
6821
|
+
nodeId: n.id
|
|
6822
|
+
}))
|
|
6823
|
+
};
|
|
6824
|
+
var maxParallelDepth = {
|
|
6825
|
+
name: "max-parallel-depth",
|
|
6826
|
+
description: "DAG has more than 5 levels of depth",
|
|
6827
|
+
severity: "warning",
|
|
6828
|
+
check: (dag) => {
|
|
6829
|
+
const nodeIds = new Set(dag.nodes.map((n) => n.id));
|
|
6830
|
+
const depthMap = /* @__PURE__ */ new Map();
|
|
6831
|
+
function getDepth(node2, visited) {
|
|
6832
|
+
if (depthMap.has(node2.id)) return depthMap.get(node2.id);
|
|
6833
|
+
if (visited.has(node2.id)) return 0;
|
|
6834
|
+
visited.add(node2.id);
|
|
6835
|
+
let maxDep = 0;
|
|
6836
|
+
for (const depId of node2.dependencies) {
|
|
6837
|
+
const depNode = dag.nodes.find((n) => n.id === depId);
|
|
6838
|
+
if (depNode) {
|
|
6839
|
+
maxDep = Math.max(maxDep, getDepth(depNode, visited) + 1);
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
depthMap.set(node2.id, maxDep);
|
|
6843
|
+
return maxDep;
|
|
6844
|
+
}
|
|
6845
|
+
for (const node2 of dag.nodes) {
|
|
6846
|
+
getDepth(node2, /* @__PURE__ */ new Set());
|
|
6847
|
+
}
|
|
6848
|
+
const maxDepth = Math.max(0, ...depthMap.values());
|
|
6849
|
+
if (maxDepth > 5) {
|
|
6850
|
+
return [
|
|
6851
|
+
{
|
|
6852
|
+
rule: "max-parallel-depth",
|
|
6853
|
+
severity: "warning",
|
|
6854
|
+
message: `DAG depth is ${maxDepth} (limit: 5)`
|
|
6855
|
+
}
|
|
6856
|
+
];
|
|
6857
|
+
}
|
|
6858
|
+
return [];
|
|
6859
|
+
}
|
|
6860
|
+
};
|
|
6861
|
+
function getDefaultPolicies() {
|
|
6862
|
+
return [
|
|
6863
|
+
maxTaskCount,
|
|
6864
|
+
requiresReview,
|
|
6865
|
+
requiresTesting,
|
|
6866
|
+
noOrphanNodes,
|
|
6867
|
+
approvalBeforeDeploy,
|
|
6868
|
+
noAdvancedWithoutJustification,
|
|
6869
|
+
maxParallelDepth
|
|
6870
|
+
];
|
|
6871
|
+
}
|
|
6872
|
+
function evaluatePolicy(dag, rules) {
|
|
6873
|
+
const effectiveRules = rules ?? getDefaultPolicies();
|
|
6874
|
+
const violations = [];
|
|
6875
|
+
for (const rule of effectiveRules) {
|
|
6876
|
+
violations.push(...rule.check(dag));
|
|
6877
|
+
}
|
|
6878
|
+
const hasErrors = violations.some((v) => v.severity === "error");
|
|
6879
|
+
return {
|
|
6880
|
+
passed: !hasErrors,
|
|
6881
|
+
violations
|
|
6882
|
+
};
|
|
6883
|
+
}
|
|
6884
|
+
|
|
6885
|
+
// src/orchestrator/runner.ts
|
|
6886
|
+
async function runOrchestrationFull(dag, options) {
|
|
6887
|
+
const startTime = Date.now();
|
|
6888
|
+
let policyResult;
|
|
6889
|
+
if (options.enablePolicyCheck) {
|
|
6890
|
+
policyResult = evaluatePolicy(dag);
|
|
6891
|
+
if (!policyResult.passed) {
|
|
6892
|
+
const errorMessages = policyResult.violations.filter((v) => v.severity === "error").map((v) => v.message).join("; ");
|
|
6893
|
+
return {
|
|
6894
|
+
scheduler: {
|
|
6895
|
+
status: "failed",
|
|
6896
|
+
taskResults: /* @__PURE__ */ new Map(),
|
|
6897
|
+
auditLog: createAuditLog(dag.id),
|
|
6898
|
+
error: `Policy check failed: ${errorMessages}`,
|
|
6899
|
+
durationMs: Date.now() - startTime
|
|
6900
|
+
},
|
|
6901
|
+
policy: policyResult,
|
|
6902
|
+
success: false,
|
|
6903
|
+
durationMs: Date.now() - startTime
|
|
6904
|
+
};
|
|
6905
|
+
}
|
|
6906
|
+
}
|
|
6907
|
+
const circuitBreakers = options.enableCircuitBreaker ? createCircuitBreakerRegistry() : void 0;
|
|
6908
|
+
const costTracker = options.enableCostTracking ? createCostTracker({ budgetLimit: options.budgetLimit }) : void 0;
|
|
6909
|
+
const wrappedCallbacks = {
|
|
6910
|
+
...options.callbacks,
|
|
6911
|
+
onTaskStarted: async (nodeId, nodeName) => {
|
|
6912
|
+
const node2 = dag.nodes.find((n) => n.id === nodeId);
|
|
6913
|
+
if (circuitBreakers && node2) {
|
|
6914
|
+
circuitBreakers.get(node2.profile).canExecute();
|
|
6915
|
+
}
|
|
6916
|
+
await options.callbacks?.onTaskStarted?.(nodeId, nodeName);
|
|
6917
|
+
},
|
|
6918
|
+
onTaskCompleted: async (nodeId, nodeName, result) => {
|
|
6919
|
+
const node2 = dag.nodes.find((n) => n.id === nodeId);
|
|
6920
|
+
if (node2) {
|
|
6921
|
+
circuitBreakers?.get(node2.profile).recordSuccess();
|
|
6922
|
+
costTracker?.record(nodeId, node2.tier, result.turns * 500, result.turns * 200);
|
|
6923
|
+
}
|
|
6924
|
+
await options.callbacks?.onTaskCompleted?.(nodeId, nodeName, result);
|
|
6925
|
+
},
|
|
6926
|
+
onTaskFailed: async (nodeId, nodeName, error) => {
|
|
6927
|
+
const node2 = dag.nodes.find((n) => n.id === nodeId);
|
|
6928
|
+
if (node2) {
|
|
6929
|
+
circuitBreakers?.get(node2.profile).recordFailure();
|
|
6930
|
+
}
|
|
6931
|
+
await options.callbacks?.onTaskFailed?.(nodeId, nodeName, error);
|
|
6932
|
+
}
|
|
6933
|
+
};
|
|
6934
|
+
const schedulerResult = await runScheduler(dag, options.router, {
|
|
6935
|
+
maxParallelTasks: options.maxParallelTasks
|
|
6936
|
+
}, wrappedCallbacks);
|
|
6937
|
+
let reviewResult;
|
|
6938
|
+
if (options.enableSelfReview && schedulerResult.status === "completed") {
|
|
6939
|
+
reviewResult = await runReviewLoop(dag, schedulerResult.taskResults, {
|
|
6940
|
+
router: options.router
|
|
6941
|
+
});
|
|
6942
|
+
}
|
|
6943
|
+
const success = schedulerResult.status === "completed" && (reviewResult ? reviewResult.passed : true) && (costTracker ? !costTracker.isOverBudget() : true);
|
|
6944
|
+
return {
|
|
6945
|
+
scheduler: schedulerResult,
|
|
6946
|
+
policy: policyResult,
|
|
6947
|
+
review: reviewResult,
|
|
6948
|
+
costSummary: costTracker?.formatSummary(),
|
|
6949
|
+
circuitBreakerStatus: circuitBreakers?.formatStatus(),
|
|
6950
|
+
success,
|
|
6951
|
+
durationMs: Date.now() - startTime
|
|
6952
|
+
};
|
|
6953
|
+
}
|
|
6954
|
+
|
|
6087
6955
|
// src/orchestrator/smart-orchestrate.ts
|
|
6088
6956
|
init_decompose();
|
|
6089
6957
|
|
|
6090
6958
|
// src/orchestrator/templates/index.ts
|
|
6091
6959
|
init_dag();
|
|
6960
|
+
function node(id, profile, tier, deps = []) {
|
|
6961
|
+
return {
|
|
6962
|
+
id,
|
|
6963
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
6964
|
+
profile,
|
|
6965
|
+
tier,
|
|
6966
|
+
dependencies: deps
|
|
6967
|
+
};
|
|
6968
|
+
}
|
|
6969
|
+
function approvalGate(id, afterNodes, beforeNodes) {
|
|
6970
|
+
return {
|
|
6971
|
+
id,
|
|
6972
|
+
name: `Approval: ${id}`,
|
|
6973
|
+
type: "approval",
|
|
6974
|
+
afterNodes,
|
|
6975
|
+
beforeNodes
|
|
6976
|
+
};
|
|
6977
|
+
}
|
|
6978
|
+
function fullFeatureTemplate(options) {
|
|
6979
|
+
const gates = [];
|
|
6980
|
+
if (options.requireApproval) {
|
|
6981
|
+
gates.push(approvalGate("approval", ["review", "test"], ["finalize"]));
|
|
6982
|
+
}
|
|
6983
|
+
const dag = {
|
|
6984
|
+
id: `full-feature-${options.name}`,
|
|
6985
|
+
name: `Full Feature: ${options.name}`,
|
|
6986
|
+
goal: options.goal,
|
|
6987
|
+
nodes: [
|
|
6988
|
+
node("design", "architect", "advanced"),
|
|
6989
|
+
node("implement", "coder", "standard", ["design"]),
|
|
6990
|
+
node("review", "reviewer", "standard", ["implement"]),
|
|
6991
|
+
node("test", "tester", "standard", ["implement"]),
|
|
6992
|
+
node("finalize", "coder", "standard", ["review", "test"])
|
|
6993
|
+
],
|
|
6994
|
+
gates
|
|
6995
|
+
};
|
|
6996
|
+
validateDAG(dag);
|
|
6997
|
+
return dag;
|
|
6998
|
+
}
|
|
6999
|
+
function bugFixTemplate(options) {
|
|
7000
|
+
const nodes = [
|
|
7001
|
+
node("reproduce", "tester", "standard"),
|
|
7002
|
+
node("fix", "coder", "standard", ["reproduce"]),
|
|
7003
|
+
node("test", "tester", "standard", ["fix"]),
|
|
7004
|
+
node("review", "reviewer", "standard", ["test"])
|
|
7005
|
+
];
|
|
7006
|
+
const gates = [];
|
|
7007
|
+
if (options.requireApproval) {
|
|
7008
|
+
nodes.push(node("verify", "tester", "standard", ["review"]));
|
|
7009
|
+
gates.push(approvalGate("approval", ["review"], ["verify"]));
|
|
7010
|
+
}
|
|
7011
|
+
const dag = {
|
|
7012
|
+
id: `bug-fix-${options.name}`,
|
|
7013
|
+
name: `Bug Fix: ${options.name}`,
|
|
7014
|
+
goal: options.goal,
|
|
7015
|
+
nodes,
|
|
7016
|
+
gates
|
|
7017
|
+
};
|
|
7018
|
+
validateDAG(dag);
|
|
7019
|
+
return dag;
|
|
7020
|
+
}
|
|
7021
|
+
function securityAuditTemplate(options) {
|
|
7022
|
+
const gates = [];
|
|
7023
|
+
if (options.requireApproval) {
|
|
7024
|
+
gates.push(approvalGate("approval", ["triage"], ["fix"]));
|
|
7025
|
+
}
|
|
7026
|
+
const dag = {
|
|
7027
|
+
id: `security-audit-${options.name}`,
|
|
7028
|
+
name: `Security Audit: ${options.name}`,
|
|
7029
|
+
goal: options.goal,
|
|
7030
|
+
nodes: [
|
|
7031
|
+
node("scan", "security", "standard"),
|
|
7032
|
+
node("triage", "security", "standard", ["scan"]),
|
|
7033
|
+
node("fix", "coder", "standard", ["triage"]),
|
|
7034
|
+
node("rescan", "security", "standard", ["fix"]),
|
|
7035
|
+
node("review", "reviewer", "standard", ["rescan"])
|
|
7036
|
+
],
|
|
7037
|
+
gates
|
|
7038
|
+
};
|
|
7039
|
+
validateDAG(dag);
|
|
7040
|
+
return dag;
|
|
7041
|
+
}
|
|
7042
|
+
var TEMPLATES = {
|
|
7043
|
+
"full-feature": fullFeatureTemplate,
|
|
7044
|
+
"bug-fix": bugFixTemplate,
|
|
7045
|
+
"security-audit": securityAuditTemplate
|
|
7046
|
+
};
|
|
7047
|
+
function getTemplate(name) {
|
|
7048
|
+
return TEMPLATES[name];
|
|
7049
|
+
}
|
|
6092
7050
|
|
|
6093
7051
|
// src/project/detector.ts
|
|
6094
7052
|
var FRONTEND_FRAMEWORKS = /* @__PURE__ */ new Set(["react", "vue", "svelte"]);
|
|
@@ -6106,11 +7064,92 @@ var BACKEND_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
|
6106
7064
|
"django",
|
|
6107
7065
|
"flask"
|
|
6108
7066
|
]);
|
|
7067
|
+
var ML_FRAMEWORKS = /* @__PURE__ */ new Set(["torch", "tensorflow", "sklearn", "pytorch", "pandas", "numpy"]);
|
|
6109
7068
|
var WEB_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
6110
7069
|
...FRONTEND_FRAMEWORKS,
|
|
6111
7070
|
...FULLSTACK_FRAMEWORKS,
|
|
6112
7071
|
...BACKEND_FRAMEWORKS
|
|
6113
7072
|
]);
|
|
7073
|
+
var TEMPLATE_MAP = {
|
|
7074
|
+
"web-frontend": "full-feature",
|
|
7075
|
+
"web-fullstack": "full-feature",
|
|
7076
|
+
"api-backend": "full-feature",
|
|
7077
|
+
mobile: "full-feature",
|
|
7078
|
+
"cli-tool": "bug-fix",
|
|
7079
|
+
library: "full-feature",
|
|
7080
|
+
"ml-data": "full-feature",
|
|
7081
|
+
monorepo: "full-feature",
|
|
7082
|
+
unknown: "full-feature"
|
|
7083
|
+
};
|
|
7084
|
+
var PROFILE_MAP = {
|
|
7085
|
+
"web-frontend": ["architect", "coder", "tester", "reviewer"],
|
|
7086
|
+
"web-fullstack": ["architect", "coder", "security", "tester", "reviewer"],
|
|
7087
|
+
"api-backend": ["architect", "coder", "security", "tester", "reviewer"],
|
|
7088
|
+
mobile: ["architect", "coder", "tester", "reviewer"],
|
|
7089
|
+
"cli-tool": ["coder", "tester", "reviewer"],
|
|
7090
|
+
library: ["architect", "coder", "tester", "reviewer"],
|
|
7091
|
+
"ml-data": ["architect", "coder", "tester"],
|
|
7092
|
+
monorepo: ["architect", "coder", "security", "tester", "reviewer"],
|
|
7093
|
+
unknown: ["coder", "tester", "reviewer"]
|
|
7094
|
+
};
|
|
7095
|
+
var DESCRIPTION_MAP = {
|
|
7096
|
+
"web-frontend": "Frontend web application",
|
|
7097
|
+
"web-fullstack": "Full-stack web application with database",
|
|
7098
|
+
"api-backend": "API/backend service",
|
|
7099
|
+
mobile: "Mobile application",
|
|
7100
|
+
"cli-tool": "Command-line tool",
|
|
7101
|
+
library: "Reusable library/package",
|
|
7102
|
+
"ml-data": "Machine learning / data science project",
|
|
7103
|
+
monorepo: "Monorepo with multiple packages",
|
|
7104
|
+
unknown: "Unknown project type"
|
|
7105
|
+
};
|
|
7106
|
+
function hasAny(items, set) {
|
|
7107
|
+
return items.some((i) => set.has(i));
|
|
7108
|
+
}
|
|
7109
|
+
function classifyProject(stack) {
|
|
7110
|
+
let type;
|
|
7111
|
+
let confidence;
|
|
7112
|
+
if (stack.isMonorepo) {
|
|
7113
|
+
type = "monorepo";
|
|
7114
|
+
confidence = 0.9;
|
|
7115
|
+
} else if (hasAny(stack.frameworks, /* @__PURE__ */ new Set(["flutter"])) || stack.languages.includes("dart")) {
|
|
7116
|
+
type = "mobile";
|
|
7117
|
+
confidence = 0.9;
|
|
7118
|
+
} else if (hasAny(stack.frameworks, FULLSTACK_FRAMEWORKS) && stack.databases.length > 0) {
|
|
7119
|
+
type = "web-fullstack";
|
|
7120
|
+
confidence = 0.9;
|
|
7121
|
+
} else if (hasAny(stack.frameworks, BACKEND_FRAMEWORKS)) {
|
|
7122
|
+
type = "api-backend";
|
|
7123
|
+
confidence = 0.9;
|
|
7124
|
+
} else if (hasAny(stack.frameworks, FRONTEND_FRAMEWORKS)) {
|
|
7125
|
+
type = "web-frontend";
|
|
7126
|
+
confidence = 0.85;
|
|
7127
|
+
} else if (stack.languages.includes("python") && !hasAny(stack.frameworks, WEB_FRAMEWORKS)) {
|
|
7128
|
+
if (hasAny(stack.frameworks, ML_FRAMEWORKS)) {
|
|
7129
|
+
type = "ml-data";
|
|
7130
|
+
confidence = 0.8;
|
|
7131
|
+
} else {
|
|
7132
|
+
type = "cli-tool";
|
|
7133
|
+
confidence = 0.6;
|
|
7134
|
+
}
|
|
7135
|
+
} else if (stack.languages.length > 0 && stack.frameworks.length === 0) {
|
|
7136
|
+
type = "library";
|
|
7137
|
+
confidence = 0.6;
|
|
7138
|
+
} else if (stack.languages.length === 0 && stack.frameworks.length === 0) {
|
|
7139
|
+
type = "unknown";
|
|
7140
|
+
confidence = 0.3;
|
|
7141
|
+
} else {
|
|
7142
|
+
type = "unknown";
|
|
7143
|
+
confidence = 0.3;
|
|
7144
|
+
}
|
|
7145
|
+
return {
|
|
7146
|
+
type,
|
|
7147
|
+
confidence,
|
|
7148
|
+
suggestedTemplate: TEMPLATE_MAP[type],
|
|
7149
|
+
suggestedProfiles: PROFILE_MAP[type],
|
|
7150
|
+
description: DESCRIPTION_MAP[type]
|
|
7151
|
+
};
|
|
7152
|
+
}
|
|
6114
7153
|
|
|
6115
7154
|
// src/orchestrator/smart-orchestrate.ts
|
|
6116
7155
|
init_stack_detector();
|
|
@@ -6119,24 +7158,130 @@ init_stack_detector();
|
|
|
6119
7158
|
import fs18 from "fs";
|
|
6120
7159
|
import path18 from "path";
|
|
6121
7160
|
import os15 from "os";
|
|
7161
|
+
function isProfileInstalled(profileName, profilesDir) {
|
|
7162
|
+
return fs18.existsSync(path18.join(profilesDir, profileName, "core.md"));
|
|
7163
|
+
}
|
|
7164
|
+
function installProfile(profileName, profilesDir) {
|
|
7165
|
+
const profile = getOrchestratorProfile(profileName);
|
|
7166
|
+
if (!profile) return false;
|
|
7167
|
+
const profileDir = path18.join(profilesDir, profileName);
|
|
7168
|
+
fs18.mkdirSync(profileDir, { recursive: true });
|
|
7169
|
+
fs18.writeFileSync(path18.join(profileDir, "core.md"), profile.core, "utf-8");
|
|
7170
|
+
if (profile.rules) {
|
|
7171
|
+
fs18.writeFileSync(path18.join(profileDir, "rules.md"), profile.rules, "utf-8");
|
|
7172
|
+
}
|
|
7173
|
+
return true;
|
|
7174
|
+
}
|
|
7175
|
+
function ensureAllProfilesInstalled(profilesDir) {
|
|
7176
|
+
const installed = [];
|
|
7177
|
+
const skipped = [];
|
|
7178
|
+
for (const profile of ORCHESTRATOR_PROFILES) {
|
|
7179
|
+
if (isProfileInstalled(profile.name, profilesDir)) {
|
|
7180
|
+
skipped.push(profile.name);
|
|
7181
|
+
} else {
|
|
7182
|
+
installProfile(profile.name, profilesDir);
|
|
7183
|
+
installed.push(profile.name);
|
|
7184
|
+
}
|
|
7185
|
+
}
|
|
7186
|
+
return { installed, skipped };
|
|
7187
|
+
}
|
|
7188
|
+
function getProfilesDir() {
|
|
7189
|
+
const acoreHome = process.env.ACORE_HOME;
|
|
7190
|
+
if (acoreHome) {
|
|
7191
|
+
return path18.join(acoreHome, "profiles");
|
|
7192
|
+
}
|
|
7193
|
+
return path18.join(os15.homedir(), ".acore", "profiles");
|
|
7194
|
+
}
|
|
6122
7195
|
|
|
6123
|
-
// src/orchestrator/
|
|
6124
|
-
init_dag();
|
|
7196
|
+
// src/orchestrator/smart-orchestrate.ts
|
|
6125
7197
|
function formatDAGForDisplay(dag) {
|
|
6126
7198
|
const lines = [];
|
|
6127
7199
|
lines.push(`## ${dag.name}`);
|
|
6128
7200
|
lines.push(`**Goal:** ${dag.goal}`);
|
|
6129
7201
|
lines.push(`**Tasks:** ${dag.nodes.length} | **Gates:** ${dag.gates.length}`);
|
|
6130
7202
|
lines.push("");
|
|
6131
|
-
for (const
|
|
6132
|
-
const depLabel =
|
|
6133
|
-
lines.push(`- **${
|
|
7203
|
+
for (const node2 of dag.nodes) {
|
|
7204
|
+
const depLabel = node2.dependencies.length === 0 ? "(root)" : `(after: ${node2.dependencies.join(", ")})`;
|
|
7205
|
+
lines.push(`- **${node2.name}** \u2192 ${node2.profile} [${node2.tier}] ${depLabel}`);
|
|
6134
7206
|
}
|
|
6135
7207
|
for (const gate of dag.gates) {
|
|
6136
7208
|
lines.push(`- \u{1F512} **${gate.name}** [${gate.type}]`);
|
|
6137
7209
|
}
|
|
6138
7210
|
return lines.join("\n");
|
|
6139
7211
|
}
|
|
7212
|
+
async function smartOrchestrate(options) {
|
|
7213
|
+
ensureAllProfilesInstalled(getProfilesDir());
|
|
7214
|
+
let projectType;
|
|
7215
|
+
let templateName = options.templateName;
|
|
7216
|
+
if (options.projectPath && !templateName) {
|
|
7217
|
+
const stack = scanStack(options.projectPath);
|
|
7218
|
+
const classification = classifyProject(stack);
|
|
7219
|
+
projectType = classification.type;
|
|
7220
|
+
templateName = classification.suggestedTemplate;
|
|
7221
|
+
}
|
|
7222
|
+
let dag;
|
|
7223
|
+
if (templateName) {
|
|
7224
|
+
const templateFn = getTemplate(templateName);
|
|
7225
|
+
if (templateFn) {
|
|
7226
|
+
dag = templateFn({ name: "Orchestration", goal: options.requirement });
|
|
7227
|
+
} else {
|
|
7228
|
+
dag = await decomposeRequirement(options.requirement, options.client);
|
|
7229
|
+
templateName = void 0;
|
|
7230
|
+
}
|
|
7231
|
+
} else {
|
|
7232
|
+
dag = await decomposeRequirement(options.requirement, options.client);
|
|
7233
|
+
}
|
|
7234
|
+
const orchestration = await runOrchestrationFull(dag, {
|
|
7235
|
+
router: options.router,
|
|
7236
|
+
enablePolicyCheck: options.enablePolicyCheck,
|
|
7237
|
+
enableSelfReview: options.enableSelfReview,
|
|
7238
|
+
enableCostTracking: options.enableCostTracking,
|
|
7239
|
+
budgetLimit: options.budgetLimit,
|
|
7240
|
+
callbacks: options.callbacks
|
|
7241
|
+
});
|
|
7242
|
+
const summary = formatSmartResult({
|
|
7243
|
+
dag,
|
|
7244
|
+
projectType,
|
|
7245
|
+
templateUsed: templateName,
|
|
7246
|
+
orchestration,
|
|
7247
|
+
summary: ""
|
|
7248
|
+
});
|
|
7249
|
+
return { dag, projectType, templateUsed: templateName, orchestration, summary };
|
|
7250
|
+
}
|
|
7251
|
+
function formatSmartResult(result) {
|
|
7252
|
+
const lines = [];
|
|
7253
|
+
if (result.projectType) {
|
|
7254
|
+
lines.push(`Project type: ${result.projectType}`);
|
|
7255
|
+
}
|
|
7256
|
+
if (result.templateUsed) {
|
|
7257
|
+
lines.push(`Template: ${result.templateUsed}`);
|
|
7258
|
+
}
|
|
7259
|
+
lines.push("");
|
|
7260
|
+
lines.push(formatDAGForDisplay(result.dag));
|
|
7261
|
+
lines.push("");
|
|
7262
|
+
const orch = result.orchestration;
|
|
7263
|
+
lines.push(
|
|
7264
|
+
`Status: ${orch.success ? "completed" : "failed"} (${orch.durationMs}ms)`
|
|
7265
|
+
);
|
|
7266
|
+
if (orch.policy && !orch.policy.passed) {
|
|
7267
|
+
const errorCount = orch.policy.violations.filter(
|
|
7268
|
+
(v) => v.severity === "error"
|
|
7269
|
+
).length;
|
|
7270
|
+
lines.push(
|
|
7271
|
+
`Policy: FAILED \u2014 ${errorCount} error${errorCount !== 1 ? "s" : ""}`
|
|
7272
|
+
);
|
|
7273
|
+
}
|
|
7274
|
+
if (orch.review) {
|
|
7275
|
+
lines.push(`Review: ${orch.review.passed ? "passed" : "failed"}`);
|
|
7276
|
+
}
|
|
7277
|
+
if (orch.costSummary) {
|
|
7278
|
+
lines.push(`Cost: ${orch.costSummary}`);
|
|
7279
|
+
}
|
|
7280
|
+
return lines.join("\n");
|
|
7281
|
+
}
|
|
7282
|
+
|
|
7283
|
+
// src/orchestrator/index.ts
|
|
7284
|
+
init_dag();
|
|
6140
7285
|
|
|
6141
7286
|
// src/commands.ts
|
|
6142
7287
|
init_registry();
|
|
@@ -8043,7 +9188,7 @@ function handleReset(action) {
|
|
|
8043
9188
|
function handleUpdate() {
|
|
8044
9189
|
try {
|
|
8045
9190
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
8046
|
-
const local = true ? "0.
|
|
9191
|
+
const local = true ? "0.41.0" : "unknown";
|
|
8047
9192
|
if (current === local) {
|
|
8048
9193
|
return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
|
|
8049
9194
|
}
|
|
@@ -8862,21 +10007,57 @@ async function handleOrchestrateCommand(action, args, ctx) {
|
|
|
8862
10007
|
if (!action) {
|
|
8863
10008
|
return {
|
|
8864
10009
|
handled: true,
|
|
8865
|
-
output:
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
10010
|
+
output: [
|
|
10011
|
+
"Usage: /orchestrate <requirement>",
|
|
10012
|
+
"",
|
|
10013
|
+
"Decomposes a requirement into a task DAG and executes it with parallel agents.",
|
|
10014
|
+
"Auto-detects project type, selects template, runs policy check, and tracks cost.",
|
|
10015
|
+
"",
|
|
10016
|
+
"Options (pass as first arg):",
|
|
10017
|
+
" --template <name> Force a template (full-feature, bug-fix, security-audit)",
|
|
10018
|
+
" --no-review Skip self-review loop",
|
|
10019
|
+
" --no-policy Skip policy check",
|
|
10020
|
+
"",
|
|
10021
|
+
"Alias: /orch"
|
|
10022
|
+
].join("\n")
|
|
8870
10023
|
};
|
|
8871
10024
|
}
|
|
8872
|
-
const requirement = [action, ...args].join(" ");
|
|
8873
10025
|
if (!ctx.llmClient) {
|
|
8874
10026
|
return { handled: true, output: pc6.red("Orchestration requires an LLM client. Not available.") };
|
|
8875
10027
|
}
|
|
10028
|
+
let templateName;
|
|
10029
|
+
let enableSelfReview = true;
|
|
10030
|
+
let enablePolicyCheck = true;
|
|
10031
|
+
const filtered = [];
|
|
10032
|
+
const allArgs = [action, ...args];
|
|
10033
|
+
for (let i = 0; i < allArgs.length; i++) {
|
|
10034
|
+
if (allArgs[i] === "--template" && allArgs[i + 1]) {
|
|
10035
|
+
templateName = allArgs[++i];
|
|
10036
|
+
} else if (allArgs[i] === "--no-review") {
|
|
10037
|
+
enableSelfReview = false;
|
|
10038
|
+
} else if (allArgs[i] === "--no-policy") {
|
|
10039
|
+
enablePolicyCheck = false;
|
|
10040
|
+
} else {
|
|
10041
|
+
filtered.push(allArgs[i]);
|
|
10042
|
+
}
|
|
10043
|
+
}
|
|
10044
|
+
const requirement = filtered.join(" ");
|
|
10045
|
+
if (!requirement.trim()) {
|
|
10046
|
+
return { handled: true, output: pc6.red("Please provide a requirement to orchestrate.") };
|
|
10047
|
+
}
|
|
8876
10048
|
try {
|
|
8877
|
-
const
|
|
8878
|
-
const
|
|
8879
|
-
|
|
10049
|
+
const router = createModelRouter({ standard: ctx.llmClient });
|
|
10050
|
+
const result = await smartOrchestrate({
|
|
10051
|
+
requirement,
|
|
10052
|
+
client: ctx.llmClient,
|
|
10053
|
+
router,
|
|
10054
|
+
projectPath: process.cwd(),
|
|
10055
|
+
templateName,
|
|
10056
|
+
enablePolicyCheck,
|
|
10057
|
+
enableSelfReview,
|
|
10058
|
+
enableCostTracking: true
|
|
10059
|
+
});
|
|
10060
|
+
return { handled: true, output: result.summary };
|
|
8880
10061
|
} catch (err) {
|
|
8881
10062
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8882
10063
|
return { handled: true, output: pc6.red(`Orchestration failed: ${msg}`) };
|
|
@@ -8931,11 +10112,22 @@ async function handleGitHubCommand(action, args, ctx) {
|
|
|
8931
10112
|
try {
|
|
8932
10113
|
const issue = await fetchIssue(issueNum);
|
|
8933
10114
|
const requirement = formatIssueAsRequirement(issue);
|
|
8934
|
-
const
|
|
8935
|
-
const
|
|
8936
|
-
|
|
10115
|
+
const router = createModelRouter({ standard: ctx.llmClient });
|
|
10116
|
+
const result = await smartOrchestrate({
|
|
10117
|
+
requirement,
|
|
10118
|
+
client: ctx.llmClient,
|
|
10119
|
+
router,
|
|
10120
|
+
projectPath: process.cwd(),
|
|
10121
|
+
enablePolicyCheck: true,
|
|
10122
|
+
enableSelfReview: false,
|
|
10123
|
+
enableCostTracking: true
|
|
10124
|
+
});
|
|
10125
|
+
return {
|
|
10126
|
+
handled: true,
|
|
10127
|
+
output: `${pc6.bold(`Plan for #${issue.number}: ${issue.title}`)}
|
|
8937
10128
|
|
|
8938
|
-
${
|
|
10129
|
+
${result.summary}`
|
|
10130
|
+
};
|
|
8939
10131
|
} catch (err) {
|
|
8940
10132
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8941
10133
|
return { handled: true, output: pc6.red(`Failed to plan issue #${issueNum}: ${msg}`) };
|
|
@@ -11150,7 +12342,7 @@ var Inbox = class {
|
|
|
11150
12342
|
// package.json
|
|
11151
12343
|
var package_default = {
|
|
11152
12344
|
name: "@aman_asmuei/aman-agent",
|
|
11153
|
-
version: "0.
|
|
12345
|
+
version: "0.41.0",
|
|
11154
12346
|
description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
|
|
11155
12347
|
type: "module",
|
|
11156
12348
|
engines: {
|
|
@@ -11517,7 +12709,7 @@ function bootstrapEcosystem() {
|
|
|
11517
12709
|
return true;
|
|
11518
12710
|
}
|
|
11519
12711
|
var program = new Command();
|
|
11520
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
12712
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.41.0").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
|
|
11521
12713
|
p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
|
|
11522
12714
|
let config = loadConfig();
|
|
11523
12715
|
if (!config) {
|