@corbat-tech/coco 2.37.0 → 2.39.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/dist/cli/index.js CHANGED
@@ -5746,12 +5746,12 @@ var init_openai = __esm({
5746
5746
  ...reasoningEffort && { reasoning_effort: reasoningEffort }
5747
5747
  });
5748
5748
  let streamStopReason;
5749
- for await (const chunk of stream) {
5750
- const delta = chunk.choices[0]?.delta;
5749
+ for await (const chunk2 of stream) {
5750
+ const delta = chunk2.choices[0]?.delta;
5751
5751
  if (delta?.content) {
5752
5752
  yield { type: "text", text: delta.content };
5753
5753
  }
5754
- const finishReason = chunk.choices[0]?.finish_reason;
5754
+ const finishReason = chunk2.choices[0]?.finish_reason;
5755
5755
  if (finishReason) {
5756
5756
  streamStopReason = this.mapFinishReason(finishReason);
5757
5757
  }
@@ -5820,8 +5820,8 @@ var init_openai = __esm({
5820
5820
  });
5821
5821
  try {
5822
5822
  let streamStopReason;
5823
- for await (const chunk of stream) {
5824
- const delta = chunk.choices[0]?.delta;
5823
+ for await (const chunk2 of stream) {
5824
+ const delta = chunk2.choices[0]?.delta;
5825
5825
  if (delta?.content || delta?.tool_calls) {
5826
5826
  lastActivityTime = Date.now();
5827
5827
  }
@@ -5859,7 +5859,7 @@ var init_openai = __esm({
5859
5859
  }
5860
5860
  }
5861
5861
  }
5862
- const finishReason = chunk.choices[0]?.finish_reason;
5862
+ const finishReason = chunk2.choices[0]?.finish_reason;
5863
5863
  if (finishReason) {
5864
5864
  streamStopReason = this.mapFinishReason(finishReason);
5865
5865
  }
@@ -7591,12 +7591,12 @@ var init_gemini = __esm({
7591
7591
  config: this.buildConfig(messages, options)
7592
7592
  });
7593
7593
  let streamStopReason = "end_turn";
7594
- for await (const chunk of stream) {
7595
- const text16 = chunk.text;
7594
+ for await (const chunk2 of stream) {
7595
+ const text16 = chunk2.text;
7596
7596
  if (text16) {
7597
7597
  yield { type: "text", text: text16 };
7598
7598
  }
7599
- const finishReason = chunk.candidates?.[0]?.finishReason;
7599
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
7600
7600
  if (finishReason) {
7601
7601
  streamStopReason = this.mapFinishReason(finishReason);
7602
7602
  }
@@ -7617,12 +7617,12 @@ var init_gemini = __esm({
7617
7617
  let streamStopReason = "end_turn";
7618
7618
  let fallbackToolCounter = 0;
7619
7619
  const emittedToolIds = /* @__PURE__ */ new Set();
7620
- for await (const chunk of stream) {
7621
- const text16 = chunk.text;
7620
+ for await (const chunk2 of stream) {
7621
+ const text16 = chunk2.text;
7622
7622
  if (text16) {
7623
7623
  yield { type: "text", text: text16 };
7624
7624
  }
7625
- const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
7625
+ const toolCalls = this.extractToolCalls(chunk2, { includeLegacyFunctionCalls: true });
7626
7626
  for (const toolCall of toolCalls) {
7627
7627
  const toolCallId = toolCall.id ?? `gemini_call_${++fallbackToolCounter}`;
7628
7628
  if (emittedToolIds.has(toolCallId)) continue;
@@ -7643,7 +7643,7 @@ var init_gemini = __esm({
7643
7643
  toolCall: normalizedToolCall
7644
7644
  };
7645
7645
  }
7646
- const finishReason = chunk.candidates?.[0]?.finishReason;
7646
+ const finishReason = chunk2.candidates?.[0]?.finishReason;
7647
7647
  if (toolCalls.length > 0) {
7648
7648
  streamStopReason = "tool_use";
7649
7649
  } else if (finishReason) {
@@ -8000,8 +8000,8 @@ var init_vertex = __esm({
8000
8000
  this.ensureInitialized();
8001
8001
  const stream = await this.streamGenerateContent(messages, options);
8002
8002
  let stopReason = "end_turn";
8003
- for await (const chunk of stream) {
8004
- const candidate = chunk.candidates?.[0];
8003
+ for await (const chunk2 of stream) {
8004
+ const candidate = chunk2.candidates?.[0];
8005
8005
  const parts = candidate?.content?.parts ?? [];
8006
8006
  for (const part of parts) {
8007
8007
  if (part.text) {
@@ -8023,8 +8023,8 @@ var init_vertex = __esm({
8023
8023
  let stopReason = "end_turn";
8024
8024
  let streamToolCallCounter = 0;
8025
8025
  const emittedToolFingerprints = /* @__PURE__ */ new Set();
8026
- for await (const chunk of stream) {
8027
- const candidate = chunk.candidates?.[0];
8026
+ for await (const chunk2 of stream) {
8027
+ const candidate = chunk2.candidates?.[0];
8028
8028
  const parts = candidate?.content?.parts ?? [];
8029
8029
  for (const part of parts) {
8030
8030
  if (part.text) {
@@ -8711,8 +8711,8 @@ var init_fallback = __esm({
8711
8711
  continue;
8712
8712
  }
8713
8713
  try {
8714
- for await (const chunk of provider.stream(messages, options)) {
8715
- yield chunk;
8714
+ for await (const chunk2 of provider.stream(messages, options)) {
8715
+ yield chunk2;
8716
8716
  }
8717
8717
  breaker.recordSuccess();
8718
8718
  return;
@@ -8735,8 +8735,8 @@ var init_fallback = __esm({
8735
8735
  continue;
8736
8736
  }
8737
8737
  try {
8738
- for await (const chunk of provider.streamWithTools(messages, options)) {
8739
- yield chunk;
8738
+ for await (const chunk2 of provider.streamWithTools(messages, options)) {
8739
+ yield chunk2;
8740
8740
  }
8741
8741
  breaker.recordSuccess();
8742
8742
  return;
@@ -9005,9 +9005,9 @@ var init_resilient = __esm({
9005
9005
  }
9006
9006
  let emittedChunk = false;
9007
9007
  try {
9008
- for await (const chunk of createStream()) {
9008
+ for await (const chunk2 of createStream()) {
9009
9009
  emittedChunk = true;
9010
- yield chunk;
9010
+ yield chunk2;
9011
9011
  }
9012
9012
  this.breaker.recordSuccess();
9013
9013
  return;
@@ -15516,25 +15516,25 @@ var init_complexity = __esm({
15516
15516
  const lines = content.split("\n");
15517
15517
  totalLines += lines.length;
15518
15518
  for (let i = 0; i <= lines.length - this.minLines; i++) {
15519
- const chunk = lines.slice(i, i + this.minLines).join("\n").trim();
15520
- if (chunk.length < 20) continue;
15521
- if (!chunks.has(chunk)) {
15522
- chunks.set(chunk, []);
15519
+ const chunk2 = lines.slice(i, i + this.minLines).join("\n").trim();
15520
+ if (chunk2.length < 20) continue;
15521
+ if (!chunks.has(chunk2)) {
15522
+ chunks.set(chunk2, []);
15523
15523
  }
15524
- chunks.get(chunk).push({ file, line: i + 1 });
15524
+ chunks.get(chunk2).push({ file, line: i + 1 });
15525
15525
  }
15526
15526
  } catch {
15527
15527
  }
15528
15528
  }
15529
15529
  const duplicates = [];
15530
15530
  let duplicateLines = 0;
15531
- for (const [chunk, locations] of chunks.entries()) {
15531
+ for (const [chunk2, locations] of chunks.entries()) {
15532
15532
  if (locations.length > 1) {
15533
15533
  duplicates.push({
15534
- lines: chunk.split("\n"),
15534
+ lines: chunk2.split("\n"),
15535
15535
  files: locations
15536
15536
  });
15537
- duplicateLines += chunk.split("\n").length * (locations.length - 1);
15537
+ duplicateLines += chunk2.split("\n").length * (locations.length - 1);
15538
15538
  }
15539
15539
  }
15540
15540
  const percentage = totalLines > 0 ? duplicateLines / totalLines * 100 : 0;
@@ -20749,14 +20749,14 @@ ${message}
20749
20749
  const subprocess = execa(command, options);
20750
20750
  let stdoutBuffer = "";
20751
20751
  let stderrBuffer = "";
20752
- subprocess.stdout?.on("data", (chunk) => {
20753
- const text16 = chunk.toString();
20752
+ subprocess.stdout?.on("data", (chunk2) => {
20753
+ const text16 = chunk2.toString();
20754
20754
  stdoutBuffer += text16;
20755
20755
  process.stdout.write(text16);
20756
20756
  heartbeat.activity();
20757
20757
  });
20758
- subprocess.stderr?.on("data", (chunk) => {
20759
- const text16 = chunk.toString();
20758
+ subprocess.stderr?.on("data", (chunk2) => {
20759
+ const text16 = chunk2.toString();
20760
20760
  stderrBuffer += text16;
20761
20761
  process.stderr.write(text16);
20762
20762
  heartbeat.activity();
@@ -43226,6 +43226,562 @@ Response format (JSON only, no prose):
43226
43226
  p26.outro(" Spec saved \u2014 starting sprints");
43227
43227
  return spec;
43228
43228
  }
43229
+ var LEGACY_ROLE_MAPPINGS = [
43230
+ { legacy: "explore", role: "researcher", reason: "read-only codebase exploration" },
43231
+ { legacy: "researcher", role: "researcher", reason: "legacy executor role" },
43232
+ { legacy: "plan", role: "planner", reason: "task planning" },
43233
+ { legacy: "planner", role: "planner", reason: "legacy executor role" },
43234
+ { legacy: "architect", role: "architect", reason: "architecture design" },
43235
+ { legacy: "editor", role: "editor", reason: "implementation edits" },
43236
+ { legacy: "debug", role: "coder", reason: "debugging maps to coding capability" },
43237
+ { legacy: "coder", role: "coder", reason: "legacy executor role" },
43238
+ { legacy: "test", role: "tester", reason: "test authoring/execution" },
43239
+ { legacy: "tester", role: "tester", reason: "legacy executor role" },
43240
+ { legacy: "tdd", role: "tester", reason: "test-first implementation" },
43241
+ { legacy: "e2e", role: "tester", reason: "end-to-end testing" },
43242
+ { legacy: "review", role: "reviewer", reason: "code review" },
43243
+ { legacy: "reviewer", role: "reviewer", reason: "legacy executor role" },
43244
+ { legacy: "refactor", role: "optimizer", reason: "structure optimization" },
43245
+ { legacy: "optimizer", role: "optimizer", reason: "legacy executor role" },
43246
+ { legacy: "security", role: "security", reason: "security analysis" },
43247
+ { legacy: "qa", role: "qa", reason: "quality assurance" },
43248
+ { legacy: "integrator", role: "integrator", reason: "integration coordination" },
43249
+ { legacy: "pm", role: "pm", reason: "product/project coordination" },
43250
+ { legacy: "docs", role: "docs", reason: "documentation" },
43251
+ { legacy: "database", role: "database", reason: "database work" }
43252
+ ];
43253
+ var LEGACY_ROLE_MAP = new Map(LEGACY_ROLE_MAPPINGS.map((mapping) => [mapping.legacy, mapping]));
43254
+ function mapLegacyAgentRole(legacyRole, fallback = "coder") {
43255
+ return LEGACY_ROLE_MAP.get(legacyRole)?.role ?? fallback;
43256
+ }
43257
+ function assertProvenance(provenance) {
43258
+ if (!provenance.workflowRunId) {
43259
+ throw new Error("Shared workspace writes require workflowRunId provenance.");
43260
+ }
43261
+ }
43262
+ function snapshotFromRecords(records, role) {
43263
+ const includeSensitive = role === void 0 || role === "security" || role === "integrator" || role === "pm";
43264
+ const facts = /* @__PURE__ */ new Map();
43265
+ const decisions = /* @__PURE__ */ new Map();
43266
+ const risks = /* @__PURE__ */ new Map();
43267
+ const files = /* @__PURE__ */ new Map();
43268
+ const testResults = /* @__PURE__ */ new Map();
43269
+ const artifacts = [];
43270
+ for (const record of records) {
43271
+ if (!includeSensitive && (record.kind === "risk" || record.provenance.risk === "secrets-sensitive")) {
43272
+ continue;
43273
+ }
43274
+ switch (record.kind) {
43275
+ case "fact":
43276
+ facts.set(record.key, record.value);
43277
+ break;
43278
+ case "decision":
43279
+ decisions.set(record.key, record.value);
43280
+ break;
43281
+ case "risk":
43282
+ risks.set(record.key, record.value);
43283
+ break;
43284
+ case "file":
43285
+ files.set(record.key, record.value);
43286
+ break;
43287
+ case "testResult":
43288
+ testResults.set(record.key, record.value);
43289
+ break;
43290
+ case "artifact":
43291
+ if (isAgentArtifact(record.value)) {
43292
+ if (includeSensitive || record.value.kind !== "riskReport") {
43293
+ artifacts.push(cloneArtifact(record.value));
43294
+ }
43295
+ }
43296
+ break;
43297
+ }
43298
+ }
43299
+ return {
43300
+ facts: Object.fromEntries(facts),
43301
+ decisions: Object.fromEntries(decisions),
43302
+ risks: Object.fromEntries(risks),
43303
+ files: Object.fromEntries(files),
43304
+ testResults: Object.fromEntries(testResults),
43305
+ artifacts
43306
+ };
43307
+ }
43308
+ var InMemorySharedWorkspaceStore = class {
43309
+ records = [];
43310
+ write(input) {
43311
+ assertProvenance(input.provenance);
43312
+ const record = {
43313
+ id: `state-${randomUUID()}`,
43314
+ kind: input.kind,
43315
+ key: input.key,
43316
+ value: cloneUnknown(input.value),
43317
+ provenance: { ...input.provenance },
43318
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
43319
+ };
43320
+ this.records.push(record);
43321
+ return cloneRecord(record);
43322
+ }
43323
+ list() {
43324
+ return this.records.map(cloneRecord);
43325
+ }
43326
+ snapshot() {
43327
+ return snapshotFromRecords(this.records);
43328
+ }
43329
+ readForRole(role) {
43330
+ return snapshotFromRecords(this.records, role);
43331
+ }
43332
+ clear() {
43333
+ this.records = [];
43334
+ }
43335
+ };
43336
+ function createAgentTraceContext(input = {}) {
43337
+ return {
43338
+ traceId: input.traceId ?? `trace-${randomUUID()}`,
43339
+ spanId: input.spanId ?? `span-${randomUUID()}`,
43340
+ parentSpanId: input.parentSpanId,
43341
+ workflowRunId: input.workflowRunId,
43342
+ agentRunId: input.agentRunId,
43343
+ taskId: input.taskId,
43344
+ toolCallId: input.toolCallId
43345
+ };
43346
+ }
43347
+ var AgentGraphEngine = class {
43348
+ eventLog;
43349
+ sharedState;
43350
+ nodeExecutor;
43351
+ gateEvaluator;
43352
+ trace;
43353
+ constructor(options = {}) {
43354
+ this.eventLog = options.eventLog;
43355
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
43356
+ this.nodeExecutor = options.nodeExecutor ?? defaultAgentGraphNodeExecutor;
43357
+ this.gateEvaluator = options.gateEvaluator ?? defaultAgentGateEvaluator;
43358
+ this.trace = options.trace ?? createAgentTraceContext();
43359
+ }
43360
+ async run(input) {
43361
+ const validation = validateAgentGraph(input.graph);
43362
+ if (!validation.valid) {
43363
+ throw new Error(
43364
+ `Invalid agent graph: ${validation.issues.map((issue) => issue.message).join("; ")}`
43365
+ );
43366
+ }
43367
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43368
+ const nodeResults = /* @__PURE__ */ new Map();
43369
+ const artifacts = [];
43370
+ const graphTrace = createAgentTraceContext({
43371
+ ...this.trace,
43372
+ workflowRunId: input.workflowRunId
43373
+ });
43374
+ this.eventLog?.record("agent.graph.started", {
43375
+ workflowRunId: input.workflowRunId,
43376
+ trace: graphTrace,
43377
+ levels: validation.levels
43378
+ });
43379
+ try {
43380
+ for (const level of validation.levels) {
43381
+ const batches = chunk(level, input.graph.parallelism ?? level.length);
43382
+ for (const batch of batches) {
43383
+ const levelResults = await Promise.all(
43384
+ batch.map(
43385
+ (nodeId) => this.executeNode({
43386
+ node: input.graph.nodes.find((candidate) => candidate.id === nodeId),
43387
+ graph: input.graph,
43388
+ workflowRunId: input.workflowRunId,
43389
+ input: input.input,
43390
+ graphTrace,
43391
+ nodeResults
43392
+ })
43393
+ )
43394
+ );
43395
+ for (const result2 of levelResults) {
43396
+ nodeResults.set(result2.taskId, result2);
43397
+ artifacts.push(...result2.artifacts.map(cloneArtifact));
43398
+ }
43399
+ }
43400
+ }
43401
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43402
+ const result = {
43403
+ id: input.workflowRunId,
43404
+ status: "completed",
43405
+ nodeResults: Object.fromEntries(nodeResults),
43406
+ artifacts,
43407
+ stateSnapshot: this.sharedState.snapshot(),
43408
+ trace: graphTrace,
43409
+ startedAt,
43410
+ completedAt
43411
+ };
43412
+ this.eventLog?.record("agent.graph.completed", {
43413
+ workflowRunId: input.workflowRunId,
43414
+ trace: graphTrace,
43415
+ nodeCount: nodeResults.size
43416
+ });
43417
+ return result;
43418
+ } catch (error) {
43419
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
43420
+ const message = error instanceof Error ? error.message : String(error);
43421
+ this.eventLog?.record("agent.graph.failed", {
43422
+ workflowRunId: input.workflowRunId,
43423
+ trace: graphTrace,
43424
+ error: message
43425
+ });
43426
+ return {
43427
+ id: input.workflowRunId,
43428
+ status: "failed",
43429
+ nodeResults: Object.fromEntries(nodeResults),
43430
+ artifacts,
43431
+ stateSnapshot: this.sharedState.snapshot(),
43432
+ trace: graphTrace,
43433
+ startedAt,
43434
+ completedAt,
43435
+ error: message
43436
+ };
43437
+ }
43438
+ }
43439
+ async executeNode(input) {
43440
+ const attempts = input.node.retryPolicy?.maxAttempts ?? 1;
43441
+ let lastResult;
43442
+ for (let attempt = 1; attempt <= attempts; attempt++) {
43443
+ const task = graphNodeToTask(input.node, input.input);
43444
+ const trace = createAgentTraceContext({
43445
+ traceId: input.graphTrace.traceId,
43446
+ parentSpanId: input.graphTrace.spanId,
43447
+ workflowRunId: input.workflowRunId,
43448
+ taskId: task.id
43449
+ });
43450
+ this.eventLog?.record("agent.started", {
43451
+ workflowRunId: input.workflowRunId,
43452
+ nodeId: input.node.id,
43453
+ taskId: task.id,
43454
+ role: task.role,
43455
+ attempt,
43456
+ trace
43457
+ });
43458
+ const result = await this.nodeExecutor({
43459
+ node: input.node,
43460
+ task,
43461
+ attempt,
43462
+ workflowRunId: input.workflowRunId,
43463
+ trace,
43464
+ dependencyResults: input.nodeResults,
43465
+ sharedState: this.sharedState,
43466
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
43467
+ });
43468
+ lastResult = result;
43469
+ for (const artifact of result.artifacts) {
43470
+ this.sharedState.write({
43471
+ kind: "artifact",
43472
+ key: artifact.id,
43473
+ value: artifact,
43474
+ provenance: {
43475
+ workflowRunId: input.workflowRunId,
43476
+ agentRunId: result.id,
43477
+ nodeId: input.node.id,
43478
+ taskId: task.id,
43479
+ risk: input.node.risk
43480
+ }
43481
+ });
43482
+ this.eventLog?.record("agent.artifact.created", {
43483
+ workflowRunId: input.workflowRunId,
43484
+ nodeId: input.node.id,
43485
+ agentRunId: result.id,
43486
+ artifactId: artifact.id,
43487
+ kind: artifact.kind,
43488
+ trace
43489
+ });
43490
+ }
43491
+ if (result.success) {
43492
+ await this.evaluateNodeGates(input.graph, input.node, result, input.workflowRunId, trace);
43493
+ this.eventLog?.record("agent.completed", {
43494
+ workflowRunId: input.workflowRunId,
43495
+ nodeId: input.node.id,
43496
+ agentRunId: result.id,
43497
+ taskId: task.id,
43498
+ role: result.role,
43499
+ attempt,
43500
+ trace
43501
+ });
43502
+ return result;
43503
+ }
43504
+ this.eventLog?.record("agent.failed", {
43505
+ workflowRunId: input.workflowRunId,
43506
+ nodeId: input.node.id,
43507
+ agentRunId: result.id,
43508
+ taskId: task.id,
43509
+ role: result.role,
43510
+ attempt,
43511
+ error: result.error,
43512
+ trace
43513
+ });
43514
+ if (attempt < attempts && input.node.retryPolicy?.backoffMs) {
43515
+ await new Promise((resolve4) => setTimeout(resolve4, input.node.retryPolicy.backoffMs));
43516
+ }
43517
+ }
43518
+ throw new Error(
43519
+ `Node '${input.node.id}' failed after ${attempts} attempt(s): ${lastResult?.error ?? "unknown error"}`
43520
+ );
43521
+ }
43522
+ async evaluateNodeGates(graph, node, result, workflowRunId, trace) {
43523
+ for (const gateId of node.gates ?? []) {
43524
+ const gate = graph.gates?.find((candidate) => candidate.id === gateId);
43525
+ if (!gate) continue;
43526
+ const evaluation = await this.gateEvaluator({
43527
+ gate,
43528
+ node,
43529
+ result,
43530
+ workflowRunId,
43531
+ trace,
43532
+ sharedState: this.sharedState,
43533
+ eventLog: this.eventLog ?? NULL_EVENT_LOG
43534
+ });
43535
+ const eventType = evaluation.passed ? "workflow.gate.passed" : "workflow.gate.failed";
43536
+ this.eventLog?.record(eventType, {
43537
+ workflowRunId,
43538
+ nodeId: node.id,
43539
+ gateId: gate.id,
43540
+ kind: gate.kind,
43541
+ required: gate.required,
43542
+ reason: evaluation.reason,
43543
+ trace
43544
+ });
43545
+ if (!evaluation.passed && gate.required) {
43546
+ throw new Error(
43547
+ `Required gate '${gate.id}' failed for node '${node.id}': ${evaluation.reason ?? "no reason"}`
43548
+ );
43549
+ }
43550
+ }
43551
+ }
43552
+ };
43553
+ function createAgentArtifact(input) {
43554
+ return {
43555
+ ...input,
43556
+ id: input.id ?? `artifact-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
43557
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
43558
+ };
43559
+ }
43560
+ function createSummaryArtifact(output, metadata = {}) {
43561
+ return createAgentArtifact({
43562
+ kind: "summary",
43563
+ content: output,
43564
+ title: metadata.title ?? "Agent summary",
43565
+ agentRunId: metadata.agentRunId,
43566
+ taskId: metadata.taskId
43567
+ });
43568
+ }
43569
+ function normalizeAgentRunResult(input) {
43570
+ const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
43571
+ const startedAt = input.startedAt ?? completedAt;
43572
+ const status = input.status ?? (input.success ? "completed" : "failed");
43573
+ const artifacts = input.artifacts && input.artifacts.length > 0 ? input.artifacts.map(cloneArtifact) : [createSummaryArtifact(input.output, { agentRunId: input.id, taskId: input.taskId })];
43574
+ return {
43575
+ id: input.id,
43576
+ taskId: input.taskId,
43577
+ role: input.role,
43578
+ status,
43579
+ success: input.success,
43580
+ output: input.output,
43581
+ artifacts,
43582
+ toolsUsed: [...input.toolsUsed ?? []],
43583
+ turns: input.turns ?? 0,
43584
+ durationMs: input.durationMs ?? 0,
43585
+ usage: input.usage,
43586
+ error: input.error,
43587
+ startedAt,
43588
+ completedAt,
43589
+ metadata: input.metadata
43590
+ };
43591
+ }
43592
+ function validateAgentGraph(graph) {
43593
+ const issues = [];
43594
+ const nodeIds = /* @__PURE__ */ new Set();
43595
+ const gateIds = new Set((graph.gates ?? []).map((gate) => gate.id));
43596
+ if (graph.parallelism !== void 0 && graph.parallelism < 1) {
43597
+ issues.push({
43598
+ code: "invalid-parallelism",
43599
+ message: "Graph parallelism must be greater than zero."
43600
+ });
43601
+ }
43602
+ for (const node of graph.nodes) {
43603
+ if (nodeIds.has(node.id)) {
43604
+ issues.push({
43605
+ code: "duplicate-node",
43606
+ message: `Duplicate graph node '${node.id}'.`,
43607
+ nodeId: node.id
43608
+ });
43609
+ }
43610
+ nodeIds.add(node.id);
43611
+ if (node.retryPolicy && node.retryPolicy.maxAttempts < 1) {
43612
+ issues.push({
43613
+ code: "invalid-retry-policy",
43614
+ message: `Node '${node.id}' retry policy must allow at least one attempt.`,
43615
+ nodeId: node.id
43616
+ });
43617
+ }
43618
+ for (const dep of node.dependsOn ?? []) {
43619
+ if (!nodeIds.has(dep) && !graph.nodes.some((candidate) => candidate.id === dep)) {
43620
+ issues.push({
43621
+ code: "missing-dependency",
43622
+ message: `Node '${node.id}' depends on missing node '${dep}'.`,
43623
+ nodeId: node.id
43624
+ });
43625
+ }
43626
+ }
43627
+ for (const gate of node.gates ?? []) {
43628
+ if (!gateIds.has(gate)) {
43629
+ issues.push({
43630
+ code: "missing-gate",
43631
+ message: `Node '${node.id}' references missing gate '${gate}'.`,
43632
+ nodeId: node.id,
43633
+ gateId: gate
43634
+ });
43635
+ }
43636
+ }
43637
+ }
43638
+ for (const edge of graph.edges ?? []) {
43639
+ if (!nodeIds.has(edge.from)) {
43640
+ issues.push({
43641
+ code: "missing-edge-node",
43642
+ message: `Graph edge references missing source node '${edge.from}'.`,
43643
+ nodeId: edge.from
43644
+ });
43645
+ }
43646
+ if (!nodeIds.has(edge.to)) {
43647
+ issues.push({
43648
+ code: "missing-edge-node",
43649
+ message: `Graph edge references missing target node '${edge.to}'.`,
43650
+ nodeId: edge.to
43651
+ });
43652
+ }
43653
+ }
43654
+ const levels = buildExecutionLevels(graph, issues);
43655
+ return { valid: issues.length === 0, issues, levels };
43656
+ }
43657
+ function buildExecutionLevels(graph, issues) {
43658
+ const dependencies = /* @__PURE__ */ new Map();
43659
+ for (const node of graph.nodes) {
43660
+ dependencies.set(node.id, new Set(node.dependsOn ?? []));
43661
+ }
43662
+ for (const edge of graph.edges ?? []) {
43663
+ if (dependencies.has(edge.to)) {
43664
+ dependencies.get(edge.to).add(edge.from);
43665
+ }
43666
+ }
43667
+ const completed = /* @__PURE__ */ new Set();
43668
+ const levels = [];
43669
+ while (completed.size < dependencies.size) {
43670
+ const level = [...dependencies.entries()].filter(([id, deps]) => !completed.has(id) && [...deps].every((dep) => completed.has(dep))).map(([id]) => id);
43671
+ if (level.length === 0) {
43672
+ const remaining = [...dependencies.keys()].filter((id) => !completed.has(id));
43673
+ issues.push({
43674
+ code: "cycle",
43675
+ message: `Graph contains a cycle involving: ${remaining.join(", ")}.`
43676
+ });
43677
+ return levels;
43678
+ }
43679
+ for (const id of level) completed.add(id);
43680
+ levels.push(level);
43681
+ }
43682
+ return levels;
43683
+ }
43684
+ var NULL_EVENT_LOG = {
43685
+ record(type, data = {}) {
43686
+ return {
43687
+ id: `event-${randomUUID()}`,
43688
+ type,
43689
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
43690
+ data
43691
+ };
43692
+ },
43693
+ list() {
43694
+ return [];
43695
+ },
43696
+ count() {
43697
+ return 0;
43698
+ },
43699
+ clear() {
43700
+ }
43701
+ };
43702
+ function graphNodeToTask(node, workflowInput) {
43703
+ return {
43704
+ id: node.id,
43705
+ role: node.agentRole ?? "coder",
43706
+ objective: node.description,
43707
+ context: {
43708
+ workflowInput,
43709
+ condition: node.condition
43710
+ },
43711
+ dependencies: node.dependsOn,
43712
+ constraints: node.requiredTools?.map((tool) => `Requires tool: ${tool}`)
43713
+ };
43714
+ }
43715
+ async function defaultAgentGraphNodeExecutor(execution) {
43716
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43717
+ const dependencyOutputs = Object.fromEntries(
43718
+ [...execution.dependencyResults.entries()].map(([id, result]) => [
43719
+ id,
43720
+ { success: result.success, output: result.output }
43721
+ ])
43722
+ );
43723
+ const output = [
43724
+ `Node '${execution.node.id}' executed by ${execution.task.role}.`,
43725
+ `Objective: ${execution.task.objective}`,
43726
+ Object.keys(dependencyOutputs).length > 0 ? `Dependencies: ${JSON.stringify(dependencyOutputs)}` : "Dependencies: none"
43727
+ ].join("\n");
43728
+ return normalizeAgentRunResult({
43729
+ id: `${execution.workflowRunId}-${execution.node.id}-attempt-${execution.attempt}`,
43730
+ taskId: execution.task.id,
43731
+ role: execution.task.role,
43732
+ success: true,
43733
+ output,
43734
+ startedAt,
43735
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
43736
+ turns: 0,
43737
+ toolsUsed: [],
43738
+ durationMs: 0,
43739
+ metadata: {
43740
+ workflowRunId: execution.workflowRunId,
43741
+ nodeId: execution.node.id,
43742
+ trace: execution.trace,
43743
+ simulated: true
43744
+ }
43745
+ });
43746
+ }
43747
+ async function defaultAgentGateEvaluator(input) {
43748
+ if (!input.result.success) {
43749
+ return { passed: false, reason: "Agent result was not successful." };
43750
+ }
43751
+ return { passed: true };
43752
+ }
43753
+ function chunk(items, size) {
43754
+ const safeSize = Math.max(1, size);
43755
+ const result = [];
43756
+ for (let index = 0; index < items.length; index += safeSize) {
43757
+ result.push(items.slice(index, index + safeSize));
43758
+ }
43759
+ return result;
43760
+ }
43761
+ function cloneUnknown(value) {
43762
+ if (value === void 0 || value === null) return value;
43763
+ try {
43764
+ return JSON.parse(JSON.stringify(value));
43765
+ } catch {
43766
+ return value;
43767
+ }
43768
+ }
43769
+ function cloneRecord(record) {
43770
+ return {
43771
+ ...record,
43772
+ value: cloneUnknown(record.value),
43773
+ provenance: { ...record.provenance }
43774
+ };
43775
+ }
43776
+ function isAgentArtifact(value) {
43777
+ return typeof value === "object" && value !== null && "id" in value && "kind" in value && "content" in value && "createdAt" in value;
43778
+ }
43779
+ function cloneArtifact(artifact) {
43780
+ return {
43781
+ ...artifact,
43782
+ metadata: artifact.metadata ? { ...artifact.metadata } : void 0
43783
+ };
43784
+ }
43229
43785
 
43230
43786
  // src/agents/executor.ts
43231
43787
  var AgentExecutor = class {
@@ -43240,6 +43796,7 @@ var AgentExecutor = class {
43240
43796
  */
43241
43797
  async execute(agent, task) {
43242
43798
  const startTime = Date.now();
43799
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43243
43800
  const toolsUsed = /* @__PURE__ */ new Set();
43244
43801
  const messages = [
43245
43802
  {
@@ -43250,6 +43807,8 @@ var AgentExecutor = class {
43250
43807
  const agentToolDefs = this.getToolDefinitionsForAgent(agent.allowedTools);
43251
43808
  let turn = 0;
43252
43809
  let totalTokens = 0;
43810
+ let totalInputTokens = 0;
43811
+ let totalOutputTokens = 0;
43253
43812
  while (turn < agent.maxTurns) {
43254
43813
  turn++;
43255
43814
  try {
@@ -43258,16 +43817,23 @@ var AgentExecutor = class {
43258
43817
  system: agent.systemPrompt
43259
43818
  });
43260
43819
  const usage = response.usage;
43820
+ totalInputTokens += usage?.inputTokens || 0;
43821
+ totalOutputTokens += usage?.outputTokens || 0;
43261
43822
  totalTokens += (usage?.inputTokens || 0) + (usage?.outputTokens || 0);
43262
43823
  if (response.stopReason !== "tool_use" || response.toolCalls.length === 0) {
43263
- return {
43824
+ return this.toAgentResult({
43825
+ agent,
43826
+ task,
43264
43827
  output: response.content,
43265
43828
  success: true,
43266
43829
  turns: turn,
43267
43830
  toolsUsed: Array.from(toolsUsed),
43268
43831
  tokensUsed: totalTokens,
43269
- duration: Date.now() - startTime
43270
- };
43832
+ inputTokens: totalInputTokens,
43833
+ outputTokens: totalOutputTokens,
43834
+ duration: Date.now() - startTime,
43835
+ startedAt
43836
+ });
43271
43837
  }
43272
43838
  const assistantContent = [];
43273
43839
  if (response.content) {
@@ -43313,24 +43879,38 @@ var AgentExecutor = class {
43313
43879
  content: toolResults
43314
43880
  });
43315
43881
  } catch (error) {
43316
- return {
43317
- output: `Agent error on turn ${turn}: ${error instanceof Error ? error.message : String(error)}`,
43882
+ const output2 = `Agent error on turn ${turn}: ${error instanceof Error ? error.message : String(error)}`;
43883
+ return this.toAgentResult({
43884
+ agent,
43885
+ task,
43886
+ output: output2,
43318
43887
  success: false,
43319
43888
  turns: turn,
43320
43889
  toolsUsed: Array.from(toolsUsed),
43321
43890
  tokensUsed: totalTokens,
43322
- duration: Date.now() - startTime
43323
- };
43891
+ inputTokens: totalInputTokens,
43892
+ outputTokens: totalOutputTokens,
43893
+ duration: Date.now() - startTime,
43894
+ startedAt,
43895
+ error: output2
43896
+ });
43324
43897
  }
43325
43898
  }
43326
- return {
43327
- output: "Agent reached maximum turns without completing task",
43899
+ const output = "Agent reached maximum turns without completing task";
43900
+ return this.toAgentResult({
43901
+ agent,
43902
+ task,
43903
+ output,
43328
43904
  success: false,
43329
43905
  turns: turn,
43330
43906
  toolsUsed: Array.from(toolsUsed),
43331
43907
  tokensUsed: totalTokens,
43332
- duration: Date.now() - startTime
43333
- };
43908
+ inputTokens: totalInputTokens,
43909
+ outputTokens: totalOutputTokens,
43910
+ duration: Date.now() - startTime,
43911
+ startedAt,
43912
+ error: output
43913
+ });
43334
43914
  }
43335
43915
  /**
43336
43916
  * Build task prompt with context
@@ -43356,7 +43936,36 @@ Complete this task autonomously using the available tools. When done, provide a
43356
43936
  if (allowedToolNames.length === 0) return allDefs;
43357
43937
  return allDefs.filter((def) => allowedToolNames.includes(def.name));
43358
43938
  }
43939
+ toAgentResult(input) {
43940
+ const structuredResult = normalizeAgentRunResult({
43941
+ id: `${input.task.id}-${Date.now().toString(36)}`,
43942
+ taskId: input.task.id,
43943
+ role: normalizeRole(input.agent.role),
43944
+ success: input.success,
43945
+ output: input.output,
43946
+ turns: input.turns,
43947
+ toolsUsed: input.toolsUsed,
43948
+ durationMs: input.duration,
43949
+ startedAt: input.startedAt,
43950
+ usage: { inputTokens: input.inputTokens, outputTokens: input.outputTokens },
43951
+ error: input.error,
43952
+ metadata: { legacyRole: input.agent.role }
43953
+ });
43954
+ return {
43955
+ output: input.output,
43956
+ success: input.success,
43957
+ turns: input.turns,
43958
+ toolsUsed: input.toolsUsed,
43959
+ tokensUsed: input.tokensUsed,
43960
+ duration: input.duration,
43961
+ artifacts: structuredResult.artifacts,
43962
+ structuredResult
43963
+ };
43964
+ }
43359
43965
  };
43966
+ function normalizeRole(role) {
43967
+ return mapLegacyAgentRole(role);
43968
+ }
43360
43969
  var AGENT_ROLES = {
43361
43970
  researcher: {
43362
43971
  role: "researcher",
@@ -44194,6 +44803,9 @@ var testTools = [runTestsTool, getCoverageTool, runTestFileTool];
44194
44803
  // src/tools/index.ts
44195
44804
  init_registry4();
44196
44805
 
44806
+ // src/tools/profiles.ts
44807
+ init_registry4();
44808
+
44197
44809
  // src/tools/file.ts
44198
44810
  init_registry4();
44199
44811
  init_errors();
@@ -45820,11 +46432,15 @@ var AgentManager = class extends EventEmitter {
45820
46432
  failedAgent.status = "failed";
45821
46433
  failedAgent.error = error;
45822
46434
  failedAgent.completedAt = /* @__PURE__ */ new Date();
45823
- return {
46435
+ return this.buildResult({
45824
46436
  agent: failedAgent,
45825
46437
  success: false,
45826
- output: error
45827
- };
46438
+ output: error,
46439
+ turns: 0,
46440
+ toolsUsed: [],
46441
+ startedAt: failedAgent.createdAt.toISOString(),
46442
+ usage: { inputTokens: 0, outputTokens: 0 }
46443
+ });
45828
46444
  }
45829
46445
  const agent = this.createAgent(type, task);
45830
46446
  this.activeAgents.set(agent.id, agent);
@@ -45876,11 +46492,15 @@ var AgentManager = class extends EventEmitter {
45876
46492
  options.onStatusChange?.(agent);
45877
46493
  this.logger.error(`Agent ${agent.id} failed unexpectedly`, { error: errorMessage });
45878
46494
  this.emitEvent("fail", agent);
45879
- return {
46495
+ return this.buildResult({
45880
46496
  agent,
45881
46497
  success: false,
45882
- output: errorMessage
45883
- };
46498
+ output: errorMessage,
46499
+ turns: 0,
46500
+ toolsUsed: [],
46501
+ startedAt: agent.createdAt.toISOString(),
46502
+ usage: { inputTokens: 0, outputTokens: 0 }
46503
+ });
45884
46504
  }
45885
46505
  }
45886
46506
  /**
@@ -46001,6 +46621,8 @@ var AgentManager = class extends EventEmitter {
46001
46621
  let finalOutput = "";
46002
46622
  let iteration = 0;
46003
46623
  const maxTurns = config.maxTurns ?? 10;
46624
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
46625
+ const toolsUsed = /* @__PURE__ */ new Set();
46004
46626
  while (iteration < maxTurns) {
46005
46627
  iteration++;
46006
46628
  if (options.signal?.aborted) {
@@ -46009,12 +46631,15 @@ var AgentManager = class extends EventEmitter {
46009
46631
  agent.completedAt = /* @__PURE__ */ new Date();
46010
46632
  this.moveToCompleted(agent.id);
46011
46633
  options.onStatusChange?.(agent);
46012
- return {
46634
+ return this.buildResult({
46013
46635
  agent,
46014
46636
  success: false,
46015
46637
  output: "Agent execution was aborted",
46638
+ turns: iteration,
46639
+ toolsUsed: Array.from(toolsUsed),
46640
+ startedAt,
46016
46641
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
46017
- };
46642
+ });
46018
46643
  }
46019
46644
  const response = await this.provider.chatWithTools(messages, {
46020
46645
  system: config.systemPrompt,
@@ -46031,7 +46656,7 @@ var AgentManager = class extends EventEmitter {
46031
46656
  messages.push({ role: "assistant", content: response.content });
46032
46657
  break;
46033
46658
  }
46034
- const toolResults = await this.executeToolCalls(response.toolCalls, config);
46659
+ const toolResults = await this.executeToolCalls(response.toolCalls, config, toolsUsed);
46035
46660
  const toolUses = response.toolCalls.map((tc) => ({
46036
46661
  type: "tool_use",
46037
46662
  id: tc.id,
@@ -46055,12 +46680,15 @@ var AgentManager = class extends EventEmitter {
46055
46680
  iterations: iteration,
46056
46681
  outputLength: finalOutput.length
46057
46682
  });
46058
- return {
46683
+ return this.buildResult({
46059
46684
  agent,
46060
46685
  success: true,
46061
46686
  output: finalOutput,
46687
+ turns: iteration,
46688
+ toolsUsed: Array.from(toolsUsed),
46689
+ startedAt,
46062
46690
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
46063
- };
46691
+ });
46064
46692
  }
46065
46693
  /**
46066
46694
  * Get tool definitions filtered for the agent's allowed tools
@@ -46073,10 +46701,11 @@ var AgentManager = class extends EventEmitter {
46073
46701
  /**
46074
46702
  * Execute tool calls and return results
46075
46703
  */
46076
- async executeToolCalls(toolCalls, config) {
46704
+ async executeToolCalls(toolCalls, config, toolsUsed) {
46077
46705
  const results = [];
46078
46706
  const allowedTools = new Set(config.tools);
46079
46707
  for (const toolCall of toolCalls) {
46708
+ toolsUsed.add(toolCall.name);
46080
46709
  if (!allowedTools.has(toolCall.name)) {
46081
46710
  results.push({
46082
46711
  type: "tool_result",
@@ -46117,6 +46746,33 @@ var AgentManager = class extends EventEmitter {
46117
46746
  this.abortControllers.delete(agentId);
46118
46747
  }
46119
46748
  }
46749
+ buildResult(input) {
46750
+ const structuredResult = normalizeAgentRunResult({
46751
+ id: `${input.agent.id}-run`,
46752
+ taskId: input.agent.id,
46753
+ role: agentTypeToRuntimeRole(input.agent.type),
46754
+ success: input.success,
46755
+ output: input.output,
46756
+ turns: input.turns,
46757
+ toolsUsed: input.toolsUsed,
46758
+ usage: input.usage,
46759
+ startedAt: input.startedAt,
46760
+ durationMs: input.agent.completedAt ? input.agent.completedAt.getTime() - input.agent.createdAt.getTime() : 0,
46761
+ status: input.success ? "completed" : "failed",
46762
+ error: input.success ? void 0 : input.agent.error,
46763
+ metadata: { agentType: input.agent.type }
46764
+ });
46765
+ return {
46766
+ agent: input.agent,
46767
+ success: input.success,
46768
+ output: input.output,
46769
+ artifacts: structuredResult.artifacts,
46770
+ structuredResult,
46771
+ toolsUsed: input.toolsUsed,
46772
+ turns: input.turns,
46773
+ usage: input.usage
46774
+ };
46775
+ }
46120
46776
  /**
46121
46777
  * Emit an agent event
46122
46778
  */
@@ -46126,6 +46782,9 @@ var AgentManager = class extends EventEmitter {
46126
46782
  this.emit("agent", event);
46127
46783
  }
46128
46784
  };
46785
+ function agentTypeToRuntimeRole(type) {
46786
+ return mapLegacyAgentRole(type);
46787
+ }
46129
46788
 
46130
46789
  // src/agents/provider-bridge.ts
46131
46790
  var agentProvider = null;
@@ -46170,7 +46829,7 @@ var AGENT_TYPES = [
46170
46829
  "docs",
46171
46830
  "database"
46172
46831
  ];
46173
- var LEGACY_ROLE_MAP = {
46832
+ var LEGACY_ROLE_MAP2 = {
46174
46833
  researcher: "explore",
46175
46834
  coder: "debug",
46176
46835
  // "debug" has write + bash + read — closest to general coding
@@ -46190,7 +46849,7 @@ var SpawnSimpleAgentSchema = z.object({
46190
46849
  });
46191
46850
  function resolveAgentType(input) {
46192
46851
  if (input.type) return input.type;
46193
- if (input.role && input.role in LEGACY_ROLE_MAP) return LEGACY_ROLE_MAP[input.role];
46852
+ if (input.role && input.role in LEGACY_ROLE_MAP2) return LEGACY_ROLE_MAP2[input.role];
46194
46853
  return "explore";
46195
46854
  }
46196
46855
  var spawnSimpleAgentTool = defineTool({
@@ -46732,14 +47391,14 @@ ${message}
46732
47391
  const subprocess = execa(pm, cmdArgs, options);
46733
47392
  let stdoutBuffer = "";
46734
47393
  let stderrBuffer = "";
46735
- subprocess.stdout?.on("data", (chunk) => {
46736
- const text16 = chunk.toString();
47394
+ subprocess.stdout?.on("data", (chunk2) => {
47395
+ const text16 = chunk2.toString();
46737
47396
  stdoutBuffer += text16;
46738
47397
  process.stdout.write(text16);
46739
47398
  heartbeat.activity();
46740
47399
  });
46741
- subprocess.stderr?.on("data", (chunk) => {
46742
- const text16 = chunk.toString();
47400
+ subprocess.stderr?.on("data", (chunk2) => {
47401
+ const text16 = chunk2.toString();
46743
47402
  stderrBuffer += text16;
46744
47403
  process.stderr.write(text16);
46745
47404
  heartbeat.activity();
@@ -46857,14 +47516,14 @@ ${message}
46857
47516
  const subprocess = execa(pm, cmdArgs, options);
46858
47517
  let stdoutBuffer = "";
46859
47518
  let stderrBuffer = "";
46860
- subprocess.stdout?.on("data", (chunk) => {
46861
- const text16 = chunk.toString();
47519
+ subprocess.stdout?.on("data", (chunk2) => {
47520
+ const text16 = chunk2.toString();
46862
47521
  stdoutBuffer += text16;
46863
47522
  process.stdout.write(text16);
46864
47523
  heartbeat.activity();
46865
47524
  });
46866
- subprocess.stderr?.on("data", (chunk) => {
46867
- const text16 = chunk.toString();
47525
+ subprocess.stderr?.on("data", (chunk2) => {
47526
+ const text16 = chunk2.toString();
46868
47527
  stderrBuffer += text16;
46869
47528
  process.stderr.write(text16);
46870
47529
  heartbeat.activity();
@@ -46959,14 +47618,14 @@ ${message}
46959
47618
  const subprocess = execa("make", cmdArgs, options);
46960
47619
  let stdoutBuffer = "";
46961
47620
  let stderrBuffer = "";
46962
- subprocess.stdout?.on("data", (chunk) => {
46963
- const text16 = chunk.toString();
47621
+ subprocess.stdout?.on("data", (chunk2) => {
47622
+ const text16 = chunk2.toString();
46964
47623
  stdoutBuffer += text16;
46965
47624
  process.stdout.write(text16);
46966
47625
  heartbeat.activity();
46967
47626
  });
46968
- subprocess.stderr?.on("data", (chunk) => {
46969
- const text16 = chunk.toString();
47627
+ subprocess.stderr?.on("data", (chunk2) => {
47628
+ const text16 = chunk2.toString();
46970
47629
  stderrBuffer += text16;
46971
47630
  process.stderr.write(text16);
46972
47631
  heartbeat.activity();
@@ -47062,14 +47721,14 @@ ${message}
47062
47721
  const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
47063
47722
  let stdoutBuffer = "";
47064
47723
  let stderrBuffer = "";
47065
- subprocess.stdout?.on("data", (chunk) => {
47066
- const text16 = chunk.toString();
47724
+ subprocess.stdout?.on("data", (chunk2) => {
47725
+ const text16 = chunk2.toString();
47067
47726
  stdoutBuffer += text16;
47068
47727
  process.stdout.write(text16);
47069
47728
  heartbeat.activity();
47070
47729
  });
47071
- subprocess.stderr?.on("data", (chunk) => {
47072
- const text16 = chunk.toString();
47730
+ subprocess.stderr?.on("data", (chunk2) => {
47731
+ const text16 = chunk2.toString();
47073
47732
  stderrBuffer += text16;
47074
47733
  process.stderr.write(text16);
47075
47734
  heartbeat.activity();
@@ -47166,14 +47825,14 @@ ${message}
47166
47825
  });
47167
47826
  let stdoutBuffer = "";
47168
47827
  let stderrBuffer = "";
47169
- subprocess.stdout?.on("data", (chunk) => {
47170
- const text16 = chunk.toString();
47828
+ subprocess.stdout?.on("data", (chunk2) => {
47829
+ const text16 = chunk2.toString();
47171
47830
  stdoutBuffer += text16;
47172
47831
  process.stdout.write(text16);
47173
47832
  heartbeat.activity();
47174
47833
  });
47175
- subprocess.stderr?.on("data", (chunk) => {
47176
- const text16 = chunk.toString();
47834
+ subprocess.stderr?.on("data", (chunk2) => {
47835
+ const text16 = chunk2.toString();
47177
47836
  stderrBuffer += text16;
47178
47837
  process.stderr.write(text16);
47179
47838
  heartbeat.activity();
@@ -47253,14 +47912,14 @@ ${message}
47253
47912
  });
47254
47913
  let stdoutBuffer = "";
47255
47914
  let stderrBuffer = "";
47256
- subprocess.stdout?.on("data", (chunk) => {
47257
- const text16 = chunk.toString();
47915
+ subprocess.stdout?.on("data", (chunk2) => {
47916
+ const text16 = chunk2.toString();
47258
47917
  stdoutBuffer += text16;
47259
47918
  process.stdout.write(text16);
47260
47919
  heartbeat.activity();
47261
47920
  });
47262
- subprocess.stderr?.on("data", (chunk) => {
47263
- const text16 = chunk.toString();
47921
+ subprocess.stderr?.on("data", (chunk2) => {
47922
+ const text16 = chunk2.toString();
47264
47923
  stderrBuffer += text16;
47265
47924
  process.stderr.write(text16);
47266
47925
  heartbeat.activity();
@@ -49082,13 +49741,13 @@ Examples:
49082
49741
  const content = await fs41.readFile(fullPath, "utf-8");
49083
49742
  if (content.length > 1e5) continue;
49084
49743
  const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
49085
- for (const chunk of fileChunks) {
49086
- const vector = await getEmbedding(chunk.text);
49744
+ for (const chunk2 of fileChunks) {
49745
+ const vector = await getEmbedding(chunk2.text);
49087
49746
  chunks.push({
49088
49747
  file,
49089
- startLine: chunk.startLine,
49090
- endLine: chunk.endLine,
49091
- text: chunk.text,
49748
+ startLine: chunk2.startLine,
49749
+ endLine: chunk2.endLine,
49750
+ text: chunk2.text,
49092
49751
  vector,
49093
49752
  mtime: stat2.mtimeMs
49094
49753
  });
@@ -49122,9 +49781,9 @@ Examples:
49122
49781
  }
49123
49782
  }
49124
49783
  const queryVector = await getEmbedding(query);
49125
- const scored = index.chunks.map((chunk) => ({
49126
- chunk,
49127
- score: cosineSimilarity(queryVector, chunk.vector)
49784
+ const scored = index.chunks.map((chunk2) => ({
49785
+ chunk: chunk2,
49786
+ score: cosineSimilarity(queryVector, chunk2.vector)
49128
49787
  }));
49129
49788
  const filtered = scored.filter((s) => s.score >= effectiveThreshold).sort((a, b) => b.score - a.score).slice(0, effectiveMaxResults);
49130
49789
  const results = filtered.map((s) => {
@@ -54103,17 +54762,17 @@ function resetLineBuffer() {
54103
54762
  stopStreamingIndicator();
54104
54763
  resetBlockStore();
54105
54764
  }
54106
- function renderStreamChunk(chunk) {
54107
- if (chunk.type === "text" && chunk.text) {
54108
- lineBuffer += chunk.text;
54109
- rawMarkdownBuffer += chunk.text;
54765
+ function renderStreamChunk(chunk2) {
54766
+ if (chunk2.type === "text" && chunk2.text) {
54767
+ lineBuffer += chunk2.text;
54768
+ rawMarkdownBuffer += chunk2.text;
54110
54769
  let newlineIndex;
54111
54770
  while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
54112
54771
  const line = lineBuffer.slice(0, newlineIndex);
54113
54772
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
54114
54773
  processAndOutputLine(line);
54115
54774
  }
54116
- } else if (chunk.type === "done") {
54775
+ } else if (chunk2.type === "done") {
54117
54776
  flushLineBuffer();
54118
54777
  }
54119
54778
  }
@@ -55307,22 +55966,22 @@ ${tail}`;
55307
55966
  content: `[System: ${reason} Do not call tools. Either explain the exact blocker and ask the user for the smallest missing input, or, if the task is already complete, summarize it briefly. Do not return an empty response.]`
55308
55967
  }
55309
55968
  ];
55310
- for await (const chunk of provider.streamWithTools(finalMessages, {
55969
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
55311
55970
  tools: [],
55312
55971
  maxTokens: session.config.provider.maxTokens,
55313
55972
  signal: options.signal
55314
55973
  // Omit thinking for the final explanation turn to avoid unnecessary cost
55315
55974
  })) {
55316
55975
  if (options.signal?.aborted) break;
55317
- if (chunk.type === "text" && chunk.text) {
55976
+ if (chunk2.type === "text" && chunk2.text) {
55318
55977
  if (!explanationThinkingEnded) {
55319
55978
  options.onThinkingEnd?.();
55320
55979
  explanationThinkingEnded = true;
55321
55980
  }
55322
- explanation += chunk.text;
55323
- options.onStream?.(chunk);
55981
+ explanation += chunk2.text;
55982
+ options.onStream?.(chunk2);
55324
55983
  }
55325
- if (chunk.type === "done") break;
55984
+ if (chunk2.type === "done") break;
55326
55985
  }
55327
55986
  } catch {
55328
55987
  } finally {
@@ -55363,7 +56022,7 @@ ${tail}`;
55363
56022
  lastStopReason = void 0;
55364
56023
  const toolCallBuilders = /* @__PURE__ */ new Map();
55365
56024
  try {
55366
- for await (const chunk of provider.streamWithTools(messages, {
56025
+ for await (const chunk2 of provider.streamWithTools(messages, {
55367
56026
  tools,
55368
56027
  maxTokens: session.config.provider.maxTokens,
55369
56028
  signal: options.signal,
@@ -55373,56 +56032,56 @@ ${tail}`;
55373
56032
  break;
55374
56033
  }
55375
56034
  try {
55376
- if (chunk.type === "text" && chunk.text) {
56035
+ if (chunk2.type === "text" && chunk2.text) {
55377
56036
  if (!thinkingEnded) {
55378
56037
  options.onThinkingEnd?.();
55379
56038
  thinkingEnded = true;
55380
56039
  }
55381
- responseContent += chunk.text;
55382
- finalContent += chunk.text;
55383
- iterationTextChunks.push(chunk);
56040
+ responseContent += chunk2.text;
56041
+ finalContent += chunk2.text;
56042
+ iterationTextChunks.push(chunk2);
55384
56043
  }
55385
- if (chunk.type === "tool_use_start" && chunk.toolCall) {
56044
+ if (chunk2.type === "tool_use_start" && chunk2.toolCall) {
55386
56045
  flushLineBuffer();
55387
56046
  if (!thinkingEnded) {
55388
56047
  options.onThinkingEnd?.();
55389
56048
  thinkingEnded = true;
55390
56049
  }
55391
- const id = chunk.toolCall.id ?? `tool_${toolCallBuilders.size}`;
55392
- const toolName = chunk.toolCall.name ?? "";
56050
+ const id = chunk2.toolCall.id ?? `tool_${toolCallBuilders.size}`;
56051
+ const toolName = chunk2.toolCall.name ?? "";
55393
56052
  toolCallBuilders.set(id, {
55394
56053
  id,
55395
56054
  name: toolName,
55396
56055
  input: {},
55397
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56056
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55398
56057
  });
55399
56058
  if (toolName) {
55400
56059
  options.onToolPreparing?.(toolName);
55401
56060
  }
55402
56061
  }
55403
- if (chunk.type === "tool_use_end" && chunk.toolCall) {
55404
- const id = chunk.toolCall.id ?? "";
56062
+ if (chunk2.type === "tool_use_end" && chunk2.toolCall) {
56063
+ const id = chunk2.toolCall.id ?? "";
55405
56064
  const builder = toolCallBuilders.get(id);
55406
56065
  if (builder) {
55407
56066
  const finalToolCall = {
55408
56067
  id: builder.id,
55409
- name: chunk.toolCall.name ?? builder.name,
55410
- input: chunk.toolCall.input ?? builder.input,
55411
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
56068
+ name: chunk2.toolCall.name ?? builder.name,
56069
+ input: chunk2.toolCall.input ?? builder.input,
56070
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
55412
56071
  };
55413
56072
  collectedToolCalls.push(finalToolCall);
55414
- } else if (chunk.toolCall.id && chunk.toolCall.name) {
56073
+ } else if (chunk2.toolCall.id && chunk2.toolCall.name) {
55415
56074
  collectedToolCalls.push({
55416
- id: chunk.toolCall.id,
55417
- name: chunk.toolCall.name,
55418
- input: chunk.toolCall.input ?? {},
55419
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56075
+ id: chunk2.toolCall.id,
56076
+ name: chunk2.toolCall.name,
56077
+ input: chunk2.toolCall.input ?? {},
56078
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55420
56079
  });
55421
56080
  }
55422
56081
  }
55423
- if (chunk.type === "done") {
55424
- if (chunk.stopReason) {
55425
- lastStopReason = chunk.stopReason;
56082
+ if (chunk2.type === "done") {
56083
+ if (chunk2.stopReason) {
56084
+ lastStopReason = chunk2.stopReason;
55426
56085
  }
55427
56086
  if (!thinkingEnded) {
55428
56087
  options.onThinkingEnd?.();
@@ -55905,17 +56564,17 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
55905
56564
  if (stuckInErrorLoop) {
55906
56565
  try {
55907
56566
  const finalMessages = getConversationContext(session, toolRegistry);
55908
- for await (const chunk of provider.streamWithTools(finalMessages, {
56567
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
55909
56568
  tools: [],
55910
56569
  maxTokens: session.config.provider.maxTokens,
55911
56570
  signal: options.signal
55912
56571
  })) {
55913
56572
  if (options.signal?.aborted) break;
55914
- if (chunk.type === "text" && chunk.text) {
55915
- finalContent += chunk.text;
55916
- options.onStream?.(chunk);
56573
+ if (chunk2.type === "text" && chunk2.text) {
56574
+ finalContent += chunk2.text;
56575
+ options.onStream?.(chunk2);
55917
56576
  }
55918
- if (chunk.type === "done") break;
56577
+ if (chunk2.type === "done") break;
55919
56578
  }
55920
56579
  } catch {
55921
56580
  }
@@ -55936,21 +56595,21 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
55936
56595
  options.onThinkingStart?.();
55937
56596
  try {
55938
56597
  const finalMessages = getConversationContext(session, toolRegistry);
55939
- for await (const chunk of provider.streamWithTools(finalMessages, {
56598
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
55940
56599
  tools: [],
55941
56600
  maxTokens: session.config.provider.maxTokens,
55942
56601
  signal: options.signal
55943
56602
  })) {
55944
56603
  if (options.signal?.aborted) break;
55945
- if (chunk.type === "text" && chunk.text) {
56604
+ if (chunk2.type === "text" && chunk2.text) {
55946
56605
  if (!summaryThinkingEnded) {
55947
56606
  options.onThinkingEnd?.();
55948
56607
  summaryThinkingEnded = true;
55949
56608
  }
55950
- finalContent += chunk.text;
55951
- options.onStream?.(chunk);
56609
+ finalContent += chunk2.text;
56610
+ options.onStream?.(chunk2);
55952
56611
  }
55953
- if (chunk.type === "done") break;
56612
+ if (chunk2.type === "done") break;
55954
56613
  }
55955
56614
  } catch {
55956
56615
  const notice = `
@@ -56101,15 +56760,15 @@ function createReplayProvider(turns) {
56101
56760
  async *stream() {
56102
56761
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56103
56762
  callIndex++;
56104
- for (const chunk of chunks) {
56105
- yield chunk;
56763
+ for (const chunk2 of chunks) {
56764
+ yield chunk2;
56106
56765
  }
56107
56766
  },
56108
56767
  async *streamWithTools() {
56109
56768
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56110
56769
  callIndex++;
56111
- for (const chunk of chunks) {
56112
- yield chunk;
56770
+ for (const chunk2 of chunks) {
56771
+ yield chunk2;
56113
56772
  }
56114
56773
  },
56115
56774
  countTokens(text16) {
@@ -56125,9 +56784,9 @@ function createReplayProvider(turns) {
56125
56784
  }
56126
56785
  function collectToolNames(stream) {
56127
56786
  const names = /* @__PURE__ */ new Set();
56128
- for (const chunk of stream) {
56129
- if ((chunk.type === "tool_use_start" || chunk.type === "tool_use_end") && chunk.toolCall?.name) {
56130
- names.add(chunk.toolCall.name);
56787
+ for (const chunk2 of stream) {
56788
+ if ((chunk2.type === "tool_use_start" || chunk2.type === "tool_use_end") && chunk2.toolCall?.name) {
56789
+ names.add(chunk2.toolCall.name);
56131
56790
  }
56132
56791
  }
56133
56792
  return Array.from(names);
@@ -57511,7 +58170,6 @@ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
57511
58170
  "recall_memory",
57512
58171
  "list_memories",
57513
58172
  "list_checkpoints",
57514
- "spawnSimpleAgent",
57515
58173
  "checkAgentCapability"
57516
58174
  ]);
57517
58175
  var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
@@ -57522,7 +58180,8 @@ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
57522
58180
  "delete_file",
57523
58181
  "restore_checkpoint",
57524
58182
  "git_commit",
57525
- "git_push"
58183
+ "git_push",
58184
+ "request_human_escalation"
57526
58185
  ]);
57527
58186
  function riskForTool(tool) {
57528
58187
  if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
@@ -57556,6 +58215,22 @@ var DefaultPermissionPolicy = class {
57556
58215
  return { allowed: true, risk };
57557
58216
  }
57558
58217
  canExecuteToolInput(mode, tool, input) {
58218
+ if (tool.name === "spawnSimpleAgent") {
58219
+ const risk = riskForSpawnedAgent(input);
58220
+ const definition2 = getAgentMode(mode);
58221
+ if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
58222
+ return {
58223
+ allowed: false,
58224
+ reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
58225
+ risk
58226
+ };
58227
+ }
58228
+ return {
58229
+ allowed: true,
58230
+ requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
58231
+ risk
58232
+ };
58233
+ }
57559
58234
  if (tool.name !== "run_linter") {
57560
58235
  return this.canExecuteTool(mode, tool);
57561
58236
  }
@@ -57575,6 +58250,37 @@ var DefaultPermissionPolicy = class {
57575
58250
  function createPermissionPolicy() {
57576
58251
  return new DefaultPermissionPolicy();
57577
58252
  }
58253
+ function riskForSpawnedAgent(input) {
58254
+ const type = typeof input["type"] === "string" ? input["type"] : void 0;
58255
+ const role = typeof input["role"] === "string" ? input["role"] : void 0;
58256
+ const resolved = type ?? role;
58257
+ switch (resolved) {
58258
+ case "explore":
58259
+ case "plan":
58260
+ case "review":
58261
+ case "architect":
58262
+ case "security":
58263
+ case "docs":
58264
+ case "researcher":
58265
+ case "reviewer":
58266
+ case "planner":
58267
+ return "read-only";
58268
+ case "database":
58269
+ return "secrets-sensitive";
58270
+ case "test":
58271
+ case "tdd":
58272
+ case "e2e":
58273
+ case "tester":
58274
+ return "destructive";
58275
+ case "debug":
58276
+ case "refactor":
58277
+ case "coder":
58278
+ case "optimizer":
58279
+ return "write";
58280
+ default:
58281
+ return "read-only";
58282
+ }
58283
+ }
57578
58284
 
57579
58285
  // src/runtime/provider-registry.ts
57580
58286
  init_providers();
@@ -57667,7 +58373,32 @@ function cloneWorkflow(workflow) {
57667
58373
  steps: workflow.steps.map((step) => ({
57668
58374
  ...step,
57669
58375
  requiredTools: [...step.requiredTools]
57670
- }))
58376
+ })),
58377
+ nodes: workflow.nodes?.map((node) => ({
58378
+ ...node,
58379
+ dependsOn: node.dependsOn ? [...node.dependsOn] : void 0,
58380
+ requiredTools: node.requiredTools ? [...node.requiredTools] : void 0,
58381
+ gates: node.gates ? [...node.gates] : void 0,
58382
+ retryPolicy: node.retryPolicy ? { ...node.retryPolicy } : void 0
58383
+ })),
58384
+ edges: workflow.edges?.map((edge) => ({ ...edge })),
58385
+ gates: workflow.gates?.map((gate) => ({ ...gate })),
58386
+ retryPolicy: workflow.retryPolicy ? { ...workflow.retryPolicy } : void 0
58387
+ };
58388
+ }
58389
+ function workflowToAgentGraph(workflow) {
58390
+ const nodes = workflow.nodes ?? workflow.steps.map((step, index) => ({
58391
+ id: step.id,
58392
+ description: step.description,
58393
+ requiredTools: [...step.requiredTools],
58394
+ risk: step.risk,
58395
+ dependsOn: index > 0 ? [workflow.steps[index - 1].id] : []
58396
+ }));
58397
+ return {
58398
+ nodes,
58399
+ edges: workflow.edges,
58400
+ gates: workflow.gates,
58401
+ parallelism: workflow.parallelism
57671
58402
  };
57672
58403
  }
57673
58404
  var WorkflowCatalog = class {
@@ -57678,6 +58409,12 @@ var WorkflowCatalog = class {
57678
58409
  }
57679
58410
  }
57680
58411
  register(workflow) {
58412
+ const validation = validateAgentGraph(workflowToAgentGraph(workflow));
58413
+ if (!validation.valid) {
58414
+ throw new Error(
58415
+ `Invalid workflow graph for '${workflow.id}': ${validation.issues.map((issue) => issue.message).join("; ")}`
58416
+ );
58417
+ }
57681
58418
  this.workflows.set(workflow.id, cloneWorkflow(workflow));
57682
58419
  }
57683
58420
  get(id) {
@@ -57703,7 +58440,8 @@ var WorkflowCatalog = class {
57703
58440
  workflowId,
57704
58441
  planId: plan.id,
57705
58442
  replayable: workflow.replayable,
57706
- checks: workflow.checks
58443
+ checks: workflow.checks,
58444
+ graphLevels: validateAgentGraph(workflowToAgentGraph(workflow)).levels
57707
58445
  });
57708
58446
  return plan;
57709
58447
  }
@@ -57849,19 +58587,26 @@ function createWorkflowCatalog(workflows) {
57849
58587
 
57850
58588
  // src/runtime/workflow-engine.ts
57851
58589
  var WorkflowEngine = class {
57852
- constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
58590
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog(), options = {}) {
57853
58591
  this.catalog = catalog;
57854
58592
  this.eventLog = eventLog;
58593
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
58594
+ this.nodeExecutor = options.nodeExecutor;
57855
58595
  }
57856
58596
  catalog;
57857
58597
  eventLog;
57858
58598
  handlers = /* @__PURE__ */ new Map();
58599
+ sharedState;
58600
+ nodeExecutor;
57859
58601
  registerHandler(workflowId, handler) {
57860
58602
  if (!this.catalog.get(workflowId)) {
57861
58603
  throw new Error(`Unknown workflow: ${workflowId}`);
57862
58604
  }
57863
58605
  this.handlers.set(workflowId, handler);
57864
58606
  }
58607
+ registerNodeExecutor(executor) {
58608
+ this.nodeExecutor = executor;
58609
+ }
57865
58610
  createPlan(workflowId, input) {
57866
58611
  return this.catalog.createPlan(workflowId, input, this.eventLog);
57867
58612
  }
@@ -57871,23 +58616,35 @@ var WorkflowEngine = class {
57871
58616
  throw new Error(`Unknown workflow: ${request.workflowId}`);
57872
58617
  }
57873
58618
  const handler = this.handlers.get(request.workflowId);
57874
- if (!handler) {
57875
- throw new Error(`No handler registered for workflow: ${request.workflowId}`);
57876
- }
57877
58619
  const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
57878
58620
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
57879
58621
  const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
58622
+ const trace = createAgentTraceContext({ workflowRunId: runId });
57880
58623
  this.eventLog.record("workflow.started", {
57881
58624
  workflowId: request.workflowId,
57882
58625
  planId: plan.id,
57883
- runId
58626
+ runId,
58627
+ trace
57884
58628
  });
57885
58629
  try {
57886
- const output = await handler(request.input, {
58630
+ const graphResult = handler ? void 0 : await new AgentGraphEngine({
58631
+ eventLog: this.eventLog,
58632
+ sharedState: this.sharedState,
58633
+ nodeExecutor: this.nodeExecutor,
58634
+ trace
58635
+ }).run({
58636
+ workflowRunId: runId,
58637
+ graph: workflowToAgentGraph(workflow),
58638
+ input: request.input
58639
+ });
58640
+ const output = graphResult ?? await handler(request.input, {
57887
58641
  workflow,
57888
58642
  plan,
57889
58643
  eventLog: this.eventLog
57890
58644
  });
58645
+ if (graphResult?.status === "failed") {
58646
+ throw new Error(graphResult.error ?? "Workflow graph failed");
58647
+ }
57891
58648
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
57892
58649
  const result = {
57893
58650
  id: runId,
@@ -57895,12 +58652,15 @@ var WorkflowEngine = class {
57895
58652
  status: "completed",
57896
58653
  output,
57897
58654
  startedAt,
57898
- completedAt
58655
+ completedAt,
58656
+ graphResult,
58657
+ trace
57899
58658
  };
57900
58659
  this.eventLog.record("workflow.completed", {
57901
58660
  workflowId: request.workflowId,
57902
58661
  planId: plan.id,
57903
- runId
58662
+ runId,
58663
+ trace
57904
58664
  });
57905
58665
  return result;
57906
58666
  } catch (error) {
@@ -57910,7 +58670,8 @@ var WorkflowEngine = class {
57910
58670
  workflowId: request.workflowId,
57911
58671
  planId: plan.id,
57912
58672
  runId,
57913
- error: message
58673
+ error: message,
58674
+ trace
57914
58675
  });
57915
58676
  return {
57916
58677
  id: runId,
@@ -57919,13 +58680,14 @@ var WorkflowEngine = class {
57919
58680
  output: null,
57920
58681
  startedAt,
57921
58682
  completedAt,
57922
- error: message
58683
+ error: message,
58684
+ trace
57923
58685
  };
57924
58686
  }
57925
58687
  }
57926
58688
  };
57927
- function createWorkflowEngine(catalog, eventLog) {
57928
- return new WorkflowEngine(catalog, eventLog);
58689
+ function createWorkflowEngine(catalog, eventLog, options) {
58690
+ return new WorkflowEngine(catalog, eventLog, options);
57929
58691
  }
57930
58692
 
57931
58693
  // src/runtime/agent-runtime.ts
@@ -58103,7 +58865,7 @@ var AgentRuntime = class {
58103
58865
  let completed = false;
58104
58866
  let failed = false;
58105
58867
  try {
58106
- for await (const chunk of provider.stream(messages, {
58868
+ for await (const chunk2 of provider.stream(messages, {
58107
58869
  model: input.options?.model,
58108
58870
  maxTokens: input.options?.maxTokens,
58109
58871
  temperature: input.options?.temperature,
@@ -58113,12 +58875,12 @@ var AgentRuntime = class {
58113
58875
  signal: input.options?.signal,
58114
58876
  thinking: input.options?.thinking
58115
58877
  })) {
58116
- if (chunk.type === "text" && chunk.text) {
58117
- content += chunk.text;
58878
+ if (chunk2.type === "text" && chunk2.text) {
58879
+ content += chunk2.text;
58118
58880
  yield {
58119
58881
  type: "text",
58120
58882
  sessionId: effectiveSession.id,
58121
- text: chunk.text
58883
+ text: chunk2.text
58122
58884
  };
58123
58885
  }
58124
58886
  }
@@ -58298,6 +59060,118 @@ async function createAgentRuntime(options) {
58298
59060
  return runtime;
58299
59061
  }
58300
59062
 
59063
+ // src/runtime/tool-calling-turn-runner.ts
59064
+ function runtimeWithTools(runtime) {
59065
+ if (runtime && typeof runtime === "object" && "executeTool" in runtime && typeof runtime.executeTool === "function") {
59066
+ return runtime;
59067
+ }
59068
+ throw new Error("ToolCallingRuntimeTurnRunner requires a runtime with executeTool().");
59069
+ }
59070
+ function toolResultToContent(result) {
59071
+ if (!result.success) {
59072
+ return `Error: ${result.error ?? "Tool failed."}`;
59073
+ }
59074
+ if (typeof result.output === "string") return result.output;
59075
+ return JSON.stringify(result.output ?? null);
59076
+ }
59077
+ var ToolCallingRuntimeTurnRunner = class {
59078
+ maxToolIterations;
59079
+ constructor(options = {}) {
59080
+ this.maxToolIterations = options.maxToolIterations ?? 10;
59081
+ }
59082
+ async run(input, context) {
59083
+ const runtime = runtimeWithTools(context.runtime);
59084
+ const messages = [
59085
+ ...context.session.messages,
59086
+ {
59087
+ role: "user",
59088
+ content: input.content
59089
+ }
59090
+ ];
59091
+ const tools = context.toolRegistry.getToolDefinitionsForLLM();
59092
+ const confirmedTools = new Set(input.confirmedTools ?? []);
59093
+ let inputTokens = 0;
59094
+ let outputTokens = 0;
59095
+ let lastModel = input.options?.model ?? context.provider.id;
59096
+ for (let iteration = 0; iteration < this.maxToolIterations; iteration++) {
59097
+ const response = await context.provider.chatWithTools(messages, {
59098
+ tools,
59099
+ model: input.options?.model,
59100
+ maxTokens: input.options?.maxTokens,
59101
+ temperature: input.options?.temperature,
59102
+ stopSequences: input.options?.stopSequences,
59103
+ system: context.session.instructions ?? input.options?.system,
59104
+ timeout: input.options?.timeout,
59105
+ signal: input.options?.signal,
59106
+ thinking: input.options?.thinking
59107
+ });
59108
+ inputTokens += response.usage.inputTokens;
59109
+ outputTokens += response.usage.outputTokens;
59110
+ lastModel = response.model;
59111
+ if (response.stopReason !== "tool_use" || response.toolCalls.length === 0) {
59112
+ return {
59113
+ sessionId: context.session.id,
59114
+ content: response.content,
59115
+ usage: { inputTokens, outputTokens },
59116
+ model: response.model,
59117
+ mode: context.session.mode
59118
+ };
59119
+ }
59120
+ const assistantContent = [];
59121
+ if (response.content.trim().length > 0) {
59122
+ assistantContent.push({ type: "text", text: response.content });
59123
+ }
59124
+ for (const toolCall of response.toolCalls) {
59125
+ assistantContent.push({
59126
+ type: "tool_use",
59127
+ id: toolCall.id,
59128
+ name: toolCall.name,
59129
+ input: toolCall.input,
59130
+ geminiThoughtSignature: toolCall.geminiThoughtSignature
59131
+ });
59132
+ }
59133
+ messages.push({
59134
+ role: "assistant",
59135
+ content: assistantContent
59136
+ });
59137
+ const toolResults = [];
59138
+ for (const toolCall of response.toolCalls) {
59139
+ const result = await runtime.executeTool({
59140
+ sessionId: context.session.id,
59141
+ mode: context.session.mode,
59142
+ toolName: toolCall.name,
59143
+ input: toolCall.input,
59144
+ confirmed: confirmedTools.has(toolCall.name),
59145
+ metadata: input.metadata
59146
+ });
59147
+ toolResults.push({
59148
+ type: "tool_result",
59149
+ tool_use_id: toolCall.id,
59150
+ content: toolResultToContent(result),
59151
+ is_error: !result.success
59152
+ });
59153
+ }
59154
+ messages.push({
59155
+ role: "user",
59156
+ content: toolResults
59157
+ });
59158
+ }
59159
+ return {
59160
+ sessionId: context.session.id,
59161
+ content: "The tool-calling runtime reached its maximum tool iteration budget.",
59162
+ usage: { inputTokens, outputTokens },
59163
+ model: lastModel,
59164
+ mode: context.session.mode
59165
+ };
59166
+ }
59167
+ };
59168
+ function createToolCallingRuntimeTurnRunner(options) {
59169
+ return new ToolCallingRuntimeTurnRunner(options);
59170
+ }
59171
+
59172
+ // src/runtime/blueprints.ts
59173
+ init_registry4();
59174
+
58301
59175
  // src/cli/repl/index.ts
58302
59176
  init_version();
58303
59177
  init_trust_store();
@@ -59444,12 +60318,12 @@ ${imagePrompts}`.trim() : imagePrompts;
59444
60318
  let lastToolGroup = null;
59445
60319
  await ensureRequestedMcpConnections(extractMessageText(effectiveMessage));
59446
60320
  const result = await executeAgentTurn(session, effectiveMessage, provider, toolRegistry, {
59447
- onStream: (chunk) => {
60321
+ onStream: (chunk2) => {
59448
60322
  if (!streamStarted) {
59449
60323
  streamStarted = true;
59450
60324
  clearSpinner();
59451
60325
  }
59452
- renderStreamChunk(chunk);
60326
+ renderStreamChunk(chunk2);
59453
60327
  },
59454
60328
  onToolStart: (tc, index, total) => {
59455
60329
  const desc = getToolRunningDescription(
@@ -60080,9 +60954,9 @@ async function readStdin() {
60080
60954
  const timeout = setTimeout(() => {
60081
60955
  resolve4("");
60082
60956
  }, 5e3);
60083
- process.stdin.on("data", (chunk) => {
60957
+ process.stdin.on("data", (chunk2) => {
60084
60958
  clearTimeout(timeout);
60085
- chunks.push(Buffer.from(chunk));
60959
+ chunks.push(Buffer.from(chunk2));
60086
60960
  });
60087
60961
  process.stdin.on("end", () => {
60088
60962
  clearTimeout(timeout);
@@ -60132,18 +61006,49 @@ ${stdinContent}
60132
61006
  model: session.config.provider.model || void 0,
60133
61007
  provider,
60134
61008
  eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
61009
+ turnRunner: options.useRuntimeRunner ? createToolCallingRuntimeTurnRunner() : void 0,
60135
61010
  publishToGlobalBridge: true
60136
61011
  });
60137
61012
  session.runtime = runtime;
60138
61013
  const toolRegistry = runtime.toolRegistry;
60139
61014
  await loadAllowedPaths(options.projectPath);
60140
61015
  await initializeContextManager(session, provider);
61016
+ if (options.useRuntimeRunner) {
61017
+ const runtimeSession = runtime.createSession({
61018
+ id: session.id,
61019
+ mode: "build",
61020
+ instructions: session.config.agent.systemPrompt || void 0,
61021
+ metadata: {
61022
+ surface: "cli",
61023
+ product: "coco-code",
61024
+ execution: "headless-runtime-runner"
61025
+ }
61026
+ });
61027
+ const result2 = await runtime.runTurn({
61028
+ sessionId: runtimeSession.id,
61029
+ content: task,
61030
+ metadata: { surface: "cli", product: "coco-code" }
61031
+ });
61032
+ const events = runtime.eventLog.list();
61033
+ const headlessResult2 = {
61034
+ success: true,
61035
+ output: result2.content,
61036
+ toolsExecuted: events.filter((event) => event.type === "tool.completed").length,
61037
+ usage: result2.usage
61038
+ };
61039
+ if (options.outputFormat === "json") {
61040
+ process.stdout.write(JSON.stringify(headlessResult2, null, 2) + "\n");
61041
+ } else {
61042
+ process.stdout.write(result2.content + "\n");
61043
+ }
61044
+ return headlessResult2;
61045
+ }
60141
61046
  const result = await executeAgentTurn(session, task, provider, toolRegistry, {
60142
61047
  skipConfirmation: true,
60143
61048
  // No interactive confirmations in headless mode
60144
- onStream: (chunk) => {
60145
- if (options.outputFormat === "text" && chunk.type === "text" && chunk.text) {
60146
- process.stdout.write(chunk.text);
61049
+ onStream: (chunk2) => {
61050
+ if (options.outputFormat === "text" && chunk2.type === "text" && chunk2.text) {
61051
+ process.stdout.write(chunk2.text);
60147
61052
  }
60148
61053
  }
60149
61054
  });
@@ -60203,7 +61108,10 @@ program.command("setup").description("Configure AI provider and API key").action
60203
61108
  console.log("\n\u274C Setup cancelled.");
60204
61109
  }
60205
61110
  });
60206
- program.command("chat", { isDefault: true }).description("Start interactive chat session with the agent").option("-m, --model <model>", "LLM model to use").option("--provider <provider>", "LLM provider (anthropic, openai, codex, gemini, kimi)").option("--editor-model <model>", "Cheap model for file edits (architect/editor split)").option("--weak-model <model>", "Cheap model for background tasks (compaction, summaries)").option("-p, --path <path>", "Project path", process.cwd()).option("-P, --print [task]", "Headless mode: run task and print output (no interactive UI)").option("--output <format>", "Output format for headless mode (text or json)", "text").option("--setup", "Run setup wizard before starting").action(
61111
+ program.command("chat", { isDefault: true }).description("Start interactive chat session with the agent").option("-m, --model <model>", "LLM model to use").option("--provider <provider>", "LLM provider (anthropic, openai, codex, gemini, kimi)").option("--editor-model <model>", "Cheap model for file edits (architect/editor split)").option("--weak-model <model>", "Cheap model for background tasks (compaction, summaries)").option("-p, --path <path>", "Project path", process.cwd()).option("-P, --print [task]", "Headless mode: run task and print output (no interactive UI)").option(
61112
+ "--runtime-runner",
61113
+ "Experimental: run headless tasks through the reusable runtime tool-calling runner"
61114
+ ).option("--output <format>", "Output format for headless mode (text or json)", "text").option("--setup", "Run setup wizard before starting").action(
60207
61115
  async (options) => {
60208
61116
  if (options.setup) {
60209
61117
  const result = await runOnboardingV2();
@@ -60220,6 +61128,7 @@ program.command("chat", { isDefault: true }).description("Start interactive chat
60220
61128
  task,
60221
61129
  projectPath: options.path,
60222
61130
  outputFormat: options.output === "json" ? "json" : "text",
61131
+ useRuntimeRunner: options.runtimeRunner === true,
60223
61132
  config: {
60224
61133
  provider: {
60225
61134
  type: providerType,