@rowan-agent/agent 0.14.1 → 0.14.3

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/index.d.ts CHANGED
@@ -545,7 +545,7 @@ type PhaseExecution = {
545
545
  }): Promise<ModelInvokeOutput>;
546
546
  reportStatus(status: PhaseStatus): Promise<void>;
547
547
  executeTool(context: AgentContext, toolCall: ToolCall): Promise<ToolResult>;
548
- executeTools(context: AgentContext, toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]>;
548
+ executeTools(context: AgentContext, toolCalls: readonly ToolCall[], contentBlocks?: readonly ContentBlock[]): Promise<readonly ToolResult[]>;
549
549
  interaction: RunInteractionDriver;
550
550
  /** Message lifecycle manager for streaming updates from programmatic phases */
551
551
  messages: PhaseMessageManager;
@@ -1442,6 +1442,8 @@ interface OwnedStore {
1442
1442
  expectedRevision: number;
1443
1443
  requestMessageId: MessageId;
1444
1444
  calls: readonly ToolCallReservation[];
1445
+ /** The model response's blocks, so the request message keeps what preceded the Tool Calls. */
1446
+ contentBlocks?: readonly ContentBlock[];
1445
1447
  }): Promise<ToolBatchCommit>;
1446
1448
  startToolCall(input: {
1447
1449
  runId: RunId;
@@ -2388,12 +2390,9 @@ declare class InMemoryStore implements DurableStore {
2388
2390
  execution: ExecutionToken;
2389
2391
  expectedRevision: number;
2390
2392
  requestMessageId: MessageId;
2391
- calls: readonly Readonly<{
2392
- providerToolCallId: string;
2393
- name: string;
2394
- args: JsonValue;
2395
- toolCallId?: ToolCallId;
2396
- }>[];
2393
+ calls: readonly ToolCallReservation[];
2394
+ /** The model response's blocks, so the request message keeps what preceded the Tool Calls. */
2395
+ contentBlocks?: readonly ContentBlock[];
2397
2396
  }): ToolBatchCommit;
2398
2397
  startToolCall(lease: OwnerLease, input: {
2399
2398
  runId: RunId;
@@ -2607,6 +2606,7 @@ declare class SqliteStore implements DurableStore {
2607
2606
  args: JsonValue;
2608
2607
  toolCallId?: ToolCallId;
2609
2608
  }>[];
2609
+ contentBlocks?: readonly ContentBlock[];
2610
2610
  }): Promise<ToolBatchCommit>;
2611
2611
  startToolCall(lease: OwnerLease, input: {
2612
2612
  runId: RunId;
package/dist/index.js CHANGED
@@ -2537,6 +2537,7 @@ async function executePhaseWithModel(ctx) {
2537
2537
  messages: ctx.messageManager.visible()
2538
2538
  };
2539
2539
  let executableToolCalls;
2540
+ let roundContentBlocks;
2540
2541
  const checkpoint = ctx.execution.interaction.checkpoint();
2541
2542
  if (checkpoint && typeof checkpoint === "object" && checkpoint.kind === "tool_call_suspension") {
2542
2543
  const toolSuspension = checkpoint;
@@ -2575,11 +2576,12 @@ async function executePhaseWithModel(ctx) {
2575
2576
  executableToolCalls = collected.toolCalls.filter(
2576
2577
  (toolCall) => executableToolNames.has(toolCall.name)
2577
2578
  );
2579
+ roundContentBlocks = collected.contentBlocks;
2578
2580
  if (executableToolCalls.length === 0) {
2579
2581
  return output;
2580
2582
  }
2581
2583
  }
2582
- const results = await ctx.execution.executeTools(roundContext, executableToolCalls);
2584
+ const results = await ctx.execution.executeTools(roundContext, executableToolCalls, roundContentBlocks);
2583
2585
  for (const result of results) {
2584
2586
  const messageId = ctx.messageManager.start("tool", createToolResultContent(result), {
2585
2587
  phase: ctx.phase.name
@@ -3055,6 +3057,7 @@ async function executeToolCall(input) {
3055
3057
  result = await input.config.runtime.tools({
3056
3058
  config: input.config,
3057
3059
  toolCall: input.toolCall,
3060
+ contentBlocks: input.contentBlocks,
3058
3061
  driver: input.driver
3059
3062
  });
3060
3063
  } else {
@@ -3082,6 +3085,7 @@ async function executeToolCalls(input) {
3082
3085
  const results2 = await input.config.runtime.toolsBatch({
3083
3086
  config: input.config,
3084
3087
  toolCalls: input.toolCalls,
3088
+ contentBlocks: input.contentBlocks,
3085
3089
  driver: input.driver
3086
3090
  });
3087
3091
  if (results2.length !== input.toolCalls.length) throw new Error("Runtime returned an invalid Tool batch result");
@@ -3187,7 +3191,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3187
3191
  return result;
3188
3192
  });
3189
3193
  },
3190
- async executeTools(phaseContext, toolCalls) {
3194
+ async executeTools(phaseContext, toolCalls, contentBlocks) {
3191
3195
  return runTurn(async () => {
3192
3196
  const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
3193
3197
  for (const toolCall of toolCalls) {
@@ -3204,6 +3208,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3204
3208
  },
3205
3209
  tools,
3206
3210
  toolCalls,
3211
+ contentBlocks,
3207
3212
  driver: interaction
3208
3213
  });
3209
3214
  for (const result of results) {
@@ -6531,7 +6536,7 @@ var AgentRuntime = class _AgentRuntime {
6531
6536
  },
6532
6537
  onContext: assembly.setContext,
6533
6538
  runtime: {
6534
- tools: ({ toolCall, driver }) => {
6539
+ tools: ({ toolCall, contentBlocks, driver }) => {
6535
6540
  const task = toolQueue.then(async () => {
6536
6541
  const execution = await this.executeToolBatch({
6537
6542
  run,
@@ -6540,6 +6545,7 @@ var AgentRuntime = class _AgentRuntime {
6540
6545
  expectedRevision: executionRevision,
6541
6546
  toolConfig: executionTools,
6542
6547
  toolCalls: [toolCall],
6548
+ contentBlocks,
6543
6549
  signal: controller.signal,
6544
6550
  driver,
6545
6551
  onRevision: (rev) => {
@@ -6552,7 +6558,7 @@ var AgentRuntime = class _AgentRuntime {
6552
6558
  toolQueue = task.then(() => void 0, () => void 0);
6553
6559
  return task;
6554
6560
  },
6555
- toolsBatch: ({ toolCalls, driver }) => {
6561
+ toolsBatch: ({ toolCalls, contentBlocks, driver }) => {
6556
6562
  const task = toolQueue.then(async () => {
6557
6563
  const execution = await this.executeToolBatch({
6558
6564
  run,
@@ -6561,6 +6567,7 @@ var AgentRuntime = class _AgentRuntime {
6561
6567
  expectedRevision: executionRevision,
6562
6568
  toolConfig: executionTools,
6563
6569
  toolCalls,
6570
+ contentBlocks,
6564
6571
  signal: controller.signal,
6565
6572
  driver,
6566
6573
  onRevision: (rev) => {
@@ -6617,7 +6624,7 @@ var AgentRuntime = class _AgentRuntime {
6617
6624
  const isToolCallInteraction = result.interactions?.some((i) => i.toolCallId !== void 0);
6618
6625
  const output = isToolCallInteraction ? void 0 : latestAssistant(
6619
6626
  run,
6620
- result.messages.slice(modelMessages.length),
6627
+ result.messages,
6621
6628
  modelMessages.length
6622
6629
  );
6623
6630
  const prompt = isToolCallInteraction ? void 0 : output ?? (result.interactions[0]?.prompt ? promptMessage(run, result.interactions[0].prompt, result.messages.length) : void 0);
@@ -6636,7 +6643,7 @@ var AgentRuntime = class _AgentRuntime {
6636
6643
  return;
6637
6644
  }
6638
6645
  if (result.type === "completed") {
6639
- const output = latestAssistant(run, result.messages.slice(modelMessages.length), modelMessages.length);
6646
+ const output = latestAssistant(run, result.messages, modelMessages.length);
6640
6647
  if (controlKind === "compact" || isCompactionOutcome(result.outcome.payload)) {
6641
6648
  const summary = compactSummary(result.outcome.payload);
6642
6649
  const instructions = compactInstructions2(run) ?? compactOutputInstructions(result.outcome.payload);
@@ -6676,7 +6683,12 @@ var AgentRuntime = class _AgentRuntime {
6676
6683
  execution: claim.execution,
6677
6684
  expectedRevision: executionRevision,
6678
6685
  failure: { code: "execution_failed", message: error instanceof Error ? error.message : "Execution failed." }
6679
- }).catch(() => void 0);
6686
+ }).catch(async (commitError) => {
6687
+ await this.owned.cancelRun({
6688
+ runId: run.id,
6689
+ reason: commitError instanceof Error ? commitError.message : "Run failure could not be committed."
6690
+ }).catch(() => void 0);
6691
+ });
6680
6692
  return;
6681
6693
  }
6682
6694
  throw error;
@@ -6756,6 +6768,7 @@ var AgentRuntime = class _AgentRuntime {
6756
6768
  execution: input.execution,
6757
6769
  expectedRevision: revision,
6758
6770
  requestMessageId: createId("msg"),
6771
+ contentBlocks: input.contentBlocks,
6759
6772
  calls: input.toolCalls.map((tc, i) => ({
6760
6773
  toolCallId: toolCallIds[i],
6761
6774
  providerToolCallId: tc.id,
@@ -6930,6 +6943,7 @@ var AgentRuntime = class _AgentRuntime {
6930
6943
  execution: input.execution,
6931
6944
  expectedRevision: revision,
6932
6945
  requestMessageId: createId("msg"),
6946
+ contentBlocks: input.contentBlocks,
6933
6947
  calls: [{
6934
6948
  toolCallId,
6935
6949
  providerToolCallId,
@@ -7012,6 +7026,7 @@ var AgentRuntime = class _AgentRuntime {
7012
7026
  execution: input.execution,
7013
7027
  expectedRevision: revision,
7014
7028
  requestMessageId: createId("msg"),
7029
+ contentBlocks: input.contentBlocks,
7015
7030
  calls: [{ toolCallId, providerToolCallId, name: toolCall.name, args: toJsonValue(toolCall.args) }]
7016
7031
  });
7017
7032
  setRevision(reserved2.run.revision);
@@ -7025,6 +7040,7 @@ var AgentRuntime = class _AgentRuntime {
7025
7040
  execution: input.execution,
7026
7041
  expectedRevision: revision,
7027
7042
  requestMessageId: createId("msg"),
7043
+ contentBlocks: input.contentBlocks,
7028
7044
  calls: [{ toolCallId, providerToolCallId, name: toolCall.name, args: toJsonValue(toolCall.args) }]
7029
7045
  });
7030
7046
  setRevision(reserved2.run.revision);
@@ -7053,6 +7069,7 @@ var AgentRuntime = class _AgentRuntime {
7053
7069
  execution: input.execution,
7054
7070
  expectedRevision: revision,
7055
7071
  requestMessageId: createId("msg"),
7072
+ contentBlocks: input.contentBlocks,
7056
7073
  calls: [{ toolCallId, providerToolCallId, name: toolCall.name, args: toJsonValue(toolCall.args) }]
7057
7074
  });
7058
7075
  setRevision(reserved2.run.revision);
@@ -7075,6 +7092,7 @@ var AgentRuntime = class _AgentRuntime {
7075
7092
  execution: input.execution,
7076
7093
  expectedRevision: revision,
7077
7094
  requestMessageId: createId("msg"),
7095
+ contentBlocks: input.contentBlocks,
7078
7096
  calls: [{ toolCallId, providerToolCallId, name: toolCall.name, args: toJsonValue(toolCall.args) }]
7079
7097
  });
7080
7098
  setRevision(committed.run.revision);
@@ -7326,10 +7344,10 @@ var DurableRun = class {
7326
7344
  function promptMessage(run, prompt, sequence) {
7327
7345
  return { id: createId("msg"), agentId: run.agentId, runId: run.id, role: "assistant", content: prompt, sequenceWithinRun: sequence, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
7328
7346
  }
7329
- function latestAssistant(run, messages, sequence, interrupted = false) {
7330
- const message = [...messages].reverse().find((candidate) => candidate.role === "assistant");
7347
+ function latestAssistant(run, messages, historyLength, interrupted = false) {
7348
+ const message = [...messages.slice(historyLength)].reverse().find((candidate) => candidate.role === "assistant");
7331
7349
  if (!message) return void 0;
7332
- return projectAssistantMessage(message, run.agentId, run.id, sequence, { interrupted });
7350
+ return projectAssistantMessage(message, run.agentId, run.id, historyLength, { interrupted });
7333
7351
  }
7334
7352
  function hasVisibleAssistantText(message) {
7335
7353
  return typeof message.content === "string" ? message.content.length > 0 : message.content.some((part) => part.type === "text" && part.text.length > 0);
@@ -7873,7 +7891,10 @@ var InMemoryStore = class _InMemoryStore {
7873
7891
  this.commitInteractionRecord(waitingRun, interaction, "replied", void 0, replyText);
7874
7892
  }
7875
7893
  delete waitingRun.openInteractions;
7876
- delete waitingRun.interactionAnswers;
7894
+ waitingRun.interactionAnswers = {
7895
+ ...waitingRun.interactionAnswers ?? {},
7896
+ ...Object.fromEntries(openInteractions.map(({ id }) => [id, { status: "replied", reply: replyText }]))
7897
+ };
7877
7898
  if (waitingRun.checkpoint?.data && typeof waitingRun.checkpoint.data === "object") {
7878
7899
  const stored = waitingRun.checkpoint.data.runInteractions ?? waitingRun.checkpoint.data.phaseInteractions;
7879
7900
  if (stored?.requests && Array.isArray(stored.requests)) {
@@ -8145,7 +8166,8 @@ var InMemoryStore = class _InMemoryStore {
8145
8166
  input.expectedRevision,
8146
8167
  input.execution.executionId,
8147
8168
  input.requestMessageId,
8148
- input.calls
8169
+ input.calls,
8170
+ input.contentBlocks ?? null
8149
8171
  ]);
8150
8172
  const replay = this.replayOperation(operationKey, operationPayload);
8151
8173
  if (replay) return clone(replay);
@@ -8174,13 +8196,7 @@ var InMemoryStore = class _InMemoryStore {
8174
8196
  agentId: run.agentId,
8175
8197
  runId: run.id,
8176
8198
  role: "assistant",
8177
- content: toolCalls.map((toolCall) => ({
8178
- type: "tool_use",
8179
- toolCallId: toolCall.id,
8180
- providerToolCallId: toolCall.providerToolCallId,
8181
- name: toolCall.name,
8182
- input: clone(toolCall.args)
8183
- })),
8199
+ content: requestMessageContent(toolCalls, input.contentBlocks),
8184
8200
  sequenceWithinRun: this.nextMessageSequence(run.id),
8185
8201
  createdAt: timestamp
8186
8202
  };
@@ -8344,6 +8360,8 @@ var InMemoryStore = class _InMemoryStore {
8344
8360
  const run = this.requireRun(input.runId);
8345
8361
  if (input.expectedRevision !== void 0) this.assertRevision(run, input.expectedRevision);
8346
8362
  if (input.output !== void 0) {
8363
+ const existing = this.messages.get(input.output.id);
8364
+ if (existing && existing.runId !== run.id) throw new TypeError("cancelled output message id belongs to another Run");
8347
8365
  if (!isAssistantMessage(input.output) || input.output.agentId !== run.agentId || input.output.runId !== run.id || input.output.interrupted !== true) {
8348
8366
  throw new TypeError("cancelled output must be an interrupted AssistantMessage from this Run");
8349
8367
  }
@@ -9004,6 +9022,32 @@ function digestToolEffects(toolCalls) {
9004
9022
  function assertToolValue(value, argument) {
9005
9023
  assertUtf8ByteLimit(canonicalJson(value), TOOL_VALUE_JSON_BYTES, argument);
9006
9024
  }
9025
+ function requestMessageContent(toolCalls, contentBlocks) {
9026
+ const toolUse = (toolCall) => ({
9027
+ type: "tool_use",
9028
+ toolCallId: toolCall.id,
9029
+ providerToolCallId: toolCall.providerToolCallId,
9030
+ name: toolCall.name,
9031
+ input: clone(toolCall.args)
9032
+ });
9033
+ if (!contentBlocks) return toolCalls.map(toolUse);
9034
+ const reserved = new Map(toolCalls.map((toolCall) => [toolCall.providerToolCallId, toolCall]));
9035
+ const parts = [];
9036
+ for (const block of contentBlocks) {
9037
+ if (block.type === "text") {
9038
+ parts.push({ type: "text", text: block.text });
9039
+ } else if (block.type === "thinking") {
9040
+ parts.push({ type: "thinking", thinking: block.thinking, ...block.signature ? { signature: block.signature } : {} });
9041
+ } else {
9042
+ const toolCall = reserved.get(block.id);
9043
+ if (!toolCall) continue;
9044
+ reserved.delete(block.id);
9045
+ parts.push(toolUse(toolCall));
9046
+ }
9047
+ }
9048
+ for (const toolCall of reserved.values()) parts.push(toolUse(toolCall));
9049
+ return parts;
9050
+ }
9007
9051
 
9008
9052
  // src/runtime/sqlite-durable-store.ts
9009
9053
  import { Database } from "bun:sqlite";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.14.1",
3
+ "version": "0.14.3",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,7 +23,7 @@
23
23
  "build": "tsup && bun scripts/check-public-interface.ts"
24
24
  },
25
25
  "dependencies": {
26
- "@rowan-agent/models": "0.7.0",
26
+ "@rowan-agent/models": "0.7.1",
27
27
  "jiti": "2.7.0",
28
28
  "typebox": "^1.0.0",
29
29
  "yaml": "^2.7.0"