@rowan-agent/agent 0.16.1 → 0.17.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/index.d.ts CHANGED
@@ -946,6 +946,8 @@ type ToolCallContext = Readonly<{
946
946
  agentMetadata?: Metadata;
947
947
  runMetadata?: Metadata;
948
948
  toolCallId: ToolCallId;
949
+ /** The model's id for this call, matching `tool_call_delta` events; absent when a host runs the tool itself. */
950
+ providerToolCallId?: string;
949
951
  scope?: ScopeRef;
950
952
  turn?: JsonObject;
951
953
  reportProgress(progress: JsonValue): void;
@@ -1365,6 +1367,8 @@ type AgentRuntimeOptions = Readonly<{
1365
1367
  concurrency?: number;
1366
1368
  bootstrap?: (registry: RuntimeBootstrapRegistry) => void | Promise<void>;
1367
1369
  host?: ExtensionHost;
1370
+ /** @internal Private / testing parameter to override retry delay */
1371
+ retryDelayMs?: number;
1368
1372
  }>;
1369
1373
  type DurableConsumer = Readonly<{
1370
1374
  caughtUp: Promise<void>;
@@ -1683,9 +1687,14 @@ type Outcome = Readonly<{
1683
1687
  toolResults?: readonly DurableToolResult[];
1684
1688
  }>;
1685
1689
  type RunState = "queued" | "running" | "input_required" | "completed" | "failed" | "cancelled";
1690
+ type WithdrawnUserInput = Readonly<{
1691
+ messageId: MessageId;
1692
+ content: UserContent;
1693
+ }>;
1686
1694
  type RunFailure = Readonly<{
1687
1695
  code: "configuration_unavailable";
1688
1696
  message: string;
1697
+ withdrawnInput?: WithdrawnUserInput;
1689
1698
  }> | Readonly<{
1690
1699
  code: "checkpoint_incompatible";
1691
1700
  message: string;
@@ -1697,18 +1706,22 @@ type RunFailure = Readonly<{
1697
1706
  codec: string;
1698
1707
  version: number;
1699
1708
  }>;
1709
+ withdrawnInput?: WithdrawnUserInput;
1700
1710
  }> | Readonly<{
1701
1711
  code: "runtime_interrupted";
1702
1712
  message: string;
1703
1713
  ownerEpoch: number;
1714
+ withdrawnInput?: WithdrawnUserInput;
1704
1715
  }> | Readonly<{
1705
1716
  code: "tool_indeterminate";
1706
1717
  message: string;
1707
1718
  toolCallIds: readonly [ToolCallId, ...ToolCallId[]];
1719
+ withdrawnInput?: WithdrawnUserInput;
1708
1720
  }> | Readonly<{
1709
1721
  code: "execution_failed";
1710
1722
  message: string;
1711
1723
  details?: JsonValue;
1724
+ withdrawnInput?: WithdrawnUserInput;
1712
1725
  }>;
1713
1726
  type QueuedRunFailure = Extract<RunFailure, {
1714
1727
  code: "configuration_unavailable" | "checkpoint_incompatible";
@@ -1811,11 +1824,13 @@ type RunStateChanged = DurableEventBase & (Readonly<{
1811
1824
  from: "queued";
1812
1825
  to: "failed";
1813
1826
  failure: QueuedRunFailure;
1827
+ withdrawnInput?: WithdrawnUserInput;
1814
1828
  }> | Readonly<{
1815
1829
  kind: "run_state_changed";
1816
1830
  from: "running";
1817
1831
  to: "failed";
1818
1832
  failure: RunningRunFailure;
1833
+ withdrawnInput?: WithdrawnUserInput;
1819
1834
  }> | Readonly<{
1820
1835
  kind: "run_state_changed";
1821
1836
  from: "queued" | "running" | "input_required";
@@ -1915,6 +1930,17 @@ type ThinkingDelta = Readonly<{
1915
1930
  offset: number;
1916
1931
  text: string;
1917
1932
  }>;
1933
+ type ToolCallDelta = Readonly<{
1934
+ kind: "tool_call_delta";
1935
+ durability: "transient";
1936
+ runId: RunId;
1937
+ executionId: ExecutionId;
1938
+ messageId: MessageId;
1939
+ providerToolCallId: string;
1940
+ toolName: string;
1941
+ arguments: string;
1942
+ args: JsonValue | undefined;
1943
+ }>;
1918
1944
  type ToolProgress = Readonly<{
1919
1945
  kind: "tool_progress";
1920
1946
  durability: "transient";
@@ -1931,7 +1957,17 @@ type PhaseStatusEvent = Readonly<{
1931
1957
  phaseId: string;
1932
1958
  status: PhaseStatus;
1933
1959
  }>;
1934
- type RunEvent = DurableRunEvent | MessageDelta | ThinkingDelta | ToolProgress | PhaseStatusEvent;
1960
+ type ModelRetry = Readonly<{
1961
+ kind: "model_retry";
1962
+ durability: "transient";
1963
+ runId: RunId;
1964
+ executionId: ExecutionId;
1965
+ attempt: number;
1966
+ maxRetries: number;
1967
+ delayMs: number;
1968
+ error: string;
1969
+ }>;
1970
+ type RunEvent = DurableRunEvent | MessageDelta | ThinkingDelta | ToolCallDelta | ToolProgress | PhaseStatusEvent | ModelRetry;
1935
1971
 
1936
1972
  type PhaseStatusState = "running" | "completed";
1937
1973
  /** Normalized status event exposed to Runtime consumers. */
@@ -2306,6 +2342,7 @@ declare class AgentRuntime implements AgentRuntime$1 {
2306
2342
  private heartbeat?;
2307
2343
  private pumping;
2308
2344
  private closed;
2345
+ private readonly retryDelayMs?;
2309
2346
  private constructor();
2310
2347
  static init(options: AgentRuntimeOptions): Promise<AgentRuntime>;
2311
2348
  private handleRunEnd;
@@ -2701,6 +2738,7 @@ declare class InMemoryStore implements DurableStore {
2701
2738
  private nextReady;
2702
2739
  private nextMessageSequence;
2703
2740
  private messagesForRun;
2741
+ private withdrawUserInputIfNoOutput;
2704
2742
  history(lease: OwnerLease, agentId: AgentId): readonly Message[];
2705
2743
  contextStatus(lease: OwnerLease, agentId: AgentId, contextWindow: number): ContextStatus;
2706
2744
  contextMessages(lease: OwnerLease, agentId: AgentId, recentTokenBudget?: number): readonly Message[];
@@ -3138,4 +3176,4 @@ declare function parseFrontmatter<T = Record<string, unknown>>(raw: string): Fro
3138
3176
 
3139
3177
  declare function createCoreTools(input?: CoreToolContext): Tool$1[];
3140
3178
 
3141
- export { type AfterToolCall, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EntryPhaseSpec, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionCapability, type ExtensionCapabilityContribution, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionHost, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type ExtensionStateStore, type ExtensionToolContribution, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryExtensionHost, InMemoryStore, type InteractionRecord, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseSettingsBadge, type PhaseSettingsContext, type PhaseSettingsControl, type PhaseSettingsDefinition, type PhaseSettingsItem, type PhaseSettingsOption, type PhaseSettingsProvider, type PhaseSettingsSection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEndEvent, type RunEvent, type RunFailure, type RunId, type RunInteraction, RunInteractionBoundary, RunInteractionCancelledError, type RunInteractionDriver, type RunInteractionKind, type RunInteractionRequest, type RunInteractionState, type RunInteractionStatus, type RunListCursor, type RunRecord, type RunSnapshot, type RunStartEvent, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type ScopeRef, type Skill, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool$1 as Tool, type ToolCallContext, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, isConfigurationSnapshot, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhaseSettings, loadPhases, loadSkill, loadSkills, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
3179
+ export { type AfterToolCall, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EntryPhaseSpec, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionCapability, type ExtensionCapabilityContribution, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionHost, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type ExtensionStateStore, type ExtensionToolContribution, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryExtensionHost, InMemoryStore, type InteractionRecord, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type ModelRetry, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseSettingsBadge, type PhaseSettingsContext, type PhaseSettingsControl, type PhaseSettingsDefinition, type PhaseSettingsItem, type PhaseSettingsOption, type PhaseSettingsProvider, type PhaseSettingsSection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEndEvent, type RunEvent, type RunFailure, type RunId, type RunInteraction, RunInteractionBoundary, RunInteractionCancelledError, type RunInteractionDriver, type RunInteractionKind, type RunInteractionRequest, type RunInteractionState, type RunInteractionStatus, type RunListCursor, type RunRecord, type RunSnapshot, type RunStartEvent, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type ScopeRef, type Skill, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool$1 as Tool, type ToolCallContext, type ToolCallDelta, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, type WithdrawnUserInput, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, isConfigurationSnapshot, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhaseSettings, loadPhases, loadSkill, loadSkills, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
package/dist/index.js CHANGED
@@ -738,8 +738,8 @@ function createReadTool(context) {
738
738
  [truncated]` : formatted;
739
739
  const archivePath = await spillResult(context, "read", fullFormatted);
740
740
  content += `
741
- Full result: ${archivePath}
742
- Offset: 0`;
741
+
742
+ [Full result: ${archivePath}, offset 0]`;
743
743
  if (lineTruncated) {
744
744
  content += `
745
745
  Showing lines ${requestedOffset}-${selectedLineEnd} of ${sourceLines.length}. Use offset=${selectedLineEnd + 1} to continue.`;
@@ -896,8 +896,8 @@ function createBashTool(context) {
896
896
  [truncated]` : output;
897
897
  const archivePath = await spillResult(context, "bash", output);
898
898
  content += `
899
- Full result: ${archivePath}
900
- Offset: 0`;
899
+
900
+ [Full result: ${archivePath}, offset 0]`;
901
901
  return toolResult({
902
902
  context: toolContext,
903
903
  toolName: "bash",
@@ -1009,6 +1009,296 @@ function validateMaxAttempts(value) {
1009
1009
  return value;
1010
1010
  }
1011
1011
 
1012
+ // src/loop/partial-json.ts
1013
+ var COMPLETE_NUMBER_REGEX = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
1014
+ function escapeRawControlChars(s) {
1015
+ let result = "";
1016
+ for (let i = 0; i < s.length; i++) {
1017
+ const ch = s[i];
1018
+ const code = ch.charCodeAt(0);
1019
+ if (code === 10) result += "\\n";
1020
+ else if (code === 13) result += "\\r";
1021
+ else if (code === 9) result += "\\t";
1022
+ else if (code < 32) result += "\\u" + code.toString(16).padStart(4, "0");
1023
+ else result += ch;
1024
+ }
1025
+ return result;
1026
+ }
1027
+ function cleanOpenString(raw) {
1028
+ let s = raw;
1029
+ let backslashes = 0;
1030
+ while (s.length - 1 - backslashes >= 0 && s[s.length - 1 - backslashes] === "\\") {
1031
+ backslashes++;
1032
+ }
1033
+ if (backslashes % 2 === 1) {
1034
+ s = s.slice(0, -1);
1035
+ } else {
1036
+ s = s.replace(/(^|[^\\])(?:\\\\)*\\u[0-9a-fA-F]{0,3}$/, (match) => {
1037
+ const uIndex = match.lastIndexOf("\\u");
1038
+ return match.slice(0, uIndex);
1039
+ });
1040
+ }
1041
+ return escapeRawControlChars(s) + '"';
1042
+ }
1043
+ function repairPartialJson(input) {
1044
+ const stack = [];
1045
+ let i = 0;
1046
+ let hasTopLevelValue = false;
1047
+ let topLevelSafeEnd = 0;
1048
+ function finishWithSafeEnd(safeEnd) {
1049
+ let result = input.slice(0, safeEnd);
1050
+ for (let j = stack.length - 1; j >= 0; j--) {
1051
+ result += stack[j].kind === "object" ? "}" : "]";
1052
+ }
1053
+ return result;
1054
+ }
1055
+ function closeStackWithPrefix(prefix) {
1056
+ let result = prefix;
1057
+ for (let j = stack.length - 1; j >= 0; j--) {
1058
+ result += stack[j].kind === "object" ? "}" : "]";
1059
+ }
1060
+ return result;
1061
+ }
1062
+ function popContainer(endIndex) {
1063
+ stack.pop();
1064
+ const parent = stack[stack.length - 1];
1065
+ if (parent) {
1066
+ parent.safeEnd = endIndex;
1067
+ parent.state = "after_value";
1068
+ } else {
1069
+ hasTopLevelValue = true;
1070
+ topLevelSafeEnd = endIndex;
1071
+ }
1072
+ }
1073
+ while (i < input.length) {
1074
+ const ch = input[i];
1075
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
1076
+ i++;
1077
+ continue;
1078
+ }
1079
+ const current = stack[stack.length - 1];
1080
+ if (!current) {
1081
+ if (hasTopLevelValue) break;
1082
+ if (ch === "{") {
1083
+ stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
1084
+ i++;
1085
+ } else if (ch === "[") {
1086
+ stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
1087
+ i++;
1088
+ } else if (ch === '"') {
1089
+ const strStart = i;
1090
+ i++;
1091
+ let closed = false;
1092
+ while (i < input.length) {
1093
+ if (input[i] === "\\") {
1094
+ i += 2;
1095
+ } else if (input[i] === '"') {
1096
+ i++;
1097
+ closed = true;
1098
+ break;
1099
+ } else {
1100
+ i++;
1101
+ }
1102
+ }
1103
+ if (closed) {
1104
+ hasTopLevelValue = true;
1105
+ topLevelSafeEnd = i;
1106
+ } else {
1107
+ return cleanOpenString(input.slice(strStart));
1108
+ }
1109
+ } else {
1110
+ const tokStart = i;
1111
+ while (i < input.length && !/[\s,}\]]/.test(input[i])) {
1112
+ i++;
1113
+ }
1114
+ const tok = input.slice(tokStart, i);
1115
+ if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
1116
+ hasTopLevelValue = true;
1117
+ topLevelSafeEnd = i;
1118
+ } else {
1119
+ return void 0;
1120
+ }
1121
+ }
1122
+ continue;
1123
+ }
1124
+ if (current.kind === "object") {
1125
+ if (current.state === "expect_key") {
1126
+ if (ch === "}") {
1127
+ i++;
1128
+ popContainer(i);
1129
+ } else if (ch === '"') {
1130
+ i++;
1131
+ let closed = false;
1132
+ while (i < input.length) {
1133
+ if (input[i] === "\\") {
1134
+ i += 2;
1135
+ } else if (input[i] === '"') {
1136
+ i++;
1137
+ closed = true;
1138
+ break;
1139
+ } else {
1140
+ i++;
1141
+ }
1142
+ }
1143
+ if (closed) {
1144
+ current.state = "expect_colon";
1145
+ } else {
1146
+ return finishWithSafeEnd(current.safeEnd);
1147
+ }
1148
+ } else {
1149
+ return finishWithSafeEnd(current.safeEnd);
1150
+ }
1151
+ } else if (current.state === "expect_colon") {
1152
+ if (ch === ":") {
1153
+ current.state = "expect_value";
1154
+ i++;
1155
+ } else {
1156
+ return finishWithSafeEnd(current.safeEnd);
1157
+ }
1158
+ } else if (current.state === "expect_value") {
1159
+ if (ch === '"') {
1160
+ const valStart = i;
1161
+ i++;
1162
+ let closed = false;
1163
+ while (i < input.length) {
1164
+ if (input[i] === "\\") {
1165
+ i += 2;
1166
+ } else if (input[i] === '"') {
1167
+ i++;
1168
+ closed = true;
1169
+ break;
1170
+ } else {
1171
+ i++;
1172
+ }
1173
+ }
1174
+ if (closed) {
1175
+ current.safeEnd = i;
1176
+ current.state = "after_value";
1177
+ } else {
1178
+ const prefix = input.slice(0, valStart);
1179
+ const repairedStr = cleanOpenString(input.slice(valStart));
1180
+ return closeStackWithPrefix(prefix + repairedStr);
1181
+ }
1182
+ } else if (ch === "{") {
1183
+ stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
1184
+ i++;
1185
+ } else if (ch === "[") {
1186
+ stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
1187
+ i++;
1188
+ } else if (ch === "}" || ch === "]") {
1189
+ return finishWithSafeEnd(current.safeEnd);
1190
+ } else {
1191
+ const tokStart = i;
1192
+ while (i < input.length && !/[\s,}\]]/.test(input[i])) {
1193
+ i++;
1194
+ }
1195
+ const tok = input.slice(tokStart, i);
1196
+ if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
1197
+ current.safeEnd = i;
1198
+ current.state = "after_value";
1199
+ } else {
1200
+ return finishWithSafeEnd(current.safeEnd);
1201
+ }
1202
+ }
1203
+ } else if (current.state === "after_value") {
1204
+ if (ch === ",") {
1205
+ current.state = "expect_key";
1206
+ i++;
1207
+ } else if (ch === "}") {
1208
+ i++;
1209
+ popContainer(i);
1210
+ } else {
1211
+ return finishWithSafeEnd(current.safeEnd);
1212
+ }
1213
+ }
1214
+ } else {
1215
+ if (current.state === "expect_value") {
1216
+ if (ch === "]") {
1217
+ i++;
1218
+ popContainer(i);
1219
+ } else if (ch === '"') {
1220
+ const valStart = i;
1221
+ i++;
1222
+ let closed = false;
1223
+ while (i < input.length) {
1224
+ if (input[i] === "\\") {
1225
+ i += 2;
1226
+ } else if (input[i] === '"') {
1227
+ i++;
1228
+ closed = true;
1229
+ break;
1230
+ } else {
1231
+ i++;
1232
+ }
1233
+ }
1234
+ if (closed) {
1235
+ current.safeEnd = i;
1236
+ current.state = "after_value";
1237
+ } else {
1238
+ const prefix = input.slice(0, valStart);
1239
+ const repairedStr = cleanOpenString(input.slice(valStart));
1240
+ return closeStackWithPrefix(prefix + repairedStr);
1241
+ }
1242
+ } else if (ch === "{") {
1243
+ stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
1244
+ i++;
1245
+ } else if (ch === "[") {
1246
+ stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
1247
+ i++;
1248
+ } else if (ch === "}") {
1249
+ return finishWithSafeEnd(current.safeEnd);
1250
+ } else {
1251
+ const tokStart = i;
1252
+ while (i < input.length && !/[\s,}\]]/.test(input[i])) {
1253
+ i++;
1254
+ }
1255
+ const tok = input.slice(tokStart, i);
1256
+ if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
1257
+ current.safeEnd = i;
1258
+ current.state = "after_value";
1259
+ } else {
1260
+ return finishWithSafeEnd(current.safeEnd);
1261
+ }
1262
+ }
1263
+ } else if (current.state === "after_value") {
1264
+ if (ch === ",") {
1265
+ current.state = "expect_value";
1266
+ i++;
1267
+ } else if (ch === "]") {
1268
+ i++;
1269
+ popContainer(i);
1270
+ } else {
1271
+ return finishWithSafeEnd(current.safeEnd);
1272
+ }
1273
+ }
1274
+ }
1275
+ }
1276
+ if (stack.length > 0) {
1277
+ const current = stack[stack.length - 1];
1278
+ return finishWithSafeEnd(current.safeEnd);
1279
+ }
1280
+ if (hasTopLevelValue) {
1281
+ return input.slice(0, topLevelSafeEnd);
1282
+ }
1283
+ return void 0;
1284
+ }
1285
+ function parsePartialJson(input) {
1286
+ if (typeof input !== "string") return void 0;
1287
+ if (!input.trim()) return void 0;
1288
+ const source = input.trimStart();
1289
+ try {
1290
+ return JSON.parse(source);
1291
+ } catch {
1292
+ }
1293
+ const repaired = repairPartialJson(source);
1294
+ if (repaired === void 0) return void 0;
1295
+ try {
1296
+ return JSON.parse(repaired);
1297
+ } catch {
1298
+ return void 0;
1299
+ }
1300
+ }
1301
+
1012
1302
  // src/loop/errors.ts
1013
1303
  var EmptyResponseError = class extends Error {
1014
1304
  code = "empty_response";
@@ -1046,7 +1336,8 @@ async function invokeModel(input) {
1046
1336
  events,
1047
1337
  metadataPhase: input.phaseId,
1048
1338
  output: input.output,
1049
- onThinkingDelta: input.onThinkingDelta
1339
+ onThinkingDelta: input.onThinkingDelta,
1340
+ onToolCallDelta: input.onToolCallDelta
1050
1341
  });
1051
1342
  const response = result.doneResponse ?? {
1052
1343
  content: result.text,
@@ -1077,6 +1368,8 @@ async function collectStreamResult(input) {
1077
1368
  let streamedOutputCharacters = 0;
1078
1369
  const toolCallsWithDeltas = /* @__PURE__ */ new Set();
1079
1370
  const thinkingOffsets = /* @__PURE__ */ new Map();
1371
+ const toolNames = /* @__PURE__ */ new Map();
1372
+ const toolArguments = /* @__PURE__ */ new Map();
1080
1373
  for await (const event of input.events) {
1081
1374
  if (event.type === "text_delta") {
1082
1375
  streamedOutputCharacters += event.text.length;
@@ -1127,6 +1420,26 @@ async function collectStreamResult(input) {
1127
1420
  }
1128
1421
  lastPartial = event.partial;
1129
1422
  }
1423
+ if (event.type === "tool_call_start") {
1424
+ toolNames.set(event.id, event.name);
1425
+ }
1426
+ if (event.type === "tool_call_delta") {
1427
+ const accumulated = (toolArguments.get(event.id) ?? "") + event.arguments;
1428
+ toolArguments.set(event.id, accumulated);
1429
+ const toolName = toolNames.get(event.id) ?? event.partial.contentBlocks.find((b) => b.type === "tool_call" && b.id === event.id)?.name ?? "";
1430
+ if (toolName && !toolNames.has(event.id)) {
1431
+ toolNames.set(event.id, toolName);
1432
+ }
1433
+ if (persistAssistant && activeMessageId) {
1434
+ input.onToolCallDelta?.({
1435
+ messageId: activeMessageId,
1436
+ providerToolCallId: event.id,
1437
+ toolName,
1438
+ arguments: accumulated,
1439
+ args: parsePartialJson(accumulated)
1440
+ });
1441
+ }
1442
+ }
1130
1443
  if (event.type === "thinking_delta") {
1131
1444
  if (persistAssistant && !activeMessageId) {
1132
1445
  activeMessageId = input.message.reserve("assistant", {
@@ -3069,9 +3382,8 @@ async function runPhaseLoop(config, state, registry) {
3069
3382
  }
3070
3383
  throw new Error("Phase machine exited without a stop or abort transition.");
3071
3384
  }
3072
- var DEFAULT_MAX_RETRIES = 3;
3073
- var DEFAULT_BASE_DELAY_MS = 1e3;
3074
- var DEFAULT_MAX_DELAY_MS = 3e4;
3385
+ var DEFAULT_MAX_RETRIES = 10;
3386
+ var DEFAULT_RETRY_DELAY_MS = 5e3;
3075
3387
  function isRetryableError(error) {
3076
3388
  if (!(error instanceof Error)) return false;
3077
3389
  const message = error.message.toLowerCase();
@@ -3082,21 +3394,36 @@ function isRetryableError(error) {
3082
3394
  if (message.includes("service unavailable") || message.includes("503")) return true;
3083
3395
  if (message.includes("gateway timeout") || message.includes("504")) return true;
3084
3396
  if (message.includes("econnreset") || message.includes("econnrefused")) return true;
3397
+ if (message.includes("socket connection was closed") || message.includes("socket hang up")) return true;
3398
+ if (message.includes("fetch failed") || message.includes("etimedout")) return true;
3399
+ if (message.includes("network") || message.includes("connection reset")) return true;
3085
3400
  if ("code" in error) {
3086
3401
  const code = error.code;
3087
3402
  if (code === "invalid_model_schema" || code === "empty_response") return true;
3088
3403
  }
3089
3404
  return false;
3090
3405
  }
3091
- function getRetryDelay(attempt, baseMs, maxMs) {
3092
- const exponential = baseMs * Math.pow(2, attempt);
3093
- const jitter = exponential * (0.5 + Math.random() * 0.5);
3094
- return Math.min(jitter, maxMs);
3406
+ function sleepAbortable(delayMs, signal) {
3407
+ return new Promise((resolve9) => {
3408
+ if (signal?.aborted) {
3409
+ resolve9();
3410
+ return;
3411
+ }
3412
+ const onAbort = () => {
3413
+ clearTimeout(timer);
3414
+ signal?.removeEventListener("abort", onAbort);
3415
+ resolve9();
3416
+ };
3417
+ const timer = setTimeout(() => {
3418
+ signal?.removeEventListener("abort", onAbort);
3419
+ resolve9();
3420
+ }, delayMs);
3421
+ signal?.addEventListener("abort", onAbort, { once: true });
3422
+ });
3095
3423
  }
3096
3424
  async function withRetry(fn, options = {}) {
3097
3425
  const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
3098
- const baseDelayMs = options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
3099
- const maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
3426
+ const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
3100
3427
  let lastError;
3101
3428
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
3102
3429
  try {
@@ -3109,9 +3436,9 @@ async function withRetry(fn, options = {}) {
3109
3436
  if (options.signal?.aborted) {
3110
3437
  throw error;
3111
3438
  }
3112
- const delayMs = getRetryDelay(attempt, baseDelayMs, maxDelayMs);
3113
- options.onRetry?.(attempt, error, delayMs);
3114
- await new Promise((resolve9) => setTimeout(resolve9, delayMs));
3439
+ const retryAttempt = attempt + 1;
3440
+ options.onRetry?.(retryAttempt, error, retryDelayMs, maxRetries);
3441
+ await sleepAbortable(retryDelayMs, options.signal);
3115
3442
  if (options.signal?.aborted) {
3116
3443
  throw lastError;
3117
3444
  }
@@ -3272,12 +3599,20 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3272
3599
  request,
3273
3600
  phaseId: phase.name,
3274
3601
  output: options.output,
3275
- onThinkingDelta: config.onThinkingDelta
3602
+ onThinkingDelta: config.onThinkingDelta,
3603
+ onToolCallDelta: config.onToolCallDelta
3276
3604
  }),
3277
3605
  {
3278
3606
  signal: config.signal,
3279
- onRetry: () => {
3607
+ retryDelayMs: config.retryDelayMs,
3608
+ onRetry: (attempt, error, delayMs, maxRetries) => {
3280
3609
  state.metrics.retryCount++;
3610
+ config.onModelRetry?.({
3611
+ attempt,
3612
+ maxRetries,
3613
+ delayMs,
3614
+ error: error instanceof Error ? error.message : String(error)
3615
+ });
3281
3616
  }
3282
3617
  }
3283
3618
  )
@@ -3571,6 +3906,9 @@ async function executeOnce(input) {
3571
3906
  onParallelPhaseOutput: input.onParallelPhaseOutput,
3572
3907
  onMessageDelta: input.onMessageDelta,
3573
3908
  onThinkingDelta: input.onThinkingDelta,
3909
+ onToolCallDelta: input.onToolCallDelta,
3910
+ onModelRetry: input.onModelRetry,
3911
+ retryDelayMs: input.retryDelayMs,
3574
3912
  onOutcome: input.onOutcome,
3575
3913
  onModelTranscript: input.onModelTranscript,
3576
3914
  onPhaseEntered: input.onPhaseEntered,
@@ -4567,6 +4905,7 @@ function projectTool(tool, agentId, runId) {
4567
4905
  agentId,
4568
4906
  runId,
4569
4907
  toolCallId: context.toolCallId,
4908
+ providerToolCallId: context.toolCallId,
4570
4909
  reportProgress: () => void 0,
4571
4910
  interaction: context.interaction ?? inertRunInteraction(signal)
4572
4911
  }, signal ?? new AbortController().signal);
@@ -4709,6 +5048,11 @@ var TransientRunEventSubscription = class {
4709
5048
  ...previous,
4710
5049
  text: previous.text + event.text
4711
5050
  };
5051
+ } else if (
5052
+ // `arguments` accumulates, so the latest delta of a call replaces the one before.
5053
+ previous?.kind === "tool_call_delta" && event.kind === "tool_call_delta" && previous.executionId === event.executionId && previous.providerToolCallId === event.providerToolCallId
5054
+ ) {
5055
+ this.queue[this.queue.length - 1] = event;
4712
5056
  } else {
4713
5057
  if (this.queue.length >= MAX_BUFFERED_EVENTS) this.queue.shift();
4714
5058
  this.queue.push(event);
@@ -4734,7 +5078,7 @@ var TransientRunEventSubscription = class {
4734
5078
  clearMessage(messageId) {
4735
5079
  for (let index = this.queue.length - 1; index >= 0; index -= 1) {
4736
5080
  const event = this.queue[index];
4737
- if ((event?.kind === "message_delta" || event?.kind === "thinking_delta") && event.messageId === messageId) this.queue.splice(index, 1);
5081
+ if ((event?.kind === "message_delta" || event?.kind === "thinking_delta" || event?.kind === "tool_call_delta") && event.messageId === messageId) this.queue.splice(index, 1);
4738
5082
  }
4739
5083
  this.notify();
4740
5084
  }
@@ -6576,7 +6920,7 @@ async function spillLargeToolResult(result, archiveDir, toolName) {
6576
6920
  const serialized = typeof result.content === "string" ? result.content : JSON.stringify(result.content, null, 2);
6577
6921
  if (serialized === void 0) return result;
6578
6922
  const bytes = new TextEncoder().encode(serialized);
6579
- if (bytes.byteLength <= MAX_INLINE_TOOL_RESULT_BYTES || /\nFull result:\s+\S+/.test(serialized)) {
6923
+ if (bytes.byteLength <= MAX_INLINE_TOOL_RESULT_BYTES || /(?:\[Full result:\s+[^\]]+\]|\nFull result:\s+\S+)/.test(serialized)) {
6580
6924
  return result;
6581
6925
  }
6582
6926
  const toolDir = archiveDir;
@@ -6591,8 +6935,8 @@ async function spillLargeToolResult(result, archiveDir, toolName) {
6591
6935
  ...result,
6592
6936
  content: `${preview}
6593
6937
  [truncated]
6594
- Full result: ${path}
6595
- Offset: 0`
6938
+
6939
+ [Full result: ${path}, offset 0]`
6596
6940
  };
6597
6941
  }
6598
6942
  var AgentRuntime = class _AgentRuntime {
@@ -6614,6 +6958,7 @@ var AgentRuntime = class _AgentRuntime {
6614
6958
  heartbeat;
6615
6959
  pumping = false;
6616
6960
  closed = false;
6961
+ retryDelayMs;
6617
6962
  constructor(options, owned, resources) {
6618
6963
  this.host = options.host;
6619
6964
  this.owned = owned;
@@ -6621,6 +6966,7 @@ var AgentRuntime = class _AgentRuntime {
6621
6966
  this.storeIncarnation = String(owned.lease.token).split(":")[0];
6622
6967
  this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
6623
6968
  this.resources = resources;
6969
+ this.retryDelayMs = options.retryDelayMs;
6624
6970
  }
6625
6971
  static async init(options) {
6626
6972
  if (!options.store) throw new TypeError("AgentRuntime requires a DurableStore");
@@ -7101,9 +7447,9 @@ var AgentRuntime = class _AgentRuntime {
7101
7447
  interactionAnswers: claim.run.interactionAnswers,
7102
7448
  signal: controller.signal,
7103
7449
  beforePhase: assembly.beforePhase,
7104
- afterPhase: async (phaseId, output) => {
7105
- const extAfter = assembly.afterPhase ? await assembly.afterPhase(phaseId, output) : {};
7106
- const effectiveOutput = extAfter.output ?? output;
7450
+ afterPhase: async (phaseId, output2) => {
7451
+ const extAfter = assembly.afterPhase ? await assembly.afterPhase(phaseId, output2) : {};
7452
+ const effectiveOutput = extAfter.output ?? output2;
7107
7453
  if (!extAfter.abort && (phaseId === COMPACT_PHASE_ID || isCompactionOutcome(effectiveOutput.payload))) {
7108
7454
  const active = this.executions.get(run.id);
7109
7455
  if (active?.executionId === claim.execution.executionId && !this.cancellationRequested.has(run.id) && !controller.signal.aborted) {
@@ -7155,7 +7501,7 @@ var AgentRuntime = class _AgentRuntime {
7155
7501
  const active = this.executions.get(run.id);
7156
7502
  if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
7157
7503
  const projected = projectAssistantMessage(message, run.agentId, run.id, 0);
7158
- const committed = await this.owned.commitPhaseOutput({
7504
+ const committed2 = await this.owned.commitPhaseOutput({
7159
7505
  runId: run.id,
7160
7506
  execution: claim.execution,
7161
7507
  expectedRevision: executionRevision,
@@ -7172,7 +7518,7 @@ var AgentRuntime = class _AgentRuntime {
7172
7518
  }
7173
7519
  }
7174
7520
  });
7175
- executionRevision = committed.revision;
7521
+ executionRevision = committed2.revision;
7176
7522
  });
7177
7523
  toolQueue = task.then(() => void 0, () => void 0);
7178
7524
  return task;
@@ -7204,6 +7550,36 @@ var AgentRuntime = class _AgentRuntime {
7204
7550
  text: event.text
7205
7551
  });
7206
7552
  },
7553
+ onToolCallDelta: (event) => {
7554
+ const active = this.executions.get(run.id);
7555
+ if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
7556
+ this.transientEvents.publish({
7557
+ kind: "tool_call_delta",
7558
+ durability: "transient",
7559
+ runId: run.id,
7560
+ executionId: claim.execution.executionId,
7561
+ messageId: event.messageId,
7562
+ providerToolCallId: event.providerToolCallId,
7563
+ toolName: event.toolName,
7564
+ arguments: event.arguments,
7565
+ args: event.args
7566
+ });
7567
+ },
7568
+ onModelRetry: (event) => {
7569
+ const active = this.executions.get(run.id);
7570
+ if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
7571
+ this.transientEvents.publish({
7572
+ kind: "model_retry",
7573
+ durability: "transient",
7574
+ runId: run.id,
7575
+ executionId: claim.execution.executionId,
7576
+ attempt: event.attempt,
7577
+ maxRetries: event.maxRetries,
7578
+ delayMs: event.delayMs,
7579
+ error: event.error
7580
+ });
7581
+ },
7582
+ retryDelayMs: this.retryDelayMs,
7207
7583
  onContext: assembly.setContext,
7208
7584
  runtime: {
7209
7585
  tools: ({ toolCall, contentBlocks, driver }) => {
@@ -7264,13 +7640,13 @@ var AgentRuntime = class _AgentRuntime {
7264
7640
  }
7265
7641
  }
7266
7642
  if (this.cancellationRequested.has(run.id) || controller.signal.aborted) {
7267
- const output = latestAssistant(run, result.messages, executionContext.messages.length, true);
7643
+ const output2 = latestAssistant(run, result.messages, executionContext.messages.length, true);
7268
7644
  const reason = this.cancellationReasons.get(run.id) ?? "Agent run stopped.";
7269
7645
  await this.owned.cancelRun({
7270
7646
  runId: run.id,
7271
7647
  expectedRevision: executionRevision,
7272
7648
  reason,
7273
- ...output && hasVisibleAssistantText(output) ? { output } : {}
7649
+ ...output2 && hasVisibleAssistantText(output2) ? { output: output2 } : {}
7274
7650
  });
7275
7651
  this.transientEvents.clear(run.id, claim.execution.executionId);
7276
7652
  await this.handleRunEnd(run.id, run.agentId, {
@@ -7289,12 +7665,12 @@ var AgentRuntime = class _AgentRuntime {
7289
7665
  pendingToolCallIds = result.interactions.map(({ toolCallId }) => toolCallId);
7290
7666
  }
7291
7667
  const isToolCallInteraction = result.interactions?.some((i) => i.toolCallId !== void 0);
7292
- const output = isToolCallInteraction ? void 0 : latestAssistant(
7668
+ const output2 = isToolCallInteraction ? void 0 : latestAssistant(
7293
7669
  run,
7294
7670
  result.messages,
7295
7671
  executionContext.messages.length
7296
7672
  );
7297
- const prompt = isToolCallInteraction ? void 0 : output ?? (result.interactions[0]?.prompt ? promptMessage(run, result.interactions[0].prompt, result.messages.length) : void 0);
7673
+ const prompt = isToolCallInteraction ? void 0 : output2 ?? (result.interactions[0]?.prompt ? promptMessage(run, result.interactions[0].prompt, result.messages.length) : void 0);
7298
7674
  await this.owned.commitInputRequired({
7299
7675
  runId: run.id,
7300
7676
  execution: claim.execution,
@@ -7310,20 +7686,27 @@ var AgentRuntime = class _AgentRuntime {
7310
7686
  return;
7311
7687
  }
7312
7688
  if (result.type === "completed") {
7313
- const output = latestAssistant(run, result.messages, executionContext.messages.length);
7314
- await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...output ? { output } : {} });
7689
+ const output2 = latestAssistant(run, result.messages, executionContext.messages.length);
7690
+ await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...output2 ? { output: output2 } : {} });
7315
7691
  this.transientEvents.clear(run.id, claim.execution.executionId, true);
7316
7692
  await this.handleRunEnd(run.id, run.agentId, result.outcome);
7317
7693
  return;
7318
7694
  }
7695
+ const output = latestAssistant(run, result.messages, executionContext.messages.length);
7319
7696
  const failure = { code: "execution_failed", message: result.error instanceof Error ? result.error.message : "Execution failed." };
7320
- await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, failure });
7697
+ const committed = await this.owned.commitOutcome({
7698
+ runId: run.id,
7699
+ execution: claim.execution,
7700
+ expectedRevision: executionRevision,
7701
+ failure,
7702
+ ...output ? { output } : {}
7703
+ });
7321
7704
  this.transientEvents.clear(run.id, claim.execution.executionId);
7322
7705
  await this.handleRunEnd(run.id, run.agentId, {
7323
7706
  id: createId("out"),
7324
7707
  status: "failed",
7325
7708
  message: failure.message,
7326
- error: failure
7709
+ error: committed.failure ?? failure
7327
7710
  });
7328
7711
  } catch (error) {
7329
7712
  if (!claim && error instanceof RuntimeError && ["run_state_conflict", "runtime_ownership_lost", "run_not_found"].includes(error.code)) return;
@@ -7343,7 +7726,7 @@ var AgentRuntime = class _AgentRuntime {
7343
7726
  return;
7344
7727
  }
7345
7728
  const failureMessage = error instanceof Error ? error.message : "Execution failed.";
7346
- await this.owned.commitOutcome({
7729
+ const committed = await this.owned.commitOutcome({
7347
7730
  runId: run.id,
7348
7731
  execution: claim.execution,
7349
7732
  expectedRevision: executionRevision,
@@ -7353,12 +7736,13 @@ var AgentRuntime = class _AgentRuntime {
7353
7736
  runId: run.id,
7354
7737
  reason: commitError instanceof Error ? commitError.message : "Run failure could not be committed."
7355
7738
  }).catch(() => void 0);
7739
+ return void 0;
7356
7740
  });
7357
7741
  await this.handleRunEnd(run.id, run.agentId, {
7358
7742
  id: createId("out"),
7359
7743
  status: "failed",
7360
7744
  message: failureMessage,
7361
- error: { code: "execution_failed", message: failureMessage }
7745
+ error: committed?.failure ?? { code: "execution_failed", message: failureMessage }
7362
7746
  });
7363
7747
  return;
7364
7748
  }
@@ -7410,6 +7794,7 @@ var AgentRuntime = class _AgentRuntime {
7410
7794
  ...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
7411
7795
  ...input.run.metadata === void 0 ? {} : { runMetadata: input.run.metadata },
7412
7796
  toolCallId,
7797
+ providerToolCallId: toolCall.id,
7413
7798
  scope,
7414
7799
  turn,
7415
7800
  interaction: createRunInteractionDriver({
@@ -7499,6 +7884,7 @@ var AgentRuntime = class _AgentRuntime {
7499
7884
  ...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
7500
7885
  ...input.run.metadata === void 0 ? {} : { runMetadata: input.run.metadata },
7501
7886
  toolCallId,
7887
+ providerToolCallId,
7502
7888
  scope,
7503
7889
  turn,
7504
7890
  interaction: createToolInteractionDriver(input.driver, {
@@ -7655,6 +8041,7 @@ var AgentRuntime = class _AgentRuntime {
7655
8041
  ...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
7656
8042
  ...input.run.metadata === void 0 ? {} : { runMetadata: input.run.metadata },
7657
8043
  toolCallId,
8044
+ providerToolCallId,
7658
8045
  scope,
7659
8046
  turn,
7660
8047
  interaction: createToolInteractionDriver(input.driver, {
@@ -9203,7 +9590,11 @@ var InMemoryStore = class _InMemoryStore {
9203
9590
  }
9204
9591
  run.state = nextState;
9205
9592
  if (input.outcome) run.outcome = clone(input.outcome);
9206
- if (input.failure) run.failure = clone(input.failure);
9593
+ let failure = input.failure ? clone(input.failure) : void 0;
9594
+ if (nextState === "failed" && failure) {
9595
+ failure = this.withdrawUserInputIfNoOutput(run, failure, output);
9596
+ run.failure = failure;
9597
+ }
9207
9598
  this.dropClaimReceipt(run.execution);
9208
9599
  delete run.execution;
9209
9600
  delete run.openInteractions;
@@ -9211,7 +9602,7 @@ var InMemoryStore = class _InMemoryStore {
9211
9602
  run.revision += 1;
9212
9603
  run.updatedAt = createTimestamp();
9213
9604
  this.touchRun(run);
9214
- this.appendTransition(run, "running", nextState, { outcome: input.outcome, failure: input.failure, output });
9605
+ this.appendTransition(run, "running", nextState, { outcome: input.outcome, failure, output });
9215
9606
  this.dropRunOperationReceipts(run.id);
9216
9607
  const result = clone(run);
9217
9608
  return result;
@@ -9586,6 +9977,28 @@ var InMemoryStore = class _InMemoryStore {
9586
9977
  messagesForRun(runId) {
9587
9978
  return [...this.messages.values()].filter((message) => message.runId === runId).sort((a, b) => a.sequenceWithinRun - b.sequenceWithinRun);
9588
9979
  }
9980
+ withdrawUserInputIfNoOutput(run, failure, output) {
9981
+ const runMessages = this.messagesForRun(run.id);
9982
+ const hasAssistantMessage = runMessages.some((m) => m.role === "assistant") || output !== void 0;
9983
+ const hasToolMessage = runMessages.some((m) => m.role === "tool");
9984
+ const hasToolCalls = [...this.toolCalls.values()].some((tc) => tc.runId === run.id);
9985
+ if (hasAssistantMessage || hasToolMessage || hasToolCalls) {
9986
+ return failure;
9987
+ }
9988
+ const userInputMessage = runMessages.find((m) => m.role === "user");
9989
+ if (!userInputMessage) {
9990
+ return failure;
9991
+ }
9992
+ this.messages.delete(userInputMessage.id);
9993
+ this.recorder?.onMessageDelete(userInputMessage.id);
9994
+ return {
9995
+ ...failure,
9996
+ withdrawnInput: {
9997
+ messageId: userInputMessage.id,
9998
+ content: clone(userInputMessage.content)
9999
+ }
10000
+ };
10001
+ }
9589
10002
  history(lease, agentId) {
9590
10003
  this.assertOwner(lease);
9591
10004
  this.requireAgent(agentId);
@@ -9678,7 +10091,10 @@ ${record.summary}`,
9678
10091
  to,
9679
10092
  ...to === "input_required" ? { interactions: clone(options?.interactions ?? []), answers: clone(options?.answers ?? {}) } : {},
9680
10093
  ...to === "completed" && options?.outcome ? { outcome: options.outcome, ...options.output ? { output: options.output } : {} } : {},
9681
- ...to === "failed" && options?.failure ? { failure: options.failure } : {},
10094
+ ...to === "failed" && options?.failure ? {
10095
+ failure: options.failure,
10096
+ ...options.failure.withdrawnInput ? { withdrawnInput: options.failure.withdrawnInput } : {}
10097
+ } : {},
9682
10098
  ...to === "cancelled" && options?.reason ? { reason: options.reason } : {}
9683
10099
  };
9684
10100
  this.touchRun(run);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",