@corbat-tech/coco 2.38.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,8 +43226,330 @@ Response format (JSON only, no prose):
43226
43226
  p26.outro(" Spec saved \u2014 starting sprints");
43227
43227
  return spec;
43228
43228
  }
43229
-
43230
- // src/runtime/multi-agent.ts
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
+ };
43231
43553
  function createAgentArtifact(input) {
43232
43554
  return {
43233
43555
  ...input,
@@ -43359,6 +43681,101 @@ function buildExecutionLevels(graph, issues) {
43359
43681
  }
43360
43682
  return levels;
43361
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
+ }
43362
43779
  function cloneArtifact(artifact) {
43363
43780
  return {
43364
43781
  ...artifact,
@@ -43547,7 +43964,7 @@ Complete this task autonomously using the available tools. When done, provide a
43547
43964
  }
43548
43965
  };
43549
43966
  function normalizeRole(role) {
43550
- return role === "researcher" || role === "architect" || role === "editor" || role === "coder" || role === "tester" || role === "reviewer" || role === "optimizer" || role === "planner" ? role : "coder";
43967
+ return mapLegacyAgentRole(role);
43551
43968
  }
43552
43969
  var AGENT_ROLES = {
43553
43970
  researcher: {
@@ -46366,29 +46783,7 @@ var AgentManager = class extends EventEmitter {
46366
46783
  }
46367
46784
  };
46368
46785
  function agentTypeToRuntimeRole(type) {
46369
- switch (type) {
46370
- case "explore":
46371
- return "researcher";
46372
- case "plan":
46373
- return "planner";
46374
- case "test":
46375
- case "e2e":
46376
- case "tdd":
46377
- return "tester";
46378
- case "debug":
46379
- case "refactor":
46380
- return "coder";
46381
- case "review":
46382
- return "reviewer";
46383
- case "architect":
46384
- return "architect";
46385
- case "security":
46386
- return "security";
46387
- case "docs":
46388
- return "docs";
46389
- case "database":
46390
- return "database";
46391
- }
46786
+ return mapLegacyAgentRole(type);
46392
46787
  }
46393
46788
 
46394
46789
  // src/agents/provider-bridge.ts
@@ -46434,7 +46829,7 @@ var AGENT_TYPES = [
46434
46829
  "docs",
46435
46830
  "database"
46436
46831
  ];
46437
- var LEGACY_ROLE_MAP = {
46832
+ var LEGACY_ROLE_MAP2 = {
46438
46833
  researcher: "explore",
46439
46834
  coder: "debug",
46440
46835
  // "debug" has write + bash + read — closest to general coding
@@ -46454,7 +46849,7 @@ var SpawnSimpleAgentSchema = z.object({
46454
46849
  });
46455
46850
  function resolveAgentType(input) {
46456
46851
  if (input.type) return input.type;
46457
- 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];
46458
46853
  return "explore";
46459
46854
  }
46460
46855
  var spawnSimpleAgentTool = defineTool({
@@ -46996,14 +47391,14 @@ ${message}
46996
47391
  const subprocess = execa(pm, cmdArgs, options);
46997
47392
  let stdoutBuffer = "";
46998
47393
  let stderrBuffer = "";
46999
- subprocess.stdout?.on("data", (chunk) => {
47000
- const text16 = chunk.toString();
47394
+ subprocess.stdout?.on("data", (chunk2) => {
47395
+ const text16 = chunk2.toString();
47001
47396
  stdoutBuffer += text16;
47002
47397
  process.stdout.write(text16);
47003
47398
  heartbeat.activity();
47004
47399
  });
47005
- subprocess.stderr?.on("data", (chunk) => {
47006
- const text16 = chunk.toString();
47400
+ subprocess.stderr?.on("data", (chunk2) => {
47401
+ const text16 = chunk2.toString();
47007
47402
  stderrBuffer += text16;
47008
47403
  process.stderr.write(text16);
47009
47404
  heartbeat.activity();
@@ -47121,14 +47516,14 @@ ${message}
47121
47516
  const subprocess = execa(pm, cmdArgs, options);
47122
47517
  let stdoutBuffer = "";
47123
47518
  let stderrBuffer = "";
47124
- subprocess.stdout?.on("data", (chunk) => {
47125
- const text16 = chunk.toString();
47519
+ subprocess.stdout?.on("data", (chunk2) => {
47520
+ const text16 = chunk2.toString();
47126
47521
  stdoutBuffer += text16;
47127
47522
  process.stdout.write(text16);
47128
47523
  heartbeat.activity();
47129
47524
  });
47130
- subprocess.stderr?.on("data", (chunk) => {
47131
- const text16 = chunk.toString();
47525
+ subprocess.stderr?.on("data", (chunk2) => {
47526
+ const text16 = chunk2.toString();
47132
47527
  stderrBuffer += text16;
47133
47528
  process.stderr.write(text16);
47134
47529
  heartbeat.activity();
@@ -47223,14 +47618,14 @@ ${message}
47223
47618
  const subprocess = execa("make", cmdArgs, options);
47224
47619
  let stdoutBuffer = "";
47225
47620
  let stderrBuffer = "";
47226
- subprocess.stdout?.on("data", (chunk) => {
47227
- const text16 = chunk.toString();
47621
+ subprocess.stdout?.on("data", (chunk2) => {
47622
+ const text16 = chunk2.toString();
47228
47623
  stdoutBuffer += text16;
47229
47624
  process.stdout.write(text16);
47230
47625
  heartbeat.activity();
47231
47626
  });
47232
- subprocess.stderr?.on("data", (chunk) => {
47233
- const text16 = chunk.toString();
47627
+ subprocess.stderr?.on("data", (chunk2) => {
47628
+ const text16 = chunk2.toString();
47234
47629
  stderrBuffer += text16;
47235
47630
  process.stderr.write(text16);
47236
47631
  heartbeat.activity();
@@ -47326,14 +47721,14 @@ ${message}
47326
47721
  const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
47327
47722
  let stdoutBuffer = "";
47328
47723
  let stderrBuffer = "";
47329
- subprocess.stdout?.on("data", (chunk) => {
47330
- const text16 = chunk.toString();
47724
+ subprocess.stdout?.on("data", (chunk2) => {
47725
+ const text16 = chunk2.toString();
47331
47726
  stdoutBuffer += text16;
47332
47727
  process.stdout.write(text16);
47333
47728
  heartbeat.activity();
47334
47729
  });
47335
- subprocess.stderr?.on("data", (chunk) => {
47336
- const text16 = chunk.toString();
47730
+ subprocess.stderr?.on("data", (chunk2) => {
47731
+ const text16 = chunk2.toString();
47337
47732
  stderrBuffer += text16;
47338
47733
  process.stderr.write(text16);
47339
47734
  heartbeat.activity();
@@ -47430,14 +47825,14 @@ ${message}
47430
47825
  });
47431
47826
  let stdoutBuffer = "";
47432
47827
  let stderrBuffer = "";
47433
- subprocess.stdout?.on("data", (chunk) => {
47434
- const text16 = chunk.toString();
47828
+ subprocess.stdout?.on("data", (chunk2) => {
47829
+ const text16 = chunk2.toString();
47435
47830
  stdoutBuffer += text16;
47436
47831
  process.stdout.write(text16);
47437
47832
  heartbeat.activity();
47438
47833
  });
47439
- subprocess.stderr?.on("data", (chunk) => {
47440
- const text16 = chunk.toString();
47834
+ subprocess.stderr?.on("data", (chunk2) => {
47835
+ const text16 = chunk2.toString();
47441
47836
  stderrBuffer += text16;
47442
47837
  process.stderr.write(text16);
47443
47838
  heartbeat.activity();
@@ -47517,14 +47912,14 @@ ${message}
47517
47912
  });
47518
47913
  let stdoutBuffer = "";
47519
47914
  let stderrBuffer = "";
47520
- subprocess.stdout?.on("data", (chunk) => {
47521
- const text16 = chunk.toString();
47915
+ subprocess.stdout?.on("data", (chunk2) => {
47916
+ const text16 = chunk2.toString();
47522
47917
  stdoutBuffer += text16;
47523
47918
  process.stdout.write(text16);
47524
47919
  heartbeat.activity();
47525
47920
  });
47526
- subprocess.stderr?.on("data", (chunk) => {
47527
- const text16 = chunk.toString();
47921
+ subprocess.stderr?.on("data", (chunk2) => {
47922
+ const text16 = chunk2.toString();
47528
47923
  stderrBuffer += text16;
47529
47924
  process.stderr.write(text16);
47530
47925
  heartbeat.activity();
@@ -49346,13 +49741,13 @@ Examples:
49346
49741
  const content = await fs41.readFile(fullPath, "utf-8");
49347
49742
  if (content.length > 1e5) continue;
49348
49743
  const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
49349
- for (const chunk of fileChunks) {
49350
- const vector = await getEmbedding(chunk.text);
49744
+ for (const chunk2 of fileChunks) {
49745
+ const vector = await getEmbedding(chunk2.text);
49351
49746
  chunks.push({
49352
49747
  file,
49353
- startLine: chunk.startLine,
49354
- endLine: chunk.endLine,
49355
- text: chunk.text,
49748
+ startLine: chunk2.startLine,
49749
+ endLine: chunk2.endLine,
49750
+ text: chunk2.text,
49356
49751
  vector,
49357
49752
  mtime: stat2.mtimeMs
49358
49753
  });
@@ -49386,9 +49781,9 @@ Examples:
49386
49781
  }
49387
49782
  }
49388
49783
  const queryVector = await getEmbedding(query);
49389
- const scored = index.chunks.map((chunk) => ({
49390
- chunk,
49391
- score: cosineSimilarity(queryVector, chunk.vector)
49784
+ const scored = index.chunks.map((chunk2) => ({
49785
+ chunk: chunk2,
49786
+ score: cosineSimilarity(queryVector, chunk2.vector)
49392
49787
  }));
49393
49788
  const filtered = scored.filter((s) => s.score >= effectiveThreshold).sort((a, b) => b.score - a.score).slice(0, effectiveMaxResults);
49394
49789
  const results = filtered.map((s) => {
@@ -54367,17 +54762,17 @@ function resetLineBuffer() {
54367
54762
  stopStreamingIndicator();
54368
54763
  resetBlockStore();
54369
54764
  }
54370
- function renderStreamChunk(chunk) {
54371
- if (chunk.type === "text" && chunk.text) {
54372
- lineBuffer += chunk.text;
54373
- rawMarkdownBuffer += chunk.text;
54765
+ function renderStreamChunk(chunk2) {
54766
+ if (chunk2.type === "text" && chunk2.text) {
54767
+ lineBuffer += chunk2.text;
54768
+ rawMarkdownBuffer += chunk2.text;
54374
54769
  let newlineIndex;
54375
54770
  while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
54376
54771
  const line = lineBuffer.slice(0, newlineIndex);
54377
54772
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
54378
54773
  processAndOutputLine(line);
54379
54774
  }
54380
- } else if (chunk.type === "done") {
54775
+ } else if (chunk2.type === "done") {
54381
54776
  flushLineBuffer();
54382
54777
  }
54383
54778
  }
@@ -55571,22 +55966,22 @@ ${tail}`;
55571
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.]`
55572
55967
  }
55573
55968
  ];
55574
- for await (const chunk of provider.streamWithTools(finalMessages, {
55969
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
55575
55970
  tools: [],
55576
55971
  maxTokens: session.config.provider.maxTokens,
55577
55972
  signal: options.signal
55578
55973
  // Omit thinking for the final explanation turn to avoid unnecessary cost
55579
55974
  })) {
55580
55975
  if (options.signal?.aborted) break;
55581
- if (chunk.type === "text" && chunk.text) {
55976
+ if (chunk2.type === "text" && chunk2.text) {
55582
55977
  if (!explanationThinkingEnded) {
55583
55978
  options.onThinkingEnd?.();
55584
55979
  explanationThinkingEnded = true;
55585
55980
  }
55586
- explanation += chunk.text;
55587
- options.onStream?.(chunk);
55981
+ explanation += chunk2.text;
55982
+ options.onStream?.(chunk2);
55588
55983
  }
55589
- if (chunk.type === "done") break;
55984
+ if (chunk2.type === "done") break;
55590
55985
  }
55591
55986
  } catch {
55592
55987
  } finally {
@@ -55627,7 +56022,7 @@ ${tail}`;
55627
56022
  lastStopReason = void 0;
55628
56023
  const toolCallBuilders = /* @__PURE__ */ new Map();
55629
56024
  try {
55630
- for await (const chunk of provider.streamWithTools(messages, {
56025
+ for await (const chunk2 of provider.streamWithTools(messages, {
55631
56026
  tools,
55632
56027
  maxTokens: session.config.provider.maxTokens,
55633
56028
  signal: options.signal,
@@ -55637,56 +56032,56 @@ ${tail}`;
55637
56032
  break;
55638
56033
  }
55639
56034
  try {
55640
- if (chunk.type === "text" && chunk.text) {
56035
+ if (chunk2.type === "text" && chunk2.text) {
55641
56036
  if (!thinkingEnded) {
55642
56037
  options.onThinkingEnd?.();
55643
56038
  thinkingEnded = true;
55644
56039
  }
55645
- responseContent += chunk.text;
55646
- finalContent += chunk.text;
55647
- iterationTextChunks.push(chunk);
56040
+ responseContent += chunk2.text;
56041
+ finalContent += chunk2.text;
56042
+ iterationTextChunks.push(chunk2);
55648
56043
  }
55649
- if (chunk.type === "tool_use_start" && chunk.toolCall) {
56044
+ if (chunk2.type === "tool_use_start" && chunk2.toolCall) {
55650
56045
  flushLineBuffer();
55651
56046
  if (!thinkingEnded) {
55652
56047
  options.onThinkingEnd?.();
55653
56048
  thinkingEnded = true;
55654
56049
  }
55655
- const id = chunk.toolCall.id ?? `tool_${toolCallBuilders.size}`;
55656
- const toolName = chunk.toolCall.name ?? "";
56050
+ const id = chunk2.toolCall.id ?? `tool_${toolCallBuilders.size}`;
56051
+ const toolName = chunk2.toolCall.name ?? "";
55657
56052
  toolCallBuilders.set(id, {
55658
56053
  id,
55659
56054
  name: toolName,
55660
56055
  input: {},
55661
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56056
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55662
56057
  });
55663
56058
  if (toolName) {
55664
56059
  options.onToolPreparing?.(toolName);
55665
56060
  }
55666
56061
  }
55667
- if (chunk.type === "tool_use_end" && chunk.toolCall) {
55668
- const id = chunk.toolCall.id ?? "";
56062
+ if (chunk2.type === "tool_use_end" && chunk2.toolCall) {
56063
+ const id = chunk2.toolCall.id ?? "";
55669
56064
  const builder = toolCallBuilders.get(id);
55670
56065
  if (builder) {
55671
56066
  const finalToolCall = {
55672
56067
  id: builder.id,
55673
- name: chunk.toolCall.name ?? builder.name,
55674
- input: chunk.toolCall.input ?? builder.input,
55675
- 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
55676
56071
  };
55677
56072
  collectedToolCalls.push(finalToolCall);
55678
- } else if (chunk.toolCall.id && chunk.toolCall.name) {
56073
+ } else if (chunk2.toolCall.id && chunk2.toolCall.name) {
55679
56074
  collectedToolCalls.push({
55680
- id: chunk.toolCall.id,
55681
- name: chunk.toolCall.name,
55682
- input: chunk.toolCall.input ?? {},
55683
- geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
56075
+ id: chunk2.toolCall.id,
56076
+ name: chunk2.toolCall.name,
56077
+ input: chunk2.toolCall.input ?? {},
56078
+ geminiThoughtSignature: chunk2.toolCall.geminiThoughtSignature
55684
56079
  });
55685
56080
  }
55686
56081
  }
55687
- if (chunk.type === "done") {
55688
- if (chunk.stopReason) {
55689
- lastStopReason = chunk.stopReason;
56082
+ if (chunk2.type === "done") {
56083
+ if (chunk2.stopReason) {
56084
+ lastStopReason = chunk2.stopReason;
55690
56085
  }
55691
56086
  if (!thinkingEnded) {
55692
56087
  options.onThinkingEnd?.();
@@ -56169,17 +56564,17 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
56169
56564
  if (stuckInErrorLoop) {
56170
56565
  try {
56171
56566
  const finalMessages = getConversationContext(session, toolRegistry);
56172
- for await (const chunk of provider.streamWithTools(finalMessages, {
56567
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
56173
56568
  tools: [],
56174
56569
  maxTokens: session.config.provider.maxTokens,
56175
56570
  signal: options.signal
56176
56571
  })) {
56177
56572
  if (options.signal?.aborted) break;
56178
- if (chunk.type === "text" && chunk.text) {
56179
- finalContent += chunk.text;
56180
- options.onStream?.(chunk);
56573
+ if (chunk2.type === "text" && chunk2.text) {
56574
+ finalContent += chunk2.text;
56575
+ options.onStream?.(chunk2);
56181
56576
  }
56182
- if (chunk.type === "done") break;
56577
+ if (chunk2.type === "done") break;
56183
56578
  }
56184
56579
  } catch {
56185
56580
  }
@@ -56200,21 +56595,21 @@ ${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
56200
56595
  options.onThinkingStart?.();
56201
56596
  try {
56202
56597
  const finalMessages = getConversationContext(session, toolRegistry);
56203
- for await (const chunk of provider.streamWithTools(finalMessages, {
56598
+ for await (const chunk2 of provider.streamWithTools(finalMessages, {
56204
56599
  tools: [],
56205
56600
  maxTokens: session.config.provider.maxTokens,
56206
56601
  signal: options.signal
56207
56602
  })) {
56208
56603
  if (options.signal?.aborted) break;
56209
- if (chunk.type === "text" && chunk.text) {
56604
+ if (chunk2.type === "text" && chunk2.text) {
56210
56605
  if (!summaryThinkingEnded) {
56211
56606
  options.onThinkingEnd?.();
56212
56607
  summaryThinkingEnded = true;
56213
56608
  }
56214
- finalContent += chunk.text;
56215
- options.onStream?.(chunk);
56609
+ finalContent += chunk2.text;
56610
+ options.onStream?.(chunk2);
56216
56611
  }
56217
- if (chunk.type === "done") break;
56612
+ if (chunk2.type === "done") break;
56218
56613
  }
56219
56614
  } catch {
56220
56615
  const notice = `
@@ -56365,15 +56760,15 @@ function createReplayProvider(turns) {
56365
56760
  async *stream() {
56366
56761
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56367
56762
  callIndex++;
56368
- for (const chunk of chunks) {
56369
- yield chunk;
56763
+ for (const chunk2 of chunks) {
56764
+ yield chunk2;
56370
56765
  }
56371
56766
  },
56372
56767
  async *streamWithTools() {
56373
56768
  const chunks = turns[Math.min(callIndex, turns.length - 1)] ?? [{ type: "done" }];
56374
56769
  callIndex++;
56375
- for (const chunk of chunks) {
56376
- yield chunk;
56770
+ for (const chunk2 of chunks) {
56771
+ yield chunk2;
56377
56772
  }
56378
56773
  },
56379
56774
  countTokens(text16) {
@@ -56389,9 +56784,9 @@ function createReplayProvider(turns) {
56389
56784
  }
56390
56785
  function collectToolNames(stream) {
56391
56786
  const names = /* @__PURE__ */ new Set();
56392
- for (const chunk of stream) {
56393
- if ((chunk.type === "tool_use_start" || chunk.type === "tool_use_end") && chunk.toolCall?.name) {
56394
- 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);
56395
56790
  }
56396
56791
  }
56397
56792
  return Array.from(names);
@@ -57775,7 +58170,6 @@ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
57775
58170
  "recall_memory",
57776
58171
  "list_memories",
57777
58172
  "list_checkpoints",
57778
- "spawnSimpleAgent",
57779
58173
  "checkAgentCapability"
57780
58174
  ]);
57781
58175
  var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
@@ -57821,6 +58215,22 @@ var DefaultPermissionPolicy = class {
57821
58215
  return { allowed: true, risk };
57822
58216
  }
57823
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
+ }
57824
58234
  if (tool.name !== "run_linter") {
57825
58235
  return this.canExecuteTool(mode, tool);
57826
58236
  }
@@ -57840,6 +58250,37 @@ var DefaultPermissionPolicy = class {
57840
58250
  function createPermissionPolicy() {
57841
58251
  return new DefaultPermissionPolicy();
57842
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
+ }
57843
58284
 
57844
58285
  // src/runtime/provider-registry.ts
57845
58286
  init_providers();
@@ -58146,19 +58587,26 @@ function createWorkflowCatalog(workflows) {
58146
58587
 
58147
58588
  // src/runtime/workflow-engine.ts
58148
58589
  var WorkflowEngine = class {
58149
- constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
58590
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog(), options = {}) {
58150
58591
  this.catalog = catalog;
58151
58592
  this.eventLog = eventLog;
58593
+ this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
58594
+ this.nodeExecutor = options.nodeExecutor;
58152
58595
  }
58153
58596
  catalog;
58154
58597
  eventLog;
58155
58598
  handlers = /* @__PURE__ */ new Map();
58599
+ sharedState;
58600
+ nodeExecutor;
58156
58601
  registerHandler(workflowId, handler) {
58157
58602
  if (!this.catalog.get(workflowId)) {
58158
58603
  throw new Error(`Unknown workflow: ${workflowId}`);
58159
58604
  }
58160
58605
  this.handlers.set(workflowId, handler);
58161
58606
  }
58607
+ registerNodeExecutor(executor) {
58608
+ this.nodeExecutor = executor;
58609
+ }
58162
58610
  createPlan(workflowId, input) {
58163
58611
  return this.catalog.createPlan(workflowId, input, this.eventLog);
58164
58612
  }
@@ -58168,23 +58616,35 @@ var WorkflowEngine = class {
58168
58616
  throw new Error(`Unknown workflow: ${request.workflowId}`);
58169
58617
  }
58170
58618
  const handler = this.handlers.get(request.workflowId);
58171
- if (!handler) {
58172
- throw new Error(`No handler registered for workflow: ${request.workflowId}`);
58173
- }
58174
58619
  const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
58175
58620
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
58176
58621
  const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
58622
+ const trace = createAgentTraceContext({ workflowRunId: runId });
58177
58623
  this.eventLog.record("workflow.started", {
58178
58624
  workflowId: request.workflowId,
58179
58625
  planId: plan.id,
58180
- runId
58626
+ runId,
58627
+ trace
58181
58628
  });
58182
58629
  try {
58183
- 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, {
58184
58641
  workflow,
58185
58642
  plan,
58186
58643
  eventLog: this.eventLog
58187
58644
  });
58645
+ if (graphResult?.status === "failed") {
58646
+ throw new Error(graphResult.error ?? "Workflow graph failed");
58647
+ }
58188
58648
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
58189
58649
  const result = {
58190
58650
  id: runId,
@@ -58192,12 +58652,15 @@ var WorkflowEngine = class {
58192
58652
  status: "completed",
58193
58653
  output,
58194
58654
  startedAt,
58195
- completedAt
58655
+ completedAt,
58656
+ graphResult,
58657
+ trace
58196
58658
  };
58197
58659
  this.eventLog.record("workflow.completed", {
58198
58660
  workflowId: request.workflowId,
58199
58661
  planId: plan.id,
58200
- runId
58662
+ runId,
58663
+ trace
58201
58664
  });
58202
58665
  return result;
58203
58666
  } catch (error) {
@@ -58207,7 +58670,8 @@ var WorkflowEngine = class {
58207
58670
  workflowId: request.workflowId,
58208
58671
  planId: plan.id,
58209
58672
  runId,
58210
- error: message
58673
+ error: message,
58674
+ trace
58211
58675
  });
58212
58676
  return {
58213
58677
  id: runId,
@@ -58216,13 +58680,14 @@ var WorkflowEngine = class {
58216
58680
  output: null,
58217
58681
  startedAt,
58218
58682
  completedAt,
58219
- error: message
58683
+ error: message,
58684
+ trace
58220
58685
  };
58221
58686
  }
58222
58687
  }
58223
58688
  };
58224
- function createWorkflowEngine(catalog, eventLog) {
58225
- return new WorkflowEngine(catalog, eventLog);
58689
+ function createWorkflowEngine(catalog, eventLog, options) {
58690
+ return new WorkflowEngine(catalog, eventLog, options);
58226
58691
  }
58227
58692
 
58228
58693
  // src/runtime/agent-runtime.ts
@@ -58400,7 +58865,7 @@ var AgentRuntime = class {
58400
58865
  let completed = false;
58401
58866
  let failed = false;
58402
58867
  try {
58403
- for await (const chunk of provider.stream(messages, {
58868
+ for await (const chunk2 of provider.stream(messages, {
58404
58869
  model: input.options?.model,
58405
58870
  maxTokens: input.options?.maxTokens,
58406
58871
  temperature: input.options?.temperature,
@@ -58410,12 +58875,12 @@ var AgentRuntime = class {
58410
58875
  signal: input.options?.signal,
58411
58876
  thinking: input.options?.thinking
58412
58877
  })) {
58413
- if (chunk.type === "text" && chunk.text) {
58414
- content += chunk.text;
58878
+ if (chunk2.type === "text" && chunk2.text) {
58879
+ content += chunk2.text;
58415
58880
  yield {
58416
58881
  type: "text",
58417
58882
  sessionId: effectiveSession.id,
58418
- text: chunk.text
58883
+ text: chunk2.text
58419
58884
  };
58420
58885
  }
58421
58886
  }
@@ -59853,12 +60318,12 @@ ${imagePrompts}`.trim() : imagePrompts;
59853
60318
  let lastToolGroup = null;
59854
60319
  await ensureRequestedMcpConnections(extractMessageText(effectiveMessage));
59855
60320
  const result = await executeAgentTurn(session, effectiveMessage, provider, toolRegistry, {
59856
- onStream: (chunk) => {
60321
+ onStream: (chunk2) => {
59857
60322
  if (!streamStarted) {
59858
60323
  streamStarted = true;
59859
60324
  clearSpinner();
59860
60325
  }
59861
- renderStreamChunk(chunk);
60326
+ renderStreamChunk(chunk2);
59862
60327
  },
59863
60328
  onToolStart: (tc, index, total) => {
59864
60329
  const desc = getToolRunningDescription(
@@ -60489,9 +60954,9 @@ async function readStdin() {
60489
60954
  const timeout = setTimeout(() => {
60490
60955
  resolve4("");
60491
60956
  }, 5e3);
60492
- process.stdin.on("data", (chunk) => {
60957
+ process.stdin.on("data", (chunk2) => {
60493
60958
  clearTimeout(timeout);
60494
- chunks.push(Buffer.from(chunk));
60959
+ chunks.push(Buffer.from(chunk2));
60495
60960
  });
60496
60961
  process.stdin.on("end", () => {
60497
60962
  clearTimeout(timeout);
@@ -60581,9 +61046,9 @@ ${stdinContent}
60581
61046
  const result = await executeAgentTurn(session, task, provider, toolRegistry, {
60582
61047
  skipConfirmation: true,
60583
61048
  // No interactive confirmations in headless mode
60584
- onStream: (chunk) => {
60585
- if (options.outputFormat === "text" && chunk.type === "text" && chunk.text) {
60586
- process.stdout.write(chunk.text);
61049
+ onStream: (chunk2) => {
61050
+ if (options.outputFormat === "text" && chunk2.type === "text" && chunk2.text) {
61051
+ process.stdout.write(chunk2.text);
60587
61052
  }
60588
61053
  }
60589
61054
  });