@rowan-agent/agent 0.30.0 → 0.32.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/runtime.js CHANGED
@@ -29,7 +29,7 @@ function snapshotMessages(messages) {
29
29
  return messages.map(snapshotMessage);
30
30
  }
31
31
 
32
- // src/types.ts
32
+ // src/loop/messages.ts
33
33
  function createMessage(role, content, metadata) {
34
34
  return {
35
35
  id: createId("msg"),
@@ -47,9 +47,6 @@ function contentBlocksToMessageContent(blocks) {
47
47
  if (block.type === "thinking") {
48
48
  return { type: "thinking", thinking: block.thinking, ...block.signature ? { signature: block.signature } : {} };
49
49
  }
50
- if (block.type === "image") {
51
- return { type: "image", data: block.data, mimeType: block.mimeType };
52
- }
53
50
  if (block.type === "tool_call") {
54
51
  let input = block.args;
55
52
  try {
@@ -419,11 +416,7 @@ async function invokeModel(input) {
419
416
  });
420
417
  const response = result.doneResponse ?? {
421
418
  content: result.text,
422
- toolCalls: result.toolCalls.map((tc) => ({
423
- id: tc.id,
424
- name: tc.name,
425
- arguments: tc.args
426
- })),
419
+ toolCalls: result.toolCalls,
427
420
  stopReason: result.stopReason
428
421
  };
429
422
  return {
@@ -578,11 +571,7 @@ async function collectStreamResult(input) {
578
571
  throw new EmptyResponseError();
579
572
  }
580
573
  if (doneResponse) {
581
- const toolCalls2 = (doneResponse.toolCalls ?? []).map((tc) => ({
582
- id: tc.id,
583
- name: tc.name,
584
- args: tc.arguments
585
- }));
574
+ const toolCalls2 = doneResponse.toolCalls ?? [];
586
575
  return {
587
576
  text: doneResponse.content,
588
577
  contentBlocks: lastPartial?.contentBlocks ?? [],
@@ -599,7 +588,7 @@ async function collectStreamResult(input) {
599
588
  parsedArgs = JSON.parse(b.args);
600
589
  } catch {
601
590
  }
602
- return { id: b.id, name: b.name, args: parsedArgs };
591
+ return { id: b.id, name: b.name, arguments: parsedArgs };
603
592
  });
604
593
  return { text, contentBlocks, toolCalls, stopReason };
605
594
  }
@@ -1424,9 +1413,7 @@ function createRouteTool(availablePhases) {
1424
1413
  instruction: Type2.Optional(Type2.String({ description: "Overall instruction, passed as context" }))
1425
1414
  }),
1426
1415
  // No-op: this tool is intercepted by phases, never executed via tool execution
1427
- execute: async (_, context) => ({
1428
- toolCallId: context.toolCallId,
1429
- toolName: PhaseRouteTool,
1416
+ execute: async () => ({
1430
1417
  ok: true,
1431
1418
  content: ""
1432
1419
  })
@@ -1436,16 +1423,17 @@ function extractRouteCall(toolCalls) {
1436
1423
  const routeCalls = toolCalls.filter((t) => t.name === PhaseRouteTool);
1437
1424
  if (routeCalls.length !== 1) return void 0;
1438
1425
  const routeCall = routeCalls[0];
1426
+ const callArgs = routeCall.arguments !== void 0 ? routeCall.arguments : routeCall.args;
1439
1427
  let args;
1440
- if (typeof routeCall.args === "string") {
1428
+ if (typeof callArgs === "string") {
1441
1429
  try {
1442
- const parsed = JSON.parse(routeCall.args);
1430
+ const parsed = JSON.parse(callArgs);
1443
1431
  args = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
1444
1432
  } catch {
1445
1433
  return { decision: [{ phase: "" }] };
1446
1434
  }
1447
1435
  } else {
1448
- args = routeCall.args !== null && typeof routeCall.args === "object" ? routeCall.args : {};
1436
+ args = callArgs !== null && typeof callArgs === "object" ? callArgs : {};
1449
1437
  }
1450
1438
  const decisionRaw = args.decision;
1451
1439
  let decision = [];
@@ -1526,21 +1514,24 @@ async function runInternalModelLoop(context, execution, phase, options) {
1526
1514
  };
1527
1515
  for (let attempt = 0; attempt < maxRounds && result.toolCalls.length > 0; attempt += 1) {
1528
1516
  if (!result.toolCalls.some((call) => isAllowedTool(call.name))) break;
1529
- const normalizedCalls = result.toolCalls.map((call) => ({
1530
- ...call,
1531
- args: typeof call.args === "string" ? (() => {
1532
- try {
1533
- return JSON.parse(call.args);
1534
- } catch {
1535
- return call.args;
1536
- }
1537
- })() : call.args
1538
- }));
1517
+ const normalizedCalls = result.toolCalls.map((call) => {
1518
+ const callArgs = call.arguments;
1519
+ return {
1520
+ ...call,
1521
+ arguments: typeof callArgs === "string" ? (() => {
1522
+ try {
1523
+ return JSON.parse(callArgs);
1524
+ } catch {
1525
+ return callArgs;
1526
+ }
1527
+ })() : callArgs
1528
+ };
1529
+ });
1539
1530
  const toolUseParts = normalizedCalls.map((call) => ({
1540
1531
  type: "tool_use",
1541
1532
  id: call.id,
1542
1533
  name: call.name,
1543
- input: call.args
1534
+ input: call.arguments
1544
1535
  }));
1545
1536
  const assistantContent = result.contentBlocks.length > 0 ? contentBlocksToMessageContent(result.contentBlocks) : result.text ? [{ type: "text", text: result.text }, ...toolUseParts] : toolUseParts;
1546
1537
  working.messages.push(createMessage("assistant", assistantContent, {
@@ -1774,20 +1765,12 @@ function resolveCoreToolPath(context, path = ".") {
1774
1765
  };
1775
1766
  }
1776
1767
  function toolResult(input) {
1777
- return {
1778
- toolCallId: input.context.toolCallId,
1779
- toolName: input.toolName,
1780
- ok: input.ok,
1781
- content: input.content,
1782
- ...input.error ? { error: input.error } : {}
1783
- };
1768
+ return input.ok ? { ok: true, content: input.content } : { ok: false, content: input.content, error: input.error ?? "Tool execution failed" };
1784
1769
  }
1785
1770
  async function executeRuntimeToolCall(input) {
1786
1771
  const tool = input.tools.find((candidate) => candidate.name === input.toolCall.name);
1787
1772
  if (!tool) {
1788
1773
  const result = toolResult({
1789
- context: input.toolContext,
1790
- toolName: input.toolCall.name,
1791
1774
  ok: false,
1792
1775
  content: null,
1793
1776
  error: `Unknown tool: ${input.toolCall.name}`
@@ -1797,11 +1780,10 @@ async function executeRuntimeToolCall(input) {
1797
1780
  }
1798
1781
  let args;
1799
1782
  try {
1800
- args = validatorFor(tool.parameters).Parse(input.toolCall.args);
1783
+ const rawArgs = input.toolCall.arguments;
1784
+ args = validatorFor(tool.parameters).Parse(rawArgs);
1801
1785
  } catch (error) {
1802
1786
  const result = toolResult({
1803
- context: input.toolContext,
1804
- toolName: tool.name,
1805
1787
  ok: false,
1806
1788
  content: null,
1807
1789
  error: error instanceof Error ? error.message : String(error)
@@ -1810,12 +1792,14 @@ async function executeRuntimeToolCall(input) {
1810
1792
  return result;
1811
1793
  }
1812
1794
  let decision;
1795
+ const effectiveSignal = input.signal ?? new AbortController().signal;
1813
1796
  if (input.beforeToolCall) {
1814
1797
  await input.observe?.({ type: "approval_requested", tool, args });
1815
1798
  decision = await input.beforeToolCall({
1816
1799
  tool,
1817
1800
  args,
1818
- toolCallId: input.toolCall.id
1801
+ context: input.toolContext,
1802
+ signal: effectiveSignal
1819
1803
  });
1820
1804
  if (decision && "allow" in decision) {
1821
1805
  await input.observe?.({
@@ -1828,8 +1812,6 @@ async function executeRuntimeToolCall(input) {
1828
1812
  }
1829
1813
  if (decision && "interaction" in decision) {
1830
1814
  const result = toolResult({
1831
- context: input.toolContext,
1832
- toolName: tool.name,
1833
1815
  ok: false,
1834
1816
  content: null,
1835
1817
  error: `Tool interaction required: ${decision.interaction.prompt}`
@@ -1839,8 +1821,6 @@ async function executeRuntimeToolCall(input) {
1839
1821
  }
1840
1822
  if (decision && "allow" in decision && !decision.allow) {
1841
1823
  const result = toolResult({
1842
- context: input.toolContext,
1843
- toolName: tool.name,
1844
1824
  ok: false,
1845
1825
  content: null,
1846
1826
  error: decision.reason
@@ -1850,14 +1830,25 @@ async function executeRuntimeToolCall(input) {
1850
1830
  }
1851
1831
  await input.observe?.({ type: "tool_start", tool, args });
1852
1832
  try {
1853
- let result = await tool.execute(args, input.toolContext, input.signal);
1833
+ let result = await tool.execute(args, input.toolContext, effectiveSignal);
1834
+ if (!("ok" in result)) {
1835
+ result = { ok: !result.isError, ...result };
1836
+ }
1854
1837
  if (input.afterToolCall) {
1855
1838
  await input.observe?.({
1856
1839
  type: "result_review_requested",
1857
1840
  tool,
1858
1841
  result
1859
1842
  });
1860
- result = await input.afterToolCall({ tool, result });
1843
+ result = await input.afterToolCall({
1844
+ tool,
1845
+ result,
1846
+ context: input.toolContext,
1847
+ signal: effectiveSignal
1848
+ });
1849
+ if (!("ok" in result)) {
1850
+ result = { ok: !result.isError, ...result };
1851
+ }
1861
1852
  await input.observe?.({
1862
1853
  type: "result_review_result",
1863
1854
  tool,
@@ -1868,8 +1859,6 @@ async function executeRuntimeToolCall(input) {
1868
1859
  return result;
1869
1860
  } catch (error) {
1870
1861
  const result = toolResult({
1871
- context: input.toolContext,
1872
- toolName: tool.name,
1873
1862
  ok: false,
1874
1863
  content: null,
1875
1864
  error: error instanceof Error ? error.message : "Tool execution failed."
@@ -1952,8 +1941,6 @@ function createReadTool(context) {
1952
1941
  const limitError = parsed.limit === void 0 ? void 0 : positiveInteger(parsed.limit, "limit");
1953
1942
  if (offsetError || limitError) {
1954
1943
  return toolResult({
1955
- context: toolContext,
1956
- toolName: "read",
1957
1944
  ok: false,
1958
1945
  content: null,
1959
1946
  error: offsetError ?? limitError
@@ -1964,8 +1951,6 @@ function createReadTool(context) {
1964
1951
  const invalidLimit = positiveNumber(maxBytes, "maxBytes");
1965
1952
  if (invalidLimit) {
1966
1953
  return toolResult({
1967
- context: toolContext,
1968
- toolName: "read",
1969
1954
  ok: false,
1970
1955
  content: null,
1971
1956
  error: invalidLimit
@@ -1976,8 +1961,6 @@ function createReadTool(context) {
1976
1961
  fileStat = await stat(resolved.absolutePath);
1977
1962
  } catch (error) {
1978
1963
  return toolResult({
1979
- context: toolContext,
1980
- toolName: "read",
1981
1964
  ok: false,
1982
1965
  content: null,
1983
1966
  error: error instanceof Error ? error.message : String(error)
@@ -1985,8 +1968,6 @@ function createReadTool(context) {
1985
1968
  }
1986
1969
  if (!fileStat.isFile()) {
1987
1970
  return toolResult({
1988
- context: toolContext,
1989
- toolName: "read",
1990
1971
  ok: false,
1991
1972
  content: null,
1992
1973
  error: `Not a file: ${resolved.relativePath}`
@@ -1997,8 +1978,6 @@ function createReadTool(context) {
1997
1978
  bytes = await readFile2(resolved.absolutePath);
1998
1979
  } catch (error) {
1999
1980
  return toolResult({
2000
- context: toolContext,
2001
- toolName: "read",
2002
1981
  ok: false,
2003
1982
  content: null,
2004
1983
  error: error instanceof Error ? error.message : String(error)
@@ -2039,8 +2018,6 @@ function createReadTool(context) {
2039
2018
  Showing lines ${requestedOffset}-${selectedLineEnd} of ${sourceLines.length}. Use offset=${selectedLineEnd + 1} to continue.`;
2040
2019
  }
2041
2020
  return toolResult({
2042
- context: toolContext,
2043
- toolName: "read",
2044
2021
  ok: true,
2045
2022
  content
2046
2023
  });
@@ -2060,8 +2037,6 @@ function createWriteTool(context) {
2060
2037
  await mkdir(dirname4(resolved.absolutePath), { recursive: true });
2061
2038
  await writeFile(resolved.absolutePath, parsed.content, "utf8");
2062
2039
  return toolResult({
2063
- context: toolContext,
2064
- toolName: "write",
2065
2040
  ok: true,
2066
2041
  content: `Successfully wrote ${parsed.content.length} bytes to ${resolved.relativePath}.`
2067
2042
  });
@@ -2118,8 +2093,6 @@ function createEditTool(context) {
2118
2093
  replacements = result.replacements;
2119
2094
  } catch (error) {
2120
2095
  return toolResult({
2121
- context: toolContext,
2122
- toolName: "edit",
2123
2096
  ok: false,
2124
2097
  content: null,
2125
2098
  error: error instanceof Error ? error.message : String(error)
@@ -2127,8 +2100,6 @@ function createEditTool(context) {
2127
2100
  }
2128
2101
  await writeFile(resolved.absolutePath, next, "utf8");
2129
2102
  return toolResult({
2130
- context: toolContext,
2131
- toolName: "edit",
2132
2103
  ok: true,
2133
2104
  content: `Successfully replaced ${replacements} block(s) in ${resolved.relativePath}.`
2134
2105
  });
@@ -2150,8 +2121,6 @@ function createBashTool(context) {
2150
2121
  const invalidOutputLimit = positiveNumber(maxOutputBytes, "maxOutputBytes");
2151
2122
  if (invalidTimeout || invalidOutputLimit) {
2152
2123
  return toolResult({
2153
- context: toolContext,
2154
- toolName: "bash",
2155
2124
  ok: false,
2156
2125
  content: null,
2157
2126
  error: invalidTimeout ?? invalidOutputLimit
@@ -2193,8 +2162,6 @@ function createBashTool(context) {
2193
2162
 
2194
2163
  [Full result: ${archivePath}, offset 0]`;
2195
2164
  return toolResult({
2196
- context: toolContext,
2197
- toolName: "bash",
2198
2165
  ok,
2199
2166
  content,
2200
2167
  ...ok ? {} : {
@@ -2318,7 +2285,7 @@ function buildModelRequest(input, options) {
2318
2285
  const modelTools = input.tools.map((t) => ({
2319
2286
  name: t.name,
2320
2287
  description: t.description,
2321
- parameters: t.parameters
2288
+ parameters: t.parameters ?? {}
2322
2289
  }));
2323
2290
  return {
2324
2291
  model: options?.model ?? { provider: "", id: "" },
@@ -2336,12 +2303,18 @@ function parseToolResult(content) {
2336
2303
  try {
2337
2304
  const parsed = JSON.parse(content);
2338
2305
  if (typeof parsed.toolCallId === "string" && typeof parsed.toolName === "string" && typeof parsed.ok === "boolean") {
2339
- return {
2306
+ const base = {
2340
2307
  toolCallId: parsed.toolCallId,
2341
2308
  toolName: parsed.toolName,
2342
- ok: parsed.ok,
2343
- content: parsed.content,
2344
- ...parsed.error ? { error: parsed.error } : {}
2309
+ content: parsed.content ?? null
2310
+ };
2311
+ if (parsed.ok) {
2312
+ return { ...base, ok: true };
2313
+ }
2314
+ return {
2315
+ ...base,
2316
+ ok: false,
2317
+ error: typeof parsed.error === "string" ? parsed.error : "Tool execution failed."
2345
2318
  };
2346
2319
  }
2347
2320
  } catch {
@@ -2383,17 +2356,12 @@ var createOutcome = {
2383
2356
  default(output, transcript) {
2384
2357
  const toolResults = transcript ? extractToolResults(transcript) : [];
2385
2358
  const message = output.message || output.routeReason || `${output.phase ?? "Unknown"} phase completed.`;
2386
- const outcome = {
2359
+ return {
2387
2360
  id: createId("out"),
2388
- message
2361
+ message,
2362
+ ...output.payload !== void 0 ? { payload: output.payload } : {},
2363
+ ...toolResults.length > 0 ? { toolResults } : {}
2389
2364
  };
2390
- if (output.payload !== void 0) {
2391
- outcome.payload = output.payload;
2392
- }
2393
- if (toolResults.length > 0) {
2394
- outcome.toolResults = toolResults;
2395
- }
2396
- return outcome;
2397
2365
  },
2398
2366
  phase(output, transcript) {
2399
2367
  return {
@@ -2638,7 +2606,7 @@ function createToolResultContent(result) {
2638
2606
  {
2639
2607
  type: "tool_result",
2640
2608
  toolUseId: result.toolCallId,
2641
- content: JSON.stringify(result),
2609
+ content: typeof result.content === "string" ? result.content : JSON.stringify(result),
2642
2610
  isError: !result.ok
2643
2611
  }
2644
2612
  ];
@@ -2959,7 +2927,7 @@ async function runPhaseLoop(config, state, registry) {
2959
2927
  previousPhaseInputMsgId = void 0;
2960
2928
  if (extBefore.skip.route === "stop") {
2961
2929
  return completeRun(config, state, {
2962
- id: "skip",
2930
+ id: createId("out"),
2963
2931
  message: extBefore.skip.message || "Skipped."
2964
2932
  });
2965
2933
  }
@@ -3209,6 +3177,25 @@ async function executePhase(ctx) {
3209
3177
  }
3210
3178
  return executePhaseWithModel(ctx);
3211
3179
  }
3180
+ function inertRunInteraction(signal) {
3181
+ const controller = signal ? void 0 : new AbortController();
3182
+ const state = {
3183
+ currentPhase: "default",
3184
+ attempt: 0,
3185
+ status: "running",
3186
+ metrics: { iterations: 0, phaseTransitions: [], compactionCount: 0, retryCount: 0, startedAt: (/* @__PURE__ */ new Date()).toISOString(), startedAtMs: Date.now() }
3187
+ };
3188
+ const driver = createRunInteractionDriver(state, "default", signal ?? controller.signal);
3189
+ return {
3190
+ ...driver,
3191
+ request: () => {
3192
+ throw new Error("Run interactions require an active interaction driver.");
3193
+ },
3194
+ suspend: () => {
3195
+ throw new Error("Run interactions require an active interaction driver.");
3196
+ }
3197
+ };
3198
+ }
3212
3199
  async function executeToolCall(input) {
3213
3200
  let result;
3214
3201
  if (input.config.runtime?.tools) {
@@ -3222,14 +3209,20 @@ async function executeToolCall(input) {
3222
3209
  ...input.phase !== void 0 ? { phase: input.phase } : {}
3223
3210
  });
3224
3211
  } else {
3225
- const toolContext = {
3226
- skills: input.config.context.skills,
3227
- toolCallId: input.toolCall.id
3212
+ const toolInvocationContext = {
3213
+ agentId: input.config.execution.agentId,
3214
+ runId: input.config.execution.runId,
3215
+ toolCallId: input.toolCall.id,
3216
+ providerToolCallId: input.toolCall.id,
3217
+ reportProgress: () => {
3218
+ },
3219
+ interaction: input.driver ?? inertRunInteraction(input.config.signal),
3220
+ ...input.phase !== void 0 ? { phase: input.phase } : {}
3228
3221
  };
3229
3222
  result = await executeRuntimeToolCall({
3230
3223
  tools: input.tools,
3231
3224
  toolCall: input.toolCall,
3232
- toolContext,
3225
+ toolContext: toolInvocationContext,
3233
3226
  beforeToolCall: input.config.beforeToolCall,
3234
3227
  afterToolCall: input.config.afterToolCall,
3235
3228
  signal: combineSignals(input.config.signal, input.options?.signal)
@@ -3273,7 +3266,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3273
3266
  const interaction = createRunInteractionDriver(state, phase.name, config.signal);
3274
3267
  const executePhaseTool = async (phaseContext, toolCall, options, providerInitiated = false) => {
3275
3268
  return runTurn(async () => {
3276
- await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.args);
3269
+ await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.arguments);
3277
3270
  const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
3278
3271
  const result = await executeToolCall({
3279
3272
  config: {
@@ -3320,7 +3313,8 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3320
3313
  request.tools = phaseContext.tools.map((t) => ({
3321
3314
  name: t.name,
3322
3315
  description: t.description,
3323
- parameters: t.parameters
3316
+ parameters: t.parameters,
3317
+ ...t._meta !== void 0 ? { _meta: t._meta } : {}
3324
3318
  }));
3325
3319
  }
3326
3320
  }
@@ -3347,7 +3341,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3347
3341
  return tools.map((t) => ({
3348
3342
  name: t.name,
3349
3343
  description: t.description,
3350
- parameters: t.parameters,
3344
+ parameters: t.parameters ?? {},
3351
3345
  ...t._meta !== void 0 ? { _meta: t._meta } : {}
3352
3346
  }));
3353
3347
  },
@@ -3356,10 +3350,11 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3356
3350
  const toolCall = {
3357
3351
  id: toolCallId,
3358
3352
  name,
3359
- args
3353
+ arguments: args
3360
3354
  };
3361
3355
  const res = await executePhaseTool(phaseContext, toolCall, options2, true);
3362
- return res.ok ? { ok: true, content: res.content } : { ok: false, error: res.error ?? "Tool execution failed", ...res.content !== void 0 ? { content: res.content } : {} };
3356
+ const { toolCallId: _id, toolName: _name, ...result2 } = res;
3357
+ return result2;
3363
3358
  }
3364
3359
  }
3365
3360
  };
@@ -3403,7 +3398,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3403
3398
  return runTurn(async () => {
3404
3399
  const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
3405
3400
  for (const toolCall of toolCalls) {
3406
- await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.args);
3401
+ await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.arguments);
3407
3402
  }
3408
3403
  const results = await executeToolCalls({
3409
3404
  config: {
@@ -3938,16 +3933,8 @@ function assertToolExecutionResult(value) {
3938
3933
  var CORE_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "edit", "write", "bash"]);
3939
3934
  function createRuntimeCoreTools(input = {}) {
3940
3935
  return createCoreTools(input).map((tool) => ({
3941
- name: tool.name,
3942
- core: true,
3943
- description: tool.description,
3944
- parameters: tool.parameters,
3945
- ...tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {},
3946
- ...tool.promptGuidelines ? { promptGuidelines: tool.promptGuidelines } : {},
3947
- execute: async (args, context, signal) => {
3948
- const result = await tool.execute(args, { skills: [], toolCallId: context.toolCallId }, signal);
3949
- return result.ok ? { ok: true, content: result.content } : { ok: false, content: result.content, error: result.error ?? "Tool failed." };
3950
- }
3936
+ ...tool,
3937
+ core: true
3951
3938
  }));
3952
3939
  }
3953
3940
 
@@ -4608,7 +4595,7 @@ function projectModelContext(input) {
4608
4595
  return {
4609
4596
  systemPrompt: input.context.systemPrompt,
4610
4597
  messages: projectedMessages,
4611
- tools: input.context.tools.map((tool) => projectTool(tool, input.agentId, input.runId)),
4598
+ tools: [...input.context.tools],
4612
4599
  skills: [...input.context.skills],
4613
4600
  ...input.context.phases ? { phases: input.context.phases } : {}
4614
4601
  };
@@ -4713,48 +4700,6 @@ function projectToolContent(content) {
4713
4700
  };
4714
4701
  });
4715
4702
  }
4716
- function inertRunInteraction(signal) {
4717
- const controller = signal ? void 0 : new AbortController();
4718
- const state = {
4719
- currentPhase: "default",
4720
- attempt: 0,
4721
- status: "running",
4722
- metrics: { iterations: 0, phaseTransitions: [], compactionCount: 0, retryCount: 0, startedAt: (/* @__PURE__ */ new Date()).toISOString(), startedAtMs: Date.now() }
4723
- };
4724
- const driver = createRunInteractionDriver(state, "default", signal ?? controller.signal);
4725
- return {
4726
- ...driver,
4727
- request: () => {
4728
- throw new Error("Run interactions require an active interaction driver.");
4729
- },
4730
- suspend: () => {
4731
- throw new Error("Run interactions require an active interaction driver.");
4732
- }
4733
- };
4734
- }
4735
- function projectTool(tool, agentId, runId) {
4736
- return {
4737
- name: tool.name,
4738
- ...tool.core ? { core: true } : {},
4739
- description: tool.description,
4740
- parameters: tool.parameters,
4741
- ...tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {},
4742
- ...tool.promptGuidelines ? { promptGuidelines: [...tool.promptGuidelines] } : {},
4743
- ...tool._meta !== void 0 ? { _meta: tool._meta } : {},
4744
- execute: async (args, context, signal) => {
4745
- const result = await tool.execute(args, {
4746
- agentId,
4747
- runId,
4748
- toolCallId: context.toolCallId,
4749
- providerToolCallId: context.toolCallId,
4750
- reportProgress: () => void 0,
4751
- interaction: context.interaction ?? inertRunInteraction(signal)
4752
- }, signal ?? new AbortController().signal);
4753
- const ok = "ok" in result && typeof result.ok === "boolean" ? result.ok : !result.isError;
4754
- return { toolCallId: context.toolCallId, toolName: tool.name, ok, ...result };
4755
- }
4756
- };
4757
- }
4758
4703
  function jsonText(value) {
4759
4704
  return typeof value === "string" ? value : JSON.stringify(value) ?? "null";
4760
4705
  }
@@ -4779,8 +4724,7 @@ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
4779
4724
  afterPhase: (phaseId, output) => runner.emitAfterPhase(phaseId, output),
4780
4725
  beforePrompt: (phaseId, input) => runner.emitBeforePrompt(phaseId, input),
4781
4726
  beforeToolCall: async (input) => {
4782
- const tool = projectTool(input.tool, input.context.agentId, input.context.runId);
4783
- const decision = await runner.emitBeforeToolCall(tool, input.args, {
4727
+ const decision = await runner.emitBeforeToolCall(input.tool, input.args, {
4784
4728
  runId: input.context.runId,
4785
4729
  agentId: input.context.agentId,
4786
4730
  toolCallId: input.context.toolCallId,
@@ -4797,10 +4741,9 @@ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
4797
4741
  return decision.allow ? { allow: true } : { allow: false, reason: decision.reason ?? "Extension hook rejected the Tool." };
4798
4742
  },
4799
4743
  afterToolCall: async (input) => {
4800
- const tool = projectTool(input.tool, input.context.agentId, input.context.runId);
4801
- const result = await runner.emitAfterToolCall(
4802
- tool,
4803
- toLoopResult(input.result, input.context.toolCallId, input.tool.name),
4744
+ return runner.emitAfterToolCall(
4745
+ input.tool,
4746
+ input.result,
4804
4747
  {
4805
4748
  runId: input.context.runId,
4806
4749
  agentId: input.context.agentId,
@@ -4811,7 +4754,6 @@ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
4811
4754
  ...input.context.phase === void 0 ? {} : { phase: input.context.phase }
4812
4755
  }
4813
4756
  );
4814
- return fromLoopResult(result);
4815
4757
  },
4816
4758
  setContext: (context2) => {
4817
4759
  runner.currentContext = context2;
@@ -4853,35 +4795,6 @@ function resolveDefinitionContext(snapshot, assembled, runner, scope) {
4853
4795
  ...snapshot.cwd ? { cwd: snapshot.cwd } : {}
4854
4796
  };
4855
4797
  }
4856
- function toLoopResult(result, toolCallId, toolName) {
4857
- const ok = "ok" in result && typeof result.ok === "boolean" ? result.ok : !result.isError;
4858
- const error = "error" in result && typeof result.error === "string" ? result.error : void 0;
4859
- return {
4860
- toolCallId,
4861
- toolName,
4862
- ok,
4863
- content: result.content,
4864
- ...!ok && error ? { error } : {},
4865
- ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
4866
- ...result.isError !== void 0 ? { isError: result.isError } : {}
4867
- };
4868
- }
4869
- function fromLoopResult(result) {
4870
- if (Array.isArray(result.content)) {
4871
- return {
4872
- content: result.content,
4873
- ...result.ok !== void 0 ? { ok: result.ok } : {},
4874
- ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
4875
- ...result.isError !== void 0 ? { isError: result.isError } : !result.ok ? { isError: true } : {},
4876
- ...result.error !== void 0 ? { error: result.error } : {}
4877
- };
4878
- }
4879
- return {
4880
- ...result.ok ? { ok: true } : { ok: false, error: result.error ?? "Extension hook rejected the Tool result." },
4881
- content: result.content,
4882
- ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
4883
- };
4884
- }
4885
4798
 
4886
4799
  // src/runtime/session-files.ts
4887
4800
  import { appendFileSync, chmodSync, existsSync as existsSync3, mkdirSync, readFileSync } from "fs";
@@ -7535,6 +7448,11 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
7535
7448
  if (!agentsDelegate) throw new Error("AgentRuntime is not available in this extension context.");
7536
7449
  return agentsDelegate.listRuns({ agentId, ...filter });
7537
7450
  },
7451
+ run: async (runId) => {
7452
+ assertActive();
7453
+ if (!agentsDelegate) throw new Error("AgentRuntime is not available in this extension context.");
7454
+ return agentsDelegate.snapshot(runId);
7455
+ },
7538
7456
  runPhase: async (agentId, runOpt) => {
7539
7457
  assertActive();
7540
7458
  if (!agentsDelegate) throw new Error("AgentRuntime is not available in this extension context.");
@@ -10538,7 +10456,7 @@ var AgentRuntime = class _AgentRuntime {
10538
10456
  options.onUpdate(createMergedToolCall(
10539
10457
  toolCallId2,
10540
10458
  "failed",
10541
- { rawInput: toJsonValue(toolCall.args) },
10459
+ { rawInput: toolCallArgs(toolCall) },
10542
10460
  toolCall.name,
10543
10461
  "other"
10544
10462
  ));
@@ -10549,8 +10467,6 @@ var AgentRuntime = class _AgentRuntime {
10549
10467
  }
10550
10468
  if (!controller.signal.aborted && isCancel) {
10551
10469
  return {
10552
- toolCallId: toolCall.id,
10553
- toolName: toolCall.name,
10554
10470
  ok: false,
10555
10471
  content: null,
10556
10472
  error: reason
@@ -10681,7 +10597,7 @@ var AgentRuntime = class _AgentRuntime {
10681
10597
  }
10682
10598
  if (result.type === "completed") {
10683
10599
  const output2 = latestAssistant(run, result.messages, executionContext.messages.length);
10684
- await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...output2 ? { output: output2 } : {} });
10600
+ await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: result.outcome, ...output2 ? { output: output2 } : {} });
10685
10601
  this.transientEvents.clear(run.id, claim.execution.executionId, true);
10686
10602
  await this.handleRunEnd(run.id, run.agentId, result.outcome);
10687
10603
  return;
@@ -10808,7 +10724,7 @@ var AgentRuntime = class _AgentRuntime {
10808
10724
  try {
10809
10725
  const decision = await input.toolConfig.beforeToolCall({
10810
10726
  tool: durableTool,
10811
- args: toJsonValue(toolCall.args),
10727
+ args: toolCallArgs(toolCall),
10812
10728
  context,
10813
10729
  signal: input.signal
10814
10730
  });
@@ -10825,7 +10741,7 @@ var AgentRuntime = class _AgentRuntime {
10825
10741
  const startPresentations = await Promise.all(
10826
10742
  input.toolCalls.map(async (tc) => {
10827
10743
  const t = input.toolConfig.tools.find((c) => c.name === tc.name);
10828
- return t ? presentToolPending(t, toJsonValue(tc.args)) : void 0;
10744
+ return t ? presentToolPending(t, toolCallArgs(tc)) : void 0;
10829
10745
  })
10830
10746
  );
10831
10747
  const reserved = await this.owned.reserveToolCalls({
@@ -10840,7 +10756,7 @@ var AgentRuntime = class _AgentRuntime {
10840
10756
  toolCallId: toolCallIds[i],
10841
10757
  providerToolCallId: tc.id,
10842
10758
  name: tc.name,
10843
- args: toJsonValue(tc.args),
10759
+ args: toolCallArgs(tc),
10844
10760
  ...startPresentations[i] ?? {}
10845
10761
  }))
10846
10762
  });
@@ -10852,8 +10768,6 @@ var AgentRuntime = class _AgentRuntime {
10852
10768
  const providerToolCallId = toolCall.id;
10853
10769
  const toolCallId = toolCallIds[i];
10854
10770
  const protocolFailure = (error) => ({
10855
- toolCallId: providerToolCallId,
10856
- toolName: toolCall.name,
10857
10771
  ok: false,
10858
10772
  content: null,
10859
10773
  error
@@ -10894,11 +10808,11 @@ var AgentRuntime = class _AgentRuntime {
10894
10808
  title: durableTool.annotations?.title ?? durableTool.name,
10895
10809
  kind: durableTool.kind ?? "other"
10896
10810
  },
10897
- rawInput: toJsonValue(toolCall.args)
10811
+ rawInput: toolCallArgs(toolCall)
10898
10812
  };
10899
10813
  const inProgressPres = await presentToolCall(durableTool, {
10900
10814
  status: "in_progress",
10901
- args: toJsonValue(toolCall.args)
10815
+ args: toolCallArgs(toolCall)
10902
10816
  });
10903
10817
  if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
10904
10818
  const started = await this.owned.startToolCall({
@@ -10958,8 +10872,6 @@ var AgentRuntime = class _AgentRuntime {
10958
10872
  const isReserved = Boolean(active?.reservedToolCalls.has(toolCallId));
10959
10873
  const isStarted = Boolean(active?.startedToolCalls.has(toolCallId));
10960
10874
  const protocolFailure = (error) => ({
10961
- toolCallId: providerToolCallId,
10962
- toolName: toolCall.name,
10963
10875
  ok: false,
10964
10876
  content: null,
10965
10877
  error
@@ -10978,7 +10890,7 @@ var AgentRuntime = class _AgentRuntime {
10978
10890
  toolCallId,
10979
10891
  providerToolCallId,
10980
10892
  name: toolCall.name,
10981
- args: toJsonValue(toolCall.args)
10893
+ args: toolCallArgs(toolCall)
10982
10894
  }]
10983
10895
  });
10984
10896
  setRevision(reserved.run.revision);
@@ -10998,15 +10910,15 @@ var AgentRuntime = class _AgentRuntime {
10998
10910
  results.push(protocolFailure(`Tool ${toolCall.name} is not available.`));
10999
10911
  continue;
11000
10912
  }
11001
- const pendingPres = await presentToolPending(durableTool, toJsonValue(toolCall.args));
10913
+ const pendingPres = await presentToolPending(durableTool, toolCallArgs(toolCall));
11002
10914
  const currentToolState = {
11003
10915
  ...pendingPres,
11004
- rawInput: toJsonValue(toolCall.args)
10916
+ rawInput: toolCallArgs(toolCall)
11005
10917
  };
11006
10918
  const resumedStart = suspension && index === suspension.pendingIndex ? await (async () => {
11007
10919
  const inProgressPres = await presentToolCall(durableTool, {
11008
10920
  status: "in_progress",
11009
- args: toJsonValue(toolCall.args)
10921
+ args: toolCallArgs(toolCall)
11010
10922
  });
11011
10923
  if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
11012
10924
  return this.owned.startToolCall({
@@ -11055,7 +10967,7 @@ var AgentRuntime = class _AgentRuntime {
11055
10967
  if (input.toolConfig.beforeToolCall) {
11056
10968
  const decision = await input.toolConfig.beforeToolCall({
11057
10969
  tool: durableTool,
11058
- args: toJsonValue(toolCall.args),
10970
+ args: toolCallArgs(toolCall),
11059
10971
  context,
11060
10972
  signal: input.signal,
11061
10973
  answer
@@ -11078,7 +10990,7 @@ var AgentRuntime = class _AgentRuntime {
11078
10990
  toolCallId,
11079
10991
  providerToolCallId,
11080
10992
  name: toolCall.name,
11081
- args: toJsonValue(toolCall.args),
10993
+ args: toolCallArgs(toolCall),
11082
10994
  ...pendingPres
11083
10995
  }]
11084
10996
  });
@@ -11101,7 +11013,7 @@ var AgentRuntime = class _AgentRuntime {
11101
11013
  toolCallId,
11102
11014
  providerToolCallId,
11103
11015
  name: toolCall.name,
11104
- args: toJsonValue(toolCall.args),
11016
+ args: toolCallArgs(toolCall),
11105
11017
  ...pendingPres
11106
11018
  }]
11107
11019
  });
@@ -11157,7 +11069,7 @@ var AgentRuntime = class _AgentRuntime {
11157
11069
  toolCallId,
11158
11070
  providerToolCallId,
11159
11071
  name: toolCall.name,
11160
- args: toJsonValue(toolCall.args),
11072
+ args: toolCallArgs(toolCall),
11161
11073
  ...pendingPres
11162
11074
  }]
11163
11075
  });
@@ -11208,7 +11120,7 @@ var AgentRuntime = class _AgentRuntime {
11208
11120
  toolCallId,
11209
11121
  providerToolCallId,
11210
11122
  name: toolCall.name,
11211
- args: toJsonValue(toolCall.args),
11123
+ args: toolCallArgs(toolCall),
11212
11124
  ...pendingPres
11213
11125
  }]
11214
11126
  });
@@ -11217,7 +11129,7 @@ var AgentRuntime = class _AgentRuntime {
11217
11129
  }
11218
11130
  const inProgressPres = await presentToolCall(durableTool, {
11219
11131
  status: "in_progress",
11220
- args: toJsonValue(toolCall.args)
11132
+ args: toolCallArgs(toolCall)
11221
11133
  });
11222
11134
  if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
11223
11135
  const started = await this.owned.startToolCall({
@@ -11330,7 +11242,7 @@ var AgentRuntime = class _AgentRuntime {
11330
11242
  if (!progressActive || this.closed || effectiveSignal.aborted) return;
11331
11243
  const pres = await presentToolCall(input.durableTool, {
11332
11244
  status: "in_progress",
11333
- args: toJsonValue(input.toolCall.args),
11245
+ args: toolCallArgs(input.toolCall),
11334
11246
  progress: copy
11335
11247
  });
11336
11248
  if (pres) {
@@ -11366,9 +11278,12 @@ var AgentRuntime = class _AgentRuntime {
11366
11278
  throw error;
11367
11279
  }
11368
11280
  let result = await withAbort(
11369
- input.durableTool.execute(toJsonValue(input.toolCall.args), context, effectiveSignal),
11281
+ input.durableTool.execute(toolCallArgs(input.toolCall), context, effectiveSignal),
11370
11282
  input.options?.signal
11371
11283
  );
11284
+ if (!("ok" in result)) {
11285
+ result = { ok: !result.isError, ...result };
11286
+ }
11372
11287
  assertToolExecutionResult(result);
11373
11288
  if (input.afterToolCall) {
11374
11289
  result = await input.afterToolCall({
@@ -11377,6 +11292,9 @@ var AgentRuntime = class _AgentRuntime {
11377
11292
  context,
11378
11293
  signal: effectiveSignal
11379
11294
  });
11295
+ if (!("ok" in result)) {
11296
+ result = { ok: !result.isError, ...result };
11297
+ }
11380
11298
  }
11381
11299
  assertToolExecutionResult(result);
11382
11300
  result = await spillLargeToolResult(
@@ -11386,10 +11304,10 @@ var AgentRuntime = class _AgentRuntime {
11386
11304
  );
11387
11305
  await progressQueue.catch(() => {
11388
11306
  });
11389
- const finalState = result.ok ? "completed" : "failed";
11307
+ const finalState = ("ok" in result ? result.ok : !result.isError) ? "completed" : "failed";
11390
11308
  const completionPres = await presentToolCall(input.durableTool, {
11391
11309
  status: finalState,
11392
- args: toJsonValue(input.toolCall.args),
11310
+ args: toolCallArgs(input.toolCall),
11393
11311
  result
11394
11312
  });
11395
11313
  if (completionPres) {
@@ -11423,13 +11341,7 @@ var AgentRuntime = class _AgentRuntime {
11423
11341
  );
11424
11342
  notifyUpdate(finalToolCall);
11425
11343
  const projectedResult = await this.foldToolInteractionRecords(result, input.toolCallId, input.agentId);
11426
- const ok = "ok" in projectedResult && typeof projectedResult.ok === "boolean" ? projectedResult.ok : !projectedResult.isError;
11427
- return {
11428
- toolCallId: input.providerToolCallId,
11429
- toolName: input.toolCall.name,
11430
- ...projectedResult,
11431
- ok
11432
- };
11344
+ return projectedResult;
11433
11345
  } catch (error) {
11434
11346
  if (error instanceof RunInteractionBoundary) {
11435
11347
  if (!input.providerInitiated) {
@@ -11450,7 +11362,7 @@ var AgentRuntime = class _AgentRuntime {
11450
11362
  });
11451
11363
  const failurePres = await presentToolCall(input.durableTool, {
11452
11364
  status: "failed",
11453
- args: toJsonValue(input.toolCall.args),
11365
+ args: toolCallArgs(input.toolCall),
11454
11366
  result: { ok: false, content: null, error: reason }
11455
11367
  });
11456
11368
  if (failurePres) {
@@ -11481,8 +11393,6 @@ var AgentRuntime = class _AgentRuntime {
11481
11393
  );
11482
11394
  notifyUpdate(finalToolCall);
11483
11395
  return {
11484
- toolCallId: input.providerToolCallId,
11485
- toolName: input.toolCall.name,
11486
11396
  ok: false,
11487
11397
  content: null,
11488
11398
  error: reason
@@ -11691,14 +11601,6 @@ function latestAssistant(run, messages, historyLength, interrupted = false) {
11691
11601
  function hasVisibleAssistantText(message) {
11692
11602
  return typeof message.content === "string" ? message.content.length > 0 : message.content.some((part) => part.type === "text" && part.text.length > 0);
11693
11603
  }
11694
- function durableOutcome(outcome) {
11695
- return {
11696
- id: outcome.id,
11697
- message: outcome.message,
11698
- ...outcome.payload === void 0 ? {} : { payload: outcome.payload },
11699
- ...outcome.toolResults === void 0 ? {} : { toolResults: outcome.toolResults }
11700
- };
11701
- }
11702
11604
  function boundaryFromSnapshot(snapshot) {
11703
11605
  switch (snapshot.state) {
11704
11606
  case "input_required":
@@ -11814,6 +11716,9 @@ function toJsonValue(value) {
11814
11716
  assertJsonValue(value, "tool arguments");
11815
11717
  return value;
11816
11718
  }
11719
+ function toolCallArgs(toolCall) {
11720
+ return toJsonValue(toolCall.arguments);
11721
+ }
11817
11722
  function createMergedToolCall(toolCallId, status, current, fallbackTitle, fallbackKind = "other") {
11818
11723
  return {
11819
11724
  toolCallId,