@corbat-tech/coco 2.37.0 → 2.38.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
@@ -43227,6 +43227,145 @@ Response format (JSON only, no prose):
43227
43227
  return spec;
43228
43228
  }
43229
43229
 
43230
+ // src/runtime/multi-agent.ts
43231
+ function createAgentArtifact(input) {
43232
+ return {
43233
+ ...input,
43234
+ id: input.id ?? `artifact-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
43235
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
43236
+ };
43237
+ }
43238
+ function createSummaryArtifact(output, metadata = {}) {
43239
+ return createAgentArtifact({
43240
+ kind: "summary",
43241
+ content: output,
43242
+ title: metadata.title ?? "Agent summary",
43243
+ agentRunId: metadata.agentRunId,
43244
+ taskId: metadata.taskId
43245
+ });
43246
+ }
43247
+ function normalizeAgentRunResult(input) {
43248
+ const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
43249
+ const startedAt = input.startedAt ?? completedAt;
43250
+ const status = input.status ?? (input.success ? "completed" : "failed");
43251
+ const artifacts = input.artifacts && input.artifacts.length > 0 ? input.artifacts.map(cloneArtifact) : [createSummaryArtifact(input.output, { agentRunId: input.id, taskId: input.taskId })];
43252
+ return {
43253
+ id: input.id,
43254
+ taskId: input.taskId,
43255
+ role: input.role,
43256
+ status,
43257
+ success: input.success,
43258
+ output: input.output,
43259
+ artifacts,
43260
+ toolsUsed: [...input.toolsUsed ?? []],
43261
+ turns: input.turns ?? 0,
43262
+ durationMs: input.durationMs ?? 0,
43263
+ usage: input.usage,
43264
+ error: input.error,
43265
+ startedAt,
43266
+ completedAt,
43267
+ metadata: input.metadata
43268
+ };
43269
+ }
43270
+ function validateAgentGraph(graph) {
43271
+ const issues = [];
43272
+ const nodeIds = /* @__PURE__ */ new Set();
43273
+ const gateIds = new Set((graph.gates ?? []).map((gate) => gate.id));
43274
+ if (graph.parallelism !== void 0 && graph.parallelism < 1) {
43275
+ issues.push({
43276
+ code: "invalid-parallelism",
43277
+ message: "Graph parallelism must be greater than zero."
43278
+ });
43279
+ }
43280
+ for (const node of graph.nodes) {
43281
+ if (nodeIds.has(node.id)) {
43282
+ issues.push({
43283
+ code: "duplicate-node",
43284
+ message: `Duplicate graph node '${node.id}'.`,
43285
+ nodeId: node.id
43286
+ });
43287
+ }
43288
+ nodeIds.add(node.id);
43289
+ if (node.retryPolicy && node.retryPolicy.maxAttempts < 1) {
43290
+ issues.push({
43291
+ code: "invalid-retry-policy",
43292
+ message: `Node '${node.id}' retry policy must allow at least one attempt.`,
43293
+ nodeId: node.id
43294
+ });
43295
+ }
43296
+ for (const dep of node.dependsOn ?? []) {
43297
+ if (!nodeIds.has(dep) && !graph.nodes.some((candidate) => candidate.id === dep)) {
43298
+ issues.push({
43299
+ code: "missing-dependency",
43300
+ message: `Node '${node.id}' depends on missing node '${dep}'.`,
43301
+ nodeId: node.id
43302
+ });
43303
+ }
43304
+ }
43305
+ for (const gate of node.gates ?? []) {
43306
+ if (!gateIds.has(gate)) {
43307
+ issues.push({
43308
+ code: "missing-gate",
43309
+ message: `Node '${node.id}' references missing gate '${gate}'.`,
43310
+ nodeId: node.id,
43311
+ gateId: gate
43312
+ });
43313
+ }
43314
+ }
43315
+ }
43316
+ for (const edge of graph.edges ?? []) {
43317
+ if (!nodeIds.has(edge.from)) {
43318
+ issues.push({
43319
+ code: "missing-edge-node",
43320
+ message: `Graph edge references missing source node '${edge.from}'.`,
43321
+ nodeId: edge.from
43322
+ });
43323
+ }
43324
+ if (!nodeIds.has(edge.to)) {
43325
+ issues.push({
43326
+ code: "missing-edge-node",
43327
+ message: `Graph edge references missing target node '${edge.to}'.`,
43328
+ nodeId: edge.to
43329
+ });
43330
+ }
43331
+ }
43332
+ const levels = buildExecutionLevels(graph, issues);
43333
+ return { valid: issues.length === 0, issues, levels };
43334
+ }
43335
+ function buildExecutionLevels(graph, issues) {
43336
+ const dependencies = /* @__PURE__ */ new Map();
43337
+ for (const node of graph.nodes) {
43338
+ dependencies.set(node.id, new Set(node.dependsOn ?? []));
43339
+ }
43340
+ for (const edge of graph.edges ?? []) {
43341
+ if (dependencies.has(edge.to)) {
43342
+ dependencies.get(edge.to).add(edge.from);
43343
+ }
43344
+ }
43345
+ const completed = /* @__PURE__ */ new Set();
43346
+ const levels = [];
43347
+ while (completed.size < dependencies.size) {
43348
+ const level = [...dependencies.entries()].filter(([id, deps]) => !completed.has(id) && [...deps].every((dep) => completed.has(dep))).map(([id]) => id);
43349
+ if (level.length === 0) {
43350
+ const remaining = [...dependencies.keys()].filter((id) => !completed.has(id));
43351
+ issues.push({
43352
+ code: "cycle",
43353
+ message: `Graph contains a cycle involving: ${remaining.join(", ")}.`
43354
+ });
43355
+ return levels;
43356
+ }
43357
+ for (const id of level) completed.add(id);
43358
+ levels.push(level);
43359
+ }
43360
+ return levels;
43361
+ }
43362
+ function cloneArtifact(artifact) {
43363
+ return {
43364
+ ...artifact,
43365
+ metadata: artifact.metadata ? { ...artifact.metadata } : void 0
43366
+ };
43367
+ }
43368
+
43230
43369
  // src/agents/executor.ts
43231
43370
  var AgentExecutor = class {
43232
43371
  constructor(provider, toolRegistry) {
@@ -43240,6 +43379,7 @@ var AgentExecutor = class {
43240
43379
  */
43241
43380
  async execute(agent, task) {
43242
43381
  const startTime = Date.now();
43382
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
43243
43383
  const toolsUsed = /* @__PURE__ */ new Set();
43244
43384
  const messages = [
43245
43385
  {
@@ -43250,6 +43390,8 @@ var AgentExecutor = class {
43250
43390
  const agentToolDefs = this.getToolDefinitionsForAgent(agent.allowedTools);
43251
43391
  let turn = 0;
43252
43392
  let totalTokens = 0;
43393
+ let totalInputTokens = 0;
43394
+ let totalOutputTokens = 0;
43253
43395
  while (turn < agent.maxTurns) {
43254
43396
  turn++;
43255
43397
  try {
@@ -43258,16 +43400,23 @@ var AgentExecutor = class {
43258
43400
  system: agent.systemPrompt
43259
43401
  });
43260
43402
  const usage = response.usage;
43403
+ totalInputTokens += usage?.inputTokens || 0;
43404
+ totalOutputTokens += usage?.outputTokens || 0;
43261
43405
  totalTokens += (usage?.inputTokens || 0) + (usage?.outputTokens || 0);
43262
43406
  if (response.stopReason !== "tool_use" || response.toolCalls.length === 0) {
43263
- return {
43407
+ return this.toAgentResult({
43408
+ agent,
43409
+ task,
43264
43410
  output: response.content,
43265
43411
  success: true,
43266
43412
  turns: turn,
43267
43413
  toolsUsed: Array.from(toolsUsed),
43268
43414
  tokensUsed: totalTokens,
43269
- duration: Date.now() - startTime
43270
- };
43415
+ inputTokens: totalInputTokens,
43416
+ outputTokens: totalOutputTokens,
43417
+ duration: Date.now() - startTime,
43418
+ startedAt
43419
+ });
43271
43420
  }
43272
43421
  const assistantContent = [];
43273
43422
  if (response.content) {
@@ -43313,24 +43462,38 @@ var AgentExecutor = class {
43313
43462
  content: toolResults
43314
43463
  });
43315
43464
  } catch (error) {
43316
- return {
43317
- output: `Agent error on turn ${turn}: ${error instanceof Error ? error.message : String(error)}`,
43465
+ const output2 = `Agent error on turn ${turn}: ${error instanceof Error ? error.message : String(error)}`;
43466
+ return this.toAgentResult({
43467
+ agent,
43468
+ task,
43469
+ output: output2,
43318
43470
  success: false,
43319
43471
  turns: turn,
43320
43472
  toolsUsed: Array.from(toolsUsed),
43321
43473
  tokensUsed: totalTokens,
43322
- duration: Date.now() - startTime
43323
- };
43474
+ inputTokens: totalInputTokens,
43475
+ outputTokens: totalOutputTokens,
43476
+ duration: Date.now() - startTime,
43477
+ startedAt,
43478
+ error: output2
43479
+ });
43324
43480
  }
43325
43481
  }
43326
- return {
43327
- output: "Agent reached maximum turns without completing task",
43482
+ const output = "Agent reached maximum turns without completing task";
43483
+ return this.toAgentResult({
43484
+ agent,
43485
+ task,
43486
+ output,
43328
43487
  success: false,
43329
43488
  turns: turn,
43330
43489
  toolsUsed: Array.from(toolsUsed),
43331
43490
  tokensUsed: totalTokens,
43332
- duration: Date.now() - startTime
43333
- };
43491
+ inputTokens: totalInputTokens,
43492
+ outputTokens: totalOutputTokens,
43493
+ duration: Date.now() - startTime,
43494
+ startedAt,
43495
+ error: output
43496
+ });
43334
43497
  }
43335
43498
  /**
43336
43499
  * Build task prompt with context
@@ -43356,7 +43519,36 @@ Complete this task autonomously using the available tools. When done, provide a
43356
43519
  if (allowedToolNames.length === 0) return allDefs;
43357
43520
  return allDefs.filter((def) => allowedToolNames.includes(def.name));
43358
43521
  }
43522
+ toAgentResult(input) {
43523
+ const structuredResult = normalizeAgentRunResult({
43524
+ id: `${input.task.id}-${Date.now().toString(36)}`,
43525
+ taskId: input.task.id,
43526
+ role: normalizeRole(input.agent.role),
43527
+ success: input.success,
43528
+ output: input.output,
43529
+ turns: input.turns,
43530
+ toolsUsed: input.toolsUsed,
43531
+ durationMs: input.duration,
43532
+ startedAt: input.startedAt,
43533
+ usage: { inputTokens: input.inputTokens, outputTokens: input.outputTokens },
43534
+ error: input.error,
43535
+ metadata: { legacyRole: input.agent.role }
43536
+ });
43537
+ return {
43538
+ output: input.output,
43539
+ success: input.success,
43540
+ turns: input.turns,
43541
+ toolsUsed: input.toolsUsed,
43542
+ tokensUsed: input.tokensUsed,
43543
+ duration: input.duration,
43544
+ artifacts: structuredResult.artifacts,
43545
+ structuredResult
43546
+ };
43547
+ }
43359
43548
  };
43549
+ function normalizeRole(role) {
43550
+ return role === "researcher" || role === "architect" || role === "editor" || role === "coder" || role === "tester" || role === "reviewer" || role === "optimizer" || role === "planner" ? role : "coder";
43551
+ }
43360
43552
  var AGENT_ROLES = {
43361
43553
  researcher: {
43362
43554
  role: "researcher",
@@ -44194,6 +44386,9 @@ var testTools = [runTestsTool, getCoverageTool, runTestFileTool];
44194
44386
  // src/tools/index.ts
44195
44387
  init_registry4();
44196
44388
 
44389
+ // src/tools/profiles.ts
44390
+ init_registry4();
44391
+
44197
44392
  // src/tools/file.ts
44198
44393
  init_registry4();
44199
44394
  init_errors();
@@ -45820,11 +46015,15 @@ var AgentManager = class extends EventEmitter {
45820
46015
  failedAgent.status = "failed";
45821
46016
  failedAgent.error = error;
45822
46017
  failedAgent.completedAt = /* @__PURE__ */ new Date();
45823
- return {
46018
+ return this.buildResult({
45824
46019
  agent: failedAgent,
45825
46020
  success: false,
45826
- output: error
45827
- };
46021
+ output: error,
46022
+ turns: 0,
46023
+ toolsUsed: [],
46024
+ startedAt: failedAgent.createdAt.toISOString(),
46025
+ usage: { inputTokens: 0, outputTokens: 0 }
46026
+ });
45828
46027
  }
45829
46028
  const agent = this.createAgent(type, task);
45830
46029
  this.activeAgents.set(agent.id, agent);
@@ -45876,11 +46075,15 @@ var AgentManager = class extends EventEmitter {
45876
46075
  options.onStatusChange?.(agent);
45877
46076
  this.logger.error(`Agent ${agent.id} failed unexpectedly`, { error: errorMessage });
45878
46077
  this.emitEvent("fail", agent);
45879
- return {
46078
+ return this.buildResult({
45880
46079
  agent,
45881
46080
  success: false,
45882
- output: errorMessage
45883
- };
46081
+ output: errorMessage,
46082
+ turns: 0,
46083
+ toolsUsed: [],
46084
+ startedAt: agent.createdAt.toISOString(),
46085
+ usage: { inputTokens: 0, outputTokens: 0 }
46086
+ });
45884
46087
  }
45885
46088
  }
45886
46089
  /**
@@ -46001,6 +46204,8 @@ var AgentManager = class extends EventEmitter {
46001
46204
  let finalOutput = "";
46002
46205
  let iteration = 0;
46003
46206
  const maxTurns = config.maxTurns ?? 10;
46207
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
46208
+ const toolsUsed = /* @__PURE__ */ new Set();
46004
46209
  while (iteration < maxTurns) {
46005
46210
  iteration++;
46006
46211
  if (options.signal?.aborted) {
@@ -46009,12 +46214,15 @@ var AgentManager = class extends EventEmitter {
46009
46214
  agent.completedAt = /* @__PURE__ */ new Date();
46010
46215
  this.moveToCompleted(agent.id);
46011
46216
  options.onStatusChange?.(agent);
46012
- return {
46217
+ return this.buildResult({
46013
46218
  agent,
46014
46219
  success: false,
46015
46220
  output: "Agent execution was aborted",
46221
+ turns: iteration,
46222
+ toolsUsed: Array.from(toolsUsed),
46223
+ startedAt,
46016
46224
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
46017
- };
46225
+ });
46018
46226
  }
46019
46227
  const response = await this.provider.chatWithTools(messages, {
46020
46228
  system: config.systemPrompt,
@@ -46031,7 +46239,7 @@ var AgentManager = class extends EventEmitter {
46031
46239
  messages.push({ role: "assistant", content: response.content });
46032
46240
  break;
46033
46241
  }
46034
- const toolResults = await this.executeToolCalls(response.toolCalls, config);
46242
+ const toolResults = await this.executeToolCalls(response.toolCalls, config, toolsUsed);
46035
46243
  const toolUses = response.toolCalls.map((tc) => ({
46036
46244
  type: "tool_use",
46037
46245
  id: tc.id,
@@ -46055,12 +46263,15 @@ var AgentManager = class extends EventEmitter {
46055
46263
  iterations: iteration,
46056
46264
  outputLength: finalOutput.length
46057
46265
  });
46058
- return {
46266
+ return this.buildResult({
46059
46267
  agent,
46060
46268
  success: true,
46061
46269
  output: finalOutput,
46270
+ turns: iteration,
46271
+ toolsUsed: Array.from(toolsUsed),
46272
+ startedAt,
46062
46273
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
46063
- };
46274
+ });
46064
46275
  }
46065
46276
  /**
46066
46277
  * Get tool definitions filtered for the agent's allowed tools
@@ -46073,10 +46284,11 @@ var AgentManager = class extends EventEmitter {
46073
46284
  /**
46074
46285
  * Execute tool calls and return results
46075
46286
  */
46076
- async executeToolCalls(toolCalls, config) {
46287
+ async executeToolCalls(toolCalls, config, toolsUsed) {
46077
46288
  const results = [];
46078
46289
  const allowedTools = new Set(config.tools);
46079
46290
  for (const toolCall of toolCalls) {
46291
+ toolsUsed.add(toolCall.name);
46080
46292
  if (!allowedTools.has(toolCall.name)) {
46081
46293
  results.push({
46082
46294
  type: "tool_result",
@@ -46117,6 +46329,33 @@ var AgentManager = class extends EventEmitter {
46117
46329
  this.abortControllers.delete(agentId);
46118
46330
  }
46119
46331
  }
46332
+ buildResult(input) {
46333
+ const structuredResult = normalizeAgentRunResult({
46334
+ id: `${input.agent.id}-run`,
46335
+ taskId: input.agent.id,
46336
+ role: agentTypeToRuntimeRole(input.agent.type),
46337
+ success: input.success,
46338
+ output: input.output,
46339
+ turns: input.turns,
46340
+ toolsUsed: input.toolsUsed,
46341
+ usage: input.usage,
46342
+ startedAt: input.startedAt,
46343
+ durationMs: input.agent.completedAt ? input.agent.completedAt.getTime() - input.agent.createdAt.getTime() : 0,
46344
+ status: input.success ? "completed" : "failed",
46345
+ error: input.success ? void 0 : input.agent.error,
46346
+ metadata: { agentType: input.agent.type }
46347
+ });
46348
+ return {
46349
+ agent: input.agent,
46350
+ success: input.success,
46351
+ output: input.output,
46352
+ artifacts: structuredResult.artifacts,
46353
+ structuredResult,
46354
+ toolsUsed: input.toolsUsed,
46355
+ turns: input.turns,
46356
+ usage: input.usage
46357
+ };
46358
+ }
46120
46359
  /**
46121
46360
  * Emit an agent event
46122
46361
  */
@@ -46126,6 +46365,31 @@ var AgentManager = class extends EventEmitter {
46126
46365
  this.emit("agent", event);
46127
46366
  }
46128
46367
  };
46368
+ 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
+ }
46392
+ }
46129
46393
 
46130
46394
  // src/agents/provider-bridge.ts
46131
46395
  var agentProvider = null;
@@ -57522,7 +57786,8 @@ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
57522
57786
  "delete_file",
57523
57787
  "restore_checkpoint",
57524
57788
  "git_commit",
57525
- "git_push"
57789
+ "git_push",
57790
+ "request_human_escalation"
57526
57791
  ]);
57527
57792
  function riskForTool(tool) {
57528
57793
  if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
@@ -57667,7 +57932,32 @@ function cloneWorkflow(workflow) {
57667
57932
  steps: workflow.steps.map((step) => ({
57668
57933
  ...step,
57669
57934
  requiredTools: [...step.requiredTools]
57670
- }))
57935
+ })),
57936
+ nodes: workflow.nodes?.map((node) => ({
57937
+ ...node,
57938
+ dependsOn: node.dependsOn ? [...node.dependsOn] : void 0,
57939
+ requiredTools: node.requiredTools ? [...node.requiredTools] : void 0,
57940
+ gates: node.gates ? [...node.gates] : void 0,
57941
+ retryPolicy: node.retryPolicy ? { ...node.retryPolicy } : void 0
57942
+ })),
57943
+ edges: workflow.edges?.map((edge) => ({ ...edge })),
57944
+ gates: workflow.gates?.map((gate) => ({ ...gate })),
57945
+ retryPolicy: workflow.retryPolicy ? { ...workflow.retryPolicy } : void 0
57946
+ };
57947
+ }
57948
+ function workflowToAgentGraph(workflow) {
57949
+ const nodes = workflow.nodes ?? workflow.steps.map((step, index) => ({
57950
+ id: step.id,
57951
+ description: step.description,
57952
+ requiredTools: [...step.requiredTools],
57953
+ risk: step.risk,
57954
+ dependsOn: index > 0 ? [workflow.steps[index - 1].id] : []
57955
+ }));
57956
+ return {
57957
+ nodes,
57958
+ edges: workflow.edges,
57959
+ gates: workflow.gates,
57960
+ parallelism: workflow.parallelism
57671
57961
  };
57672
57962
  }
57673
57963
  var WorkflowCatalog = class {
@@ -57678,6 +57968,12 @@ var WorkflowCatalog = class {
57678
57968
  }
57679
57969
  }
57680
57970
  register(workflow) {
57971
+ const validation = validateAgentGraph(workflowToAgentGraph(workflow));
57972
+ if (!validation.valid) {
57973
+ throw new Error(
57974
+ `Invalid workflow graph for '${workflow.id}': ${validation.issues.map((issue) => issue.message).join("; ")}`
57975
+ );
57976
+ }
57681
57977
  this.workflows.set(workflow.id, cloneWorkflow(workflow));
57682
57978
  }
57683
57979
  get(id) {
@@ -57703,7 +57999,8 @@ var WorkflowCatalog = class {
57703
57999
  workflowId,
57704
58000
  planId: plan.id,
57705
58001
  replayable: workflow.replayable,
57706
- checks: workflow.checks
58002
+ checks: workflow.checks,
58003
+ graphLevels: validateAgentGraph(workflowToAgentGraph(workflow)).levels
57707
58004
  });
57708
58005
  return plan;
57709
58006
  }
@@ -58298,6 +58595,118 @@ async function createAgentRuntime(options) {
58298
58595
  return runtime;
58299
58596
  }
58300
58597
 
58598
+ // src/runtime/tool-calling-turn-runner.ts
58599
+ function runtimeWithTools(runtime) {
58600
+ if (runtime && typeof runtime === "object" && "executeTool" in runtime && typeof runtime.executeTool === "function") {
58601
+ return runtime;
58602
+ }
58603
+ throw new Error("ToolCallingRuntimeTurnRunner requires a runtime with executeTool().");
58604
+ }
58605
+ function toolResultToContent(result) {
58606
+ if (!result.success) {
58607
+ return `Error: ${result.error ?? "Tool failed."}`;
58608
+ }
58609
+ if (typeof result.output === "string") return result.output;
58610
+ return JSON.stringify(result.output ?? null);
58611
+ }
58612
+ var ToolCallingRuntimeTurnRunner = class {
58613
+ maxToolIterations;
58614
+ constructor(options = {}) {
58615
+ this.maxToolIterations = options.maxToolIterations ?? 10;
58616
+ }
58617
+ async run(input, context) {
58618
+ const runtime = runtimeWithTools(context.runtime);
58619
+ const messages = [
58620
+ ...context.session.messages,
58621
+ {
58622
+ role: "user",
58623
+ content: input.content
58624
+ }
58625
+ ];
58626
+ const tools = context.toolRegistry.getToolDefinitionsForLLM();
58627
+ const confirmedTools = new Set(input.confirmedTools ?? []);
58628
+ let inputTokens = 0;
58629
+ let outputTokens = 0;
58630
+ let lastModel = input.options?.model ?? context.provider.id;
58631
+ for (let iteration = 0; iteration < this.maxToolIterations; iteration++) {
58632
+ const response = await context.provider.chatWithTools(messages, {
58633
+ tools,
58634
+ model: input.options?.model,
58635
+ maxTokens: input.options?.maxTokens,
58636
+ temperature: input.options?.temperature,
58637
+ stopSequences: input.options?.stopSequences,
58638
+ system: context.session.instructions ?? input.options?.system,
58639
+ timeout: input.options?.timeout,
58640
+ signal: input.options?.signal,
58641
+ thinking: input.options?.thinking
58642
+ });
58643
+ inputTokens += response.usage.inputTokens;
58644
+ outputTokens += response.usage.outputTokens;
58645
+ lastModel = response.model;
58646
+ if (response.stopReason !== "tool_use" || response.toolCalls.length === 0) {
58647
+ return {
58648
+ sessionId: context.session.id,
58649
+ content: response.content,
58650
+ usage: { inputTokens, outputTokens },
58651
+ model: response.model,
58652
+ mode: context.session.mode
58653
+ };
58654
+ }
58655
+ const assistantContent = [];
58656
+ if (response.content.trim().length > 0) {
58657
+ assistantContent.push({ type: "text", text: response.content });
58658
+ }
58659
+ for (const toolCall of response.toolCalls) {
58660
+ assistantContent.push({
58661
+ type: "tool_use",
58662
+ id: toolCall.id,
58663
+ name: toolCall.name,
58664
+ input: toolCall.input,
58665
+ geminiThoughtSignature: toolCall.geminiThoughtSignature
58666
+ });
58667
+ }
58668
+ messages.push({
58669
+ role: "assistant",
58670
+ content: assistantContent
58671
+ });
58672
+ const toolResults = [];
58673
+ for (const toolCall of response.toolCalls) {
58674
+ const result = await runtime.executeTool({
58675
+ sessionId: context.session.id,
58676
+ mode: context.session.mode,
58677
+ toolName: toolCall.name,
58678
+ input: toolCall.input,
58679
+ confirmed: confirmedTools.has(toolCall.name),
58680
+ metadata: input.metadata
58681
+ });
58682
+ toolResults.push({
58683
+ type: "tool_result",
58684
+ tool_use_id: toolCall.id,
58685
+ content: toolResultToContent(result),
58686
+ is_error: !result.success
58687
+ });
58688
+ }
58689
+ messages.push({
58690
+ role: "user",
58691
+ content: toolResults
58692
+ });
58693
+ }
58694
+ return {
58695
+ sessionId: context.session.id,
58696
+ content: "The tool-calling runtime reached its maximum tool iteration budget.",
58697
+ usage: { inputTokens, outputTokens },
58698
+ model: lastModel,
58699
+ mode: context.session.mode
58700
+ };
58701
+ }
58702
+ };
58703
+ function createToolCallingRuntimeTurnRunner(options) {
58704
+ return new ToolCallingRuntimeTurnRunner(options);
58705
+ }
58706
+
58707
+ // src/runtime/blueprints.ts
58708
+ init_registry4();
58709
+
58301
58710
  // src/cli/repl/index.ts
58302
58711
  init_version();
58303
58712
  init_trust_store();
@@ -60132,12 +60541,43 @@ ${stdinContent}
60132
60541
  model: session.config.provider.model || void 0,
60133
60542
  provider,
60134
60543
  eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
60544
+ turnRunner: options.useRuntimeRunner ? createToolCallingRuntimeTurnRunner() : void 0,
60135
60545
  publishToGlobalBridge: true
60136
60546
  });
60137
60547
  session.runtime = runtime;
60138
60548
  const toolRegistry = runtime.toolRegistry;
60139
60549
  await loadAllowedPaths(options.projectPath);
60140
60550
  await initializeContextManager(session, provider);
60551
+ if (options.useRuntimeRunner) {
60552
+ const runtimeSession = runtime.createSession({
60553
+ id: session.id,
60554
+ mode: "build",
60555
+ instructions: session.config.agent.systemPrompt || void 0,
60556
+ metadata: {
60557
+ surface: "cli",
60558
+ product: "coco-code",
60559
+ execution: "headless-runtime-runner"
60560
+ }
60561
+ });
60562
+ const result2 = await runtime.runTurn({
60563
+ sessionId: runtimeSession.id,
60564
+ content: task,
60565
+ metadata: { surface: "cli", product: "coco-code" }
60566
+ });
60567
+ const events = runtime.eventLog.list();
60568
+ const headlessResult2 = {
60569
+ success: true,
60570
+ output: result2.content,
60571
+ toolsExecuted: events.filter((event) => event.type === "tool.completed").length,
60572
+ usage: result2.usage
60573
+ };
60574
+ if (options.outputFormat === "json") {
60575
+ process.stdout.write(JSON.stringify(headlessResult2, null, 2) + "\n");
60576
+ } else {
60577
+ process.stdout.write(result2.content + "\n");
60578
+ }
60579
+ return headlessResult2;
60580
+ }
60141
60581
  const result = await executeAgentTurn(session, task, provider, toolRegistry, {
60142
60582
  skipConfirmation: true,
60143
60583
  // No interactive confirmations in headless mode
@@ -60203,7 +60643,10 @@ program.command("setup").description("Configure AI provider and API key").action
60203
60643
  console.log("\n\u274C Setup cancelled.");
60204
60644
  }
60205
60645
  });
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(
60646
+ 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(
60647
+ "--runtime-runner",
60648
+ "Experimental: run headless tasks through the reusable runtime tool-calling runner"
60649
+ ).option("--output <format>", "Output format for headless mode (text or json)", "text").option("--setup", "Run setup wizard before starting").action(
60207
60650
  async (options) => {
60208
60651
  if (options.setup) {
60209
60652
  const result = await runOnboardingV2();
@@ -60220,6 +60663,7 @@ program.command("chat", { isDefault: true }).description("Start interactive chat
60220
60663
  task,
60221
60664
  projectPath: options.path,
60222
60665
  outputFormat: options.output === "json" ? "json" : "text",
60666
+ useRuntimeRunner: options.runtimeRunner === true,
60223
60667
  config: {
60224
60668
  provider: {
60225
60669
  type: providerType,