@rowan-agent/agent 0.19.0 → 0.20.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +822 -805
  2. package/dist/index.js +278 -93
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1922,6 +1922,19 @@ function createRunInteractionDriver(state, phase, signal) {
1922
1922
  checkpoint = void 0;
1923
1923
  sync();
1924
1924
  },
1925
+ answer(id, value) {
1926
+ answers.set(id, value);
1927
+ const req = requests.get(id);
1928
+ if (req) {
1929
+ requests.set(id, { ...req, status: "answered", answer: value });
1930
+ }
1931
+ sync();
1932
+ },
1933
+ clearAnswer(id) {
1934
+ answers.delete(id);
1935
+ requests.delete(id);
1936
+ sync();
1937
+ },
1925
1938
  suspend(input = {}) {
1926
1939
  assertActive();
1927
1940
  const pending = this.pending();
@@ -2667,6 +2680,16 @@ function serializeSkills(skills) {
2667
2680
  function conversationMessages(messages) {
2668
2681
  return messages.flatMap((message) => {
2669
2682
  if (message.role === "user") {
2683
+ if (message.contexts && message.contexts.length > 0) {
2684
+ const turnContextText = `<turn_context>
2685
+ ${buildContextDescription(message.contexts)}
2686
+ </turn_context>`;
2687
+ const contentParts = [
2688
+ { type: "text", text: turnContextText },
2689
+ ...typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content
2690
+ ];
2691
+ return [{ role: "user", content: contentParts }];
2692
+ }
2670
2693
  return [{ role: "user", content: message.content }];
2671
2694
  }
2672
2695
  if (message.role === "assistant") {
@@ -2701,6 +2724,7 @@ function buildModelRequest(input, options) {
2701
2724
  return {
2702
2725
  model: options?.model ?? { provider: "", id: "" },
2703
2726
  ...options?.thinkingLevel === void 0 ? {} : { thinkingLevel: options.thinkingLevel },
2727
+ ...options?.providerOptions === void 0 ? {} : { providerOptions: options.providerOptions },
2704
2728
  system: systemText,
2705
2729
  messages,
2706
2730
  tools: modelTools.length > 0 ? modelTools : void 0
@@ -3607,7 +3631,8 @@ async function executeToolCall(input) {
3607
3631
  toolCall: input.toolCall,
3608
3632
  contentBlocks: input.contentBlocks,
3609
3633
  driver: input.driver,
3610
- options: input.options
3634
+ options: input.options,
3635
+ ...input.providerInitiated ? { providerInitiated: true } : {}
3611
3636
  });
3612
3637
  } else {
3613
3638
  const toolContext = {
@@ -3652,7 +3677,7 @@ async function executeToolCalls(input) {
3652
3677
  }
3653
3678
  function createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry) {
3654
3679
  const interaction = createRunInteractionDriver(state, phase.name, config.signal);
3655
- const executePhaseTool = async (phaseContext, toolCall, options) => {
3680
+ const executePhaseTool = async (phaseContext, toolCall, options, providerInitiated = false) => {
3656
3681
  return runTurn(async () => {
3657
3682
  await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.args);
3658
3683
  const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
@@ -3668,7 +3693,8 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3668
3693
  tools,
3669
3694
  toolCall,
3670
3695
  driver: interaction,
3671
- options
3696
+ options,
3697
+ providerInitiated
3672
3698
  });
3673
3699
  await toolExecutionManager.end(result.toolCallId, result.toolName, result, !result.ok);
3674
3700
  return result;
@@ -3706,7 +3732,8 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3706
3732
  appendSystemPrompt: phaseContext.appendSystemPrompt
3707
3733
  }, {
3708
3734
  model: phase.model ?? config.model,
3709
- ...config.thinkingLevel === void 0 ? {} : { thinkingLevel: config.thinkingLevel }
3735
+ ...config.thinkingLevel === void 0 ? {} : { thinkingLevel: config.thinkingLevel },
3736
+ ...config.providerOptions === void 0 ? {} : { providerOptions: config.providerOptions }
3710
3737
  });
3711
3738
  if (!request.tools) {
3712
3739
  if (phaseContext.tools.length > 0) {
@@ -3751,7 +3778,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3751
3778
  name,
3752
3779
  args
3753
3780
  };
3754
- const res = await executePhaseTool(phaseContext, toolCall, options2);
3781
+ const res = await executePhaseTool(phaseContext, toolCall, options2, true);
3755
3782
  return res.ok ? { ok: true, content: res.content } : { ok: false, error: res.error ?? "Tool execution failed", ...res.content !== void 0 ? { content: res.content } : {} };
3756
3783
  },
3757
3784
  report: (update) => {
@@ -4046,6 +4073,7 @@ async function executeOnce(input) {
4046
4073
  execution: input.execution,
4047
4074
  model: input.model,
4048
4075
  ...input.thinkingLevel === void 0 ? {} : { thinkingLevel: input.thinkingLevel },
4076
+ ...input.providerOptions === void 0 ? {} : { providerOptions: input.providerOptions },
4049
4077
  stream: input.stream,
4050
4078
  maxAttempts: input.maxAttempts,
4051
4079
  signal: input.signal,
@@ -4209,6 +4237,9 @@ var THINKING_LEVELS = [
4209
4237
  function thinkingLevelFromUserInput(input) {
4210
4238
  return typeof input === "string" ? void 0 : input.thinkingLevel;
4211
4239
  }
4240
+ function providerOptionsFromUserInput(input) {
4241
+ return typeof input === "string" ? void 0 : input.providerOptions;
4242
+ }
4212
4243
  var METADATA_LIMIT = 64 * 1024;
4213
4244
  var IDENTITY_LIMIT = 256;
4214
4245
  function isRecord3(value) {
@@ -4263,13 +4294,16 @@ function isAssistantContent(value) {
4263
4294
  }
4264
4295
  function normalizeUserInput(input) {
4265
4296
  const normalized = typeof input === "string" ? { content: input } : input;
4266
- if (!isRecord3(normalized) || !hasOnlyKeys(normalized, ["content", "metadata", "thinkingLevel"]) || !isUserContent(normalized.content)) {
4297
+ if (!isRecord3(normalized) || !hasOnlyKeys(normalized, ["content", "metadata", "thinkingLevel", "providerOptions"]) || !isUserContent(normalized.content)) {
4267
4298
  throw new TypeError("input must contain only valid UserContent");
4268
4299
  }
4269
4300
  if (normalized.metadata !== void 0) assertMetadata(normalized.metadata, "input.metadata");
4270
4301
  if (normalized.thinkingLevel !== void 0 && !THINKING_LEVELS.includes(normalized.thinkingLevel)) {
4271
4302
  throw new TypeError("input.thinkingLevel must be a valid ThinkingLevel");
4272
4303
  }
4304
+ if (normalized.providerOptions !== void 0 && (!isRecord3(normalized.providerOptions) || !isJsonValue(normalized.providerOptions))) {
4305
+ throw new TypeError("input.providerOptions must be a JSON object");
4306
+ }
4273
4307
  assertJsonValue(normalized, "input");
4274
4308
  return normalized;
4275
4309
  }
@@ -5000,7 +5034,14 @@ function durableInterruptedAssistantContent(content) {
5000
5034
  function projectMessage(message) {
5001
5035
  switch (message.role) {
5002
5036
  case "user":
5003
- return { id: message.id, role: message.role, content: projectUserContent(message.content), createdAt: message.createdAt, ...message.metadata ? { metadata: message.metadata } : {} };
5037
+ return {
5038
+ id: message.id,
5039
+ role: message.role,
5040
+ content: projectUserContent(message.content),
5041
+ createdAt: message.createdAt,
5042
+ ...message.metadata ? { metadata: message.metadata } : {},
5043
+ ...message.contexts && message.contexts.length > 0 ? { contexts: message.contexts } : {}
5044
+ };
5004
5045
  case "assistant":
5005
5046
  return { id: message.id, role: message.role, content: projectAssistantContent(message.content), createdAt: message.createdAt, ...message.metadata ? { metadata: message.metadata } : {} };
5006
5047
  case "tool":
@@ -5185,10 +5226,7 @@ function resolveDefinitionContext(snapshot, assembled) {
5185
5226
  selectNamedResources(snapshot.resources.skills, snapshot.definition.skills, "Skill"),
5186
5227
  snapshot.definition.bundledSkills
5187
5228
  );
5188
- const contexts = [
5189
- ...selectNamedResources(snapshot.contexts, snapshot.definition.contexts, "Context"),
5190
- ...snapshot.additionalContexts
5191
- ];
5229
+ const contexts = selectNamedResources(snapshot.contexts, snapshot.definition.contexts, "Context");
5192
5230
  const phaseCandidates = [...snapshot.resources.phases?.phases.values() ?? []];
5193
5231
  const corePhases = phaseCandidates.filter((phase) => phase.core);
5194
5232
  const authoredPhases = phaseCandidates.filter((phase) => !phase.core);
@@ -5340,7 +5378,6 @@ var TransientRunEventSubscription = class {
5340
5378
  stop() {
5341
5379
  if (this.stopped) return;
5342
5380
  this.stopped = true;
5343
- this.queue.length = 0;
5344
5381
  this.notify();
5345
5382
  }
5346
5383
  notify() {
@@ -7217,6 +7254,8 @@ function createToolInteractionDriver(driver, input) {
7217
7254
  answers: () => driver.answers(),
7218
7255
  checkpoint: () => resumed ? resumed.toolCheckpoint : stored,
7219
7256
  clearCheckpoint: () => driver.clearCheckpoint(),
7257
+ answer: (id, val) => driver.answer?.(id, val),
7258
+ clearAnswer: (id) => driver.clearAnswer?.(id),
7220
7259
  suspend(options = {}) {
7221
7260
  const interactionIds = [.../* @__PURE__ */ new Set([
7222
7261
  ...requestedIds,
@@ -7357,14 +7396,26 @@ var AgentRuntime = class _AgentRuntime {
7357
7396
  throw error;
7358
7397
  }
7359
7398
  }
7360
- async handleRunEnd(runId, agentId, outcome) {
7399
+ publishLiveInteraction(runId, interaction) {
7400
+ this.transientEvents.publish({
7401
+ kind: "live_interaction",
7402
+ durability: "transient",
7403
+ runId,
7404
+ executionId: this.executions.get(runId)?.executionId,
7405
+ interaction
7406
+ });
7407
+ }
7408
+ cancelLiveInteractions(runId, reason) {
7361
7409
  const runLive = this.liveInteractions.get(runId);
7362
- if (runLive) {
7363
- for (const live of runLive.values()) {
7364
- live.reject(new RunInteractionCancelledError("Run ended."));
7365
- }
7366
- this.liveInteractions.delete(runId);
7410
+ if (!runLive) return;
7411
+ this.liveInteractions.delete(runId);
7412
+ for (const live of runLive.values()) {
7413
+ this.publishLiveInteraction(runId, { ...live.interaction, status: "cancelled" });
7414
+ live.reject(new RunInteractionCancelledError(reason));
7367
7415
  }
7416
+ }
7417
+ async handleRunEnd(runId, agentId, outcome) {
7418
+ this.cancelLiveInteractions(runId, "Run ended.");
7368
7419
  if (this.startedRuns.has(runId)) {
7369
7420
  this.startedRuns.delete(runId);
7370
7421
  try {
@@ -7631,11 +7682,13 @@ var AgentRuntime = class _AgentRuntime {
7631
7682
  runLive = /* @__PURE__ */ new Map();
7632
7683
  this.liveInteractions.set(runId, runLive);
7633
7684
  }
7685
+ this.publishLiveInteraction(runId, interaction);
7634
7686
  return new Promise((resolve9, reject) => {
7635
7687
  const onAbort = () => {
7636
7688
  runLive?.delete(interactionId);
7637
7689
  if (runLive && runLive.size === 0) this.liveInteractions.delete(runId);
7638
7690
  signal.removeEventListener("abort", onAbort);
7691
+ this.publishLiveInteraction(runId, { ...interaction, status: "cancelled" });
7639
7692
  reject(signal.reason ?? new Error("Run aborted"));
7640
7693
  };
7641
7694
  signal.addEventListener("abort", onAbort, { once: true });
@@ -7658,12 +7711,9 @@ var AgentRuntime = class _AgentRuntime {
7658
7711
  if (this.heartbeat) clearInterval(this.heartbeat);
7659
7712
  for (const execution of this.executions.values()) execution.controller.abort();
7660
7713
  this.executions.clear();
7661
- for (const runLive of this.liveInteractions.values()) {
7662
- for (const live of runLive.values()) {
7663
- live.reject(new RunInteractionCancelledError("Runtime closed."));
7664
- }
7714
+ for (const runId of [...this.liveInteractions.keys()]) {
7715
+ this.cancelLiveInteractions(runId, "Runtime closed.");
7665
7716
  }
7666
- this.liveInteractions.clear();
7667
7717
  this.transientEvents.close();
7668
7718
  for (const subscription of this.consumers.values()) subscription.controller.abort();
7669
7719
  await this.resources.closeExtensions();
@@ -7693,8 +7743,10 @@ var AgentRuntime = class _AgentRuntime {
7693
7743
  runLive.delete(input.interactionId);
7694
7744
  if (runLive.size === 0) this.liveInteractions.delete(runId);
7695
7745
  if (input.cancel) {
7746
+ this.publishLiveInteraction(runId, { ...live.interaction, status: "cancelled" });
7696
7747
  live.reject(new RunInteractionCancelledError("Run interaction cancelled."));
7697
7748
  } else if (input.input !== void 0) {
7749
+ this.publishLiveInteraction(runId, { ...live.interaction, status: "answered", answer: input.input });
7698
7750
  live.resolve(input.input);
7699
7751
  } else {
7700
7752
  live.reject(new TypeError("respondInteraction requires input or cancel: true"));
@@ -7710,13 +7762,7 @@ var AgentRuntime = class _AgentRuntime {
7710
7762
  }
7711
7763
  async cancel(runId, reason) {
7712
7764
  this.assertOpen();
7713
- const runLive = this.liveInteractions.get(runId);
7714
- if (runLive) {
7715
- for (const live of runLive.values()) {
7716
- live.reject(new RunInteractionCancelledError(reason ?? "Agent run stopped."));
7717
- }
7718
- this.liveInteractions.delete(runId);
7719
- }
7765
+ this.cancelLiveInteractions(runId, reason ?? "Agent run stopped.");
7720
7766
  const done = this.executionDone.get(runId);
7721
7767
  if (done) {
7722
7768
  this.cancellationRequested.add(runId);
@@ -7841,11 +7887,18 @@ var AgentRuntime = class _AgentRuntime {
7841
7887
  runId: run.id,
7842
7888
  expectedRevision: run.revision,
7843
7889
  executionId,
7844
- configToken: token
7890
+ configToken: token,
7891
+ ...config.additionalContexts && config.additionalContexts.length > 0 ? { additionalContexts: config.additionalContexts } : {}
7845
7892
  });
7846
7893
  executionRevision = claim.run.revision;
7847
7894
  const controller = new AbortController();
7848
- this.executions.set(run.id, { controller, executionId });
7895
+ this.executions.set(run.id, {
7896
+ controller,
7897
+ executionId,
7898
+ reservedToolCalls: /* @__PURE__ */ new Set(),
7899
+ startedToolCalls: /* @__PURE__ */ new Set(),
7900
+ providerToolCalls: /* @__PURE__ */ new Map()
7901
+ });
7849
7902
  if (this.cancellationRequested.has(run.id)) controller.abort();
7850
7903
  if (!this.startedRuns.has(run.id)) {
7851
7904
  this.startedRuns.add(run.id);
@@ -7908,6 +7961,7 @@ var AgentRuntime = class _AgentRuntime {
7908
7961
  },
7909
7962
  model,
7910
7963
  thinkingLevel: thinkingLevelFromUserInput(run.input),
7964
+ providerOptions: providerOptionsFromUserInput(run.input),
7911
7965
  stream,
7912
7966
  maxAttempts: config.maxAttempts,
7913
7967
  checkpoint: claim.run.checkpoint,
@@ -8077,25 +8131,130 @@ var AgentRuntime = class _AgentRuntime {
8077
8131
  onContext: assembly.setContext,
8078
8132
  runtime: {
8079
8133
  interact: (request) => this.liveInteract(run.id, request, controller.signal),
8080
- tools: ({ toolCall, contentBlocks, driver, options }) => {
8134
+ tools: ({ toolCall, contentBlocks, driver, options, providerInitiated }) => {
8081
8135
  const task = toolQueue.then(async () => {
8082
- const execution = await this.executeToolBatch({
8083
- run,
8084
- agentMetadata: agent.metadata,
8085
- execution: claim.execution,
8086
- expectedRevision: executionRevision,
8087
- toolConfig: executionTools,
8088
- toolCalls: [toolCall],
8089
- contentBlocks,
8090
- signal: controller.signal,
8091
- driver,
8092
- options,
8093
- onRevision: (rev) => {
8094
- executionRevision = rev;
8136
+ if (!providerInitiated) {
8137
+ const execution = await this.executeToolBatch({
8138
+ run,
8139
+ agentMetadata: agent.metadata,
8140
+ execution: claim.execution,
8141
+ expectedRevision: executionRevision,
8142
+ toolConfig: executionTools,
8143
+ toolCalls: [toolCall],
8144
+ contentBlocks,
8145
+ signal: controller.signal,
8146
+ driver,
8147
+ options,
8148
+ onRevision: (rev) => {
8149
+ executionRevision = rev;
8150
+ }
8151
+ });
8152
+ executionRevision = execution.revision;
8153
+ return execution.results[0];
8154
+ }
8155
+ const interactionIds = [];
8156
+ try {
8157
+ while (true) {
8158
+ try {
8159
+ const execution = await this.executeToolBatch({
8160
+ run,
8161
+ agentMetadata: agent.metadata,
8162
+ execution: claim.execution,
8163
+ expectedRevision: executionRevision,
8164
+ toolConfig: executionTools,
8165
+ toolCalls: [toolCall],
8166
+ contentBlocks,
8167
+ signal: controller.signal,
8168
+ driver,
8169
+ options,
8170
+ providerInitiated: true,
8171
+ interactionIds,
8172
+ onRevision: (rev) => {
8173
+ executionRevision = rev;
8174
+ }
8175
+ });
8176
+ executionRevision = execution.revision;
8177
+ return execution.results[0];
8178
+ } catch (error) {
8179
+ if (error instanceof RunInteractionBoundary) {
8180
+ try {
8181
+ for (const interaction of error.interactions) {
8182
+ interactionIds.push(interaction.id);
8183
+ const answer = await this.liveInteract(run.id, interaction, controller.signal);
8184
+ driver?.answer?.(interaction.id, answer);
8185
+ }
8186
+ driver?.clearCheckpoint();
8187
+ continue;
8188
+ } catch (waitError) {
8189
+ const active2 = this.executions.get(run.id);
8190
+ const toolCallId2 = active2?.providerToolCalls.get(toolCall.id) ?? error.interactions[0]?.toolCallId;
8191
+ const isCancel = waitError instanceof RunInteractionCancelledError;
8192
+ const reason = isCancel ? waitError.message : "Tool execution aborted.";
8193
+ if (toolCallId2) {
8194
+ const committed2 = await this.owned.commitToolResult({
8195
+ runId: run.id,
8196
+ execution: claim.execution,
8197
+ expectedRevision: executionRevision,
8198
+ toolCallId: toolCallId2,
8199
+ state: "failed",
8200
+ result: { ok: false, content: null, error: reason },
8201
+ title: toolCall.name,
8202
+ kind: "other"
8203
+ });
8204
+ executionRevision = committed2.run.revision;
8205
+ if (options?.onUpdate) {
8206
+ try {
8207
+ options.onUpdate(createMergedToolCall(
8208
+ toolCallId2,
8209
+ "failed",
8210
+ { rawInput: toJsonValue(toolCall.args) },
8211
+ toolCall.name,
8212
+ "other"
8213
+ ));
8214
+ } catch (err) {
8215
+ console.warn("Error in tool call onUpdate callback:", err);
8216
+ }
8217
+ }
8218
+ }
8219
+ if (!controller.signal.aborted && isCancel) {
8220
+ return {
8221
+ toolCallId: toolCall.id,
8222
+ toolName: toolCall.name,
8223
+ ok: false,
8224
+ content: null,
8225
+ error: reason
8226
+ };
8227
+ }
8228
+ throw waitError;
8229
+ }
8230
+ }
8231
+ const active = this.executions.get(run.id);
8232
+ const toolCallId = active?.providerToolCalls.get(toolCall.id);
8233
+ if (toolCallId && (active?.reservedToolCalls.has(toolCallId) || active?.startedToolCalls.has(toolCallId))) {
8234
+ try {
8235
+ const committed2 = await this.owned.commitToolResult({
8236
+ runId: run.id,
8237
+ execution: claim.execution,
8238
+ expectedRevision: executionRevision,
8239
+ toolCallId,
8240
+ state: "failed",
8241
+ result: { ok: false, content: null, error: error instanceof Error ? error.message : "Tool execution failed." },
8242
+ title: toolCall.name,
8243
+ kind: "other"
8244
+ });
8245
+ executionRevision = committed2.run.revision;
8246
+ } catch {
8247
+ }
8248
+ }
8249
+ throw error;
8250
+ }
8095
8251
  }
8096
- });
8097
- executionRevision = execution.revision;
8098
- return execution.results[0];
8252
+ } finally {
8253
+ driver?.clearCheckpoint();
8254
+ for (const id of interactionIds) driver?.clearAnswer?.(id);
8255
+ const active = this.executions.get(run.id);
8256
+ active?.providerToolCalls.delete(toolCall.id);
8257
+ }
8099
8258
  });
8100
8259
  toolQueue = task.then(() => void 0, () => void 0);
8101
8260
  return task;
@@ -8136,6 +8295,9 @@ var AgentRuntime = class _AgentRuntime {
8136
8295
  result = await executeModel(executionContext);
8137
8296
  }
8138
8297
  }
8298
+ if (result.type !== "input_required") {
8299
+ this.cancelLiveInteractions(run.id, result.type === "failed" ? result.error instanceof Error ? result.error.message : "Model execution failed." : "Run ended.");
8300
+ }
8139
8301
  await toolQueue;
8140
8302
  if (this.cancellationRequested.has(run.id) || controller.signal.aborted) {
8141
8303
  const output2 = latestAssistant(run, result.messages, executionContext.messages.length, true);
@@ -8209,6 +8371,7 @@ var AgentRuntime = class _AgentRuntime {
8209
8371
  } catch (error) {
8210
8372
  if (!claim && error instanceof RuntimeError && ["run_state_conflict", "runtime_ownership_lost", "run_not_found"].includes(error.code)) return;
8211
8373
  if (claim) {
8374
+ this.cancelLiveInteractions(run.id, error instanceof Error ? error.message : "Execution failed.");
8212
8375
  await toolQueue;
8213
8376
  if (this.cancellationRequested.has(run.id)) {
8214
8377
  const reason = this.cancellationReasons.get(run.id) ?? "Agent run stopped.";
@@ -8445,11 +8608,17 @@ var AgentRuntime = class _AgentRuntime {
8445
8608
  }
8446
8609
  const results = suspension ? [...suspension.completedResults] : [];
8447
8610
  const startIndex = suspension ? suspension.pendingIndex : 0;
8611
+ const active = this.executions.get(input.run.id);
8448
8612
  for (let index = startIndex; index < input.toolCalls.length; index += 1) {
8449
8613
  const toolCall = input.toolCalls[index];
8450
8614
  const durableTool = input.toolConfig.tools.find((candidate) => candidate.name === toolCall.name);
8451
8615
  const providerToolCallId = toolCall.id;
8452
- const toolCallId = suspension && index >= suspension.pendingIndex && suspension.toolCallIds?.[index] ? suspension.toolCallIds[index] : suspension && index === suspension.pendingIndex && suspension.toolCallId ? suspension.toolCallId : createId("tool");
8616
+ const toolCallId = input.providerInitiated && active?.providerToolCalls.has(providerToolCallId) ? active.providerToolCalls.get(providerToolCallId) : suspension && index >= suspension.pendingIndex && suspension.toolCallIds?.[index] ? suspension.toolCallIds[index] : suspension && index === suspension.pendingIndex && suspension.toolCallId ? suspension.toolCallId : createId("tool");
8617
+ if (input.providerInitiated && !active?.providerToolCalls.has(providerToolCallId)) {
8618
+ active?.providerToolCalls.set(providerToolCallId, toolCallId);
8619
+ }
8620
+ const isReserved = Boolean(active?.reservedToolCalls.has(toolCallId));
8621
+ const isStarted = Boolean(active?.startedToolCalls.has(toolCallId));
8453
8622
  const protocolFailure = (error) => ({
8454
8623
  toolCallId: providerToolCallId,
8455
8624
  toolName: toolCall.name,
@@ -8458,20 +8627,23 @@ var AgentRuntime = class _AgentRuntime {
8458
8627
  error
8459
8628
  });
8460
8629
  if (!durableTool) {
8461
- const reserved = await this.owned.reserveToolCalls({
8462
- runId: input.run.id,
8463
- execution: input.execution,
8464
- expectedRevision: revision,
8465
- requestMessageId: createId("msg"),
8466
- contentBlocks: input.contentBlocks,
8467
- calls: [{
8468
- toolCallId,
8469
- providerToolCallId,
8470
- name: toolCall.name,
8471
- args: toJsonValue(toolCall.args)
8472
- }]
8473
- });
8474
- setRevision(reserved.run.revision);
8630
+ if (!isReserved) {
8631
+ const reserved = await this.owned.reserveToolCalls({
8632
+ runId: input.run.id,
8633
+ execution: input.execution,
8634
+ expectedRevision: revision,
8635
+ requestMessageId: createId("msg"),
8636
+ contentBlocks: input.contentBlocks,
8637
+ calls: [{
8638
+ toolCallId,
8639
+ providerToolCallId,
8640
+ name: toolCall.name,
8641
+ args: toJsonValue(toolCall.args)
8642
+ }]
8643
+ });
8644
+ setRevision(reserved.run.revision);
8645
+ active?.reservedToolCalls.add(toolCallId);
8646
+ }
8475
8647
  const failed = await this.owned.commitToolResult({
8476
8648
  runId: input.run.id,
8477
8649
  execution: input.execution,
@@ -8537,7 +8709,7 @@ var AgentRuntime = class _AgentRuntime {
8537
8709
  reportProgress: () => {
8538
8710
  }
8539
8711
  };
8540
- const answer = suspension && index === suspension.pendingIndex ? suspension.interactionIds?.map((id) => input.driver?.answers().get(id)).find((value) => value !== void 0) : void 0;
8712
+ const answer = suspension && index === suspension.pendingIndex ? suspension.interactionIds?.map((id) => input.driver?.answers().get(id)).find((value) => value !== void 0) : input.providerInitiated && input.interactionIds ? input.interactionIds.map((id) => input.driver?.answers().get(id)).find((value) => value !== void 0) : void 0;
8541
8713
  try {
8542
8714
  if (input.toolConfig.beforeToolCall) {
8543
8715
  const decision = await input.toolConfig.beforeToolCall({
@@ -8552,7 +8724,7 @@ var AgentRuntime = class _AgentRuntime {
8552
8724
  throw new Error("Tool call requested interaction but no interaction driver is active.");
8553
8725
  }
8554
8726
  interactionDriver.request(decision.interaction);
8555
- if (!resumedStart) {
8727
+ if (!resumedStart && !isReserved) {
8556
8728
  const reserved = await this.owned.reserveToolCalls({
8557
8729
  runId: input.run.id,
8558
8730
  execution: input.execution,
@@ -8568,11 +8740,12 @@ var AgentRuntime = class _AgentRuntime {
8568
8740
  }]
8569
8741
  });
8570
8742
  setRevision(reserved.run.revision);
8743
+ active?.reservedToolCalls.add(toolCallId);
8571
8744
  }
8572
8745
  interactionDriver.suspend();
8573
8746
  }
8574
8747
  if ("allow" in decision && !decision.allow) {
8575
- if (!resumedStart) {
8748
+ if (!resumedStart && !isReserved) {
8576
8749
  const reserved = await this.owned.reserveToolCalls({
8577
8750
  runId: input.run.id,
8578
8751
  execution: input.execution,
@@ -8588,6 +8761,7 @@ var AgentRuntime = class _AgentRuntime {
8588
8761
  }]
8589
8762
  });
8590
8763
  setRevision(reserved.run.revision);
8764
+ active?.reservedToolCalls.add(toolCallId);
8591
8765
  }
8592
8766
  const failed = await this.owned.commitToolResult({
8593
8767
  runId: input.run.id,
@@ -8625,7 +8799,7 @@ var AgentRuntime = class _AgentRuntime {
8625
8799
  throw error;
8626
8800
  }
8627
8801
  const reason = error instanceof Error ? error.message : "Tool policy rejected the call.";
8628
- if (!resumedStart) {
8802
+ if (!resumedStart && !isReserved) {
8629
8803
  const reserved = await this.owned.reserveToolCalls({
8630
8804
  runId: input.run.id,
8631
8805
  execution: input.execution,
@@ -8641,6 +8815,7 @@ var AgentRuntime = class _AgentRuntime {
8641
8815
  }]
8642
8816
  });
8643
8817
  setRevision(reserved.run.revision);
8818
+ active?.reservedToolCalls.add(toolCallId);
8644
8819
  }
8645
8820
  const failed = await this.owned.commitToolResult({
8646
8821
  runId: input.run.id,
@@ -8672,22 +8847,25 @@ var AgentRuntime = class _AgentRuntime {
8672
8847
  results.push(protocolFailure(reason));
8673
8848
  continue;
8674
8849
  }
8675
- if (!resumedStart) {
8676
- const reserved = await this.owned.reserveToolCalls({
8677
- runId: input.run.id,
8678
- execution: input.execution,
8679
- expectedRevision: revision,
8680
- requestMessageId: createId("msg"),
8681
- contentBlocks: input.contentBlocks,
8682
- calls: [{
8683
- toolCallId,
8684
- providerToolCallId,
8685
- name: toolCall.name,
8686
- args: toJsonValue(toolCall.args),
8687
- ...pendingPres
8688
- }]
8689
- });
8690
- setRevision(reserved.run.revision);
8850
+ if (!resumedStart && !isStarted) {
8851
+ if (!isReserved) {
8852
+ const reserved = await this.owned.reserveToolCalls({
8853
+ runId: input.run.id,
8854
+ execution: input.execution,
8855
+ expectedRevision: revision,
8856
+ requestMessageId: createId("msg"),
8857
+ contentBlocks: input.contentBlocks,
8858
+ calls: [{
8859
+ toolCallId,
8860
+ providerToolCallId,
8861
+ name: toolCall.name,
8862
+ args: toJsonValue(toolCall.args),
8863
+ ...pendingPres
8864
+ }]
8865
+ });
8866
+ setRevision(reserved.run.revision);
8867
+ active?.reservedToolCalls.add(toolCallId);
8868
+ }
8691
8869
  const inProgressPres = await presentToolCall(durableTool, {
8692
8870
  status: "in_progress",
8693
8871
  args: toJsonValue(toolCall.args)
@@ -8705,6 +8883,7 @@ var AgentRuntime = class _AgentRuntime {
8705
8883
  ...currentToolState._meta !== void 0 ? { _meta: currentToolState._meta } : {}
8706
8884
  });
8707
8885
  setRevision(started.run.revision);
8886
+ active?.startedToolCalls.add(toolCallId);
8708
8887
  }
8709
8888
  const toolResult2 = await this.executeAndCommitTool({
8710
8889
  runId: input.run.id,
@@ -8729,7 +8908,8 @@ var AgentRuntime = class _AgentRuntime {
8729
8908
  signal: input.signal,
8730
8909
  afterToolCall: input.toolConfig.afterToolCall,
8731
8910
  currentToolState,
8732
- options: input.options
8911
+ options: input.options,
8912
+ providerInitiated: input.providerInitiated
8733
8913
  });
8734
8914
  results.push(toolResult2);
8735
8915
  }
@@ -8901,13 +9081,15 @@ var AgentRuntime = class _AgentRuntime {
8901
9081
  };
8902
9082
  } catch (error) {
8903
9083
  if (error instanceof RunInteractionBoundary) {
8904
- const suspended = await this.owned.suspendToolCall({
8905
- runId: input.runId,
8906
- execution: input.execution,
8907
- expectedRevision: input.revision,
8908
- toolCallId: input.toolCallId
8909
- });
8910
- input.setRevision(suspended.run.revision);
9084
+ if (!input.providerInitiated) {
9085
+ const suspended = await this.owned.suspendToolCall({
9086
+ runId: input.runId,
9087
+ execution: input.execution,
9088
+ expectedRevision: input.revision,
9089
+ toolCallId: input.toolCallId
9090
+ });
9091
+ input.setRevision(suspended.run.revision);
9092
+ }
8911
9093
  throw error;
8912
9094
  }
8913
9095
  if (error instanceof RunInteractionCancelledError) throw error;
@@ -9936,7 +10118,8 @@ var InMemoryStore = class _InMemoryStore {
9936
10118
  input.runId,
9937
10119
  input.expectedRevision,
9938
10120
  input.messageId ?? null,
9939
- input.configToken ?? null
10121
+ input.configToken ?? null,
10122
+ input.additionalContexts ?? null
9940
10123
  ]);
9941
10124
  const replay = this.replayOperation(operationKey, operationPayload);
9942
10125
  if (replay) return clone(replay);
@@ -9956,6 +10139,7 @@ var InMemoryStore = class _InMemoryStore {
9956
10139
  const committedMessages = [];
9957
10140
  if (!run.checkpoint && !run.initialMessageId && (!isControlRun(run) || hasUserInput(run.input))) {
9958
10141
  const userInput = normalizeUserInput(run.input);
10142
+ const turnContexts = input.additionalContexts ?? [];
9959
10143
  const message = {
9960
10144
  id: input.messageId ?? createId("msg"),
9961
10145
  agentId: run.agentId,
@@ -9963,6 +10147,7 @@ var InMemoryStore = class _InMemoryStore {
9963
10147
  role: "user",
9964
10148
  content: userInputContent(userInput),
9965
10149
  ...userInputMetadata(userInput) ? { metadata: clone(userInputMetadata(userInput)) } : {},
10150
+ ...turnContexts.length > 0 ? { contexts: clone(turnContexts) } : {},
9966
10151
  sequenceWithinRun: this.nextMessageSequence(run.id),
9967
10152
  createdAt: createTimestamp()
9968
10153
  };