@rowan-agent/agent 0.6.0 → 0.6.2

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 (4) hide show
  1. package/README.md +137 -60
  2. package/dist/index.d.ts +212 -145
  3. package/dist/index.js +678 -295
  4. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -521,10 +521,10 @@ ${indent}</${tag}>`;
521
521
  return `${indent}<${tag}>${escapeXml(String(val))}</${tag}>`;
522
522
  }).join("\n");
523
523
  }
524
- function buildPhaseDirectiveMessage(phase, output, toolUseId) {
524
+ function buildPhaseDirectiveMessage(phase, output) {
525
525
  const parts = [];
526
- parts.push(`<phase name="${escapeXml(phase.name)}">`);
527
- parts.push(` <content>${phase.content}</content>`);
526
+ parts.push(`<phase_content name="${escapeXml(phase.name)}">`);
527
+ parts.push(phase.content);
528
528
  if (output.results && output.results.length > 0) {
529
529
  parts.push(` <prev_phase_outputs>`);
530
530
  if (output.instruction) {
@@ -539,13 +539,8 @@ function buildPhaseDirectiveMessage(phase, output, toolUseId) {
539
539
  }
540
540
  parts.push(` </prev_phase_outputs>`);
541
541
  }
542
- parts.push(`</phase>`);
543
- return [{
544
- type: "tool_result",
545
- toolUseId,
546
- content: parts.join("\n"),
547
- isError: false
548
- }];
542
+ parts.push(`</phase_content>`);
543
+ return parts.join("\n");
549
544
  }
550
545
 
551
546
  // src/harness/phases/loader.ts
@@ -781,34 +776,27 @@ var DEFAULT_MAX_READ_BYTES = 64e3;
781
776
  var DEFAULT_BASH_TIMEOUT_MS = 3e4;
782
777
  var DEFAULT_MAX_BASH_OUTPUT_BYTES = 64e3;
783
778
  var ReadArgsSchema = Type2.Object({
784
- path: Type2.String(),
785
- maxBytes: Type2.Optional(Type2.Number()),
786
- type: Type2.Optional(Type2.Union([
787
- Type2.Literal("skill"),
788
- Type2.Literal("phase"),
789
- Type2.Literal("markdown"),
790
- Type2.Literal("code"),
791
- Type2.Literal("file")
792
- ]))
779
+ path: Type2.String({ description: "Path to the file to read." }),
780
+ offset: Type2.Optional(Type2.Number({ description: "1-based line to start from." })),
781
+ limit: Type2.Optional(Type2.Number({ description: "Maximum number of lines." }))
793
782
  });
794
783
  var ReadArgsValidator = Schema.Compile(ReadArgsSchema);
795
784
  var WriteArgsSchema = Type2.Object({
796
- path: Type2.String(),
797
- content: Type2.String()
785
+ path: Type2.String({ description: "Path to the file to write." }),
786
+ content: Type2.String({ description: "Complete file contents." })
798
787
  });
799
788
  var WriteArgsValidator = Schema.Compile(WriteArgsSchema);
800
789
  var EditArgsSchema = Type2.Object({
801
- path: Type2.String(),
802
- oldText: Type2.String(),
803
- newText: Type2.String(),
804
- replaceAll: Type2.Optional(Type2.Boolean())
790
+ path: Type2.String({ description: "Path to the file to edit." }),
791
+ edits: Type2.Array(Type2.Object({
792
+ oldText: Type2.String({ description: "Exact unique text to replace." }),
793
+ newText: Type2.String({ description: "Replacement text." })
794
+ }), { description: "One or more non-overlapping replacements." })
805
795
  });
806
796
  var EditArgsValidator = Schema.Compile(EditArgsSchema);
807
797
  var BashArgsSchema = Type2.Object({
808
- command: Type2.String(),
809
- cwd: Type2.Optional(Type2.String()),
810
- timeoutMs: Type2.Optional(Type2.Number()),
811
- maxOutputBytes: Type2.Optional(Type2.Number())
798
+ command: Type2.String({ description: "Bash command to execute." }),
799
+ timeout: Type2.Optional(Type2.Number({ description: "Timeout in seconds." }))
812
800
  });
813
801
  var BashArgsValidator = Schema.Compile(BashArgsSchema);
814
802
  var validatorCache = /* @__PURE__ */ new WeakMap();
@@ -911,12 +899,7 @@ async function executeRuntimeToolCall(input) {
911
899
  }
912
900
  await input.observe?.({ type: "tool_start", tool, args });
913
901
  try {
914
- const rawResult = await tool.execute(args, input.toolContext, input.signal);
915
- let result = {
916
- ...rawResult,
917
- toolCallId: input.toolCall.id,
918
- toolName: tool.name
919
- };
902
+ let result = await tool.execute(args, input.toolContext, input.signal);
920
903
  if (input.afterToolCall) {
921
904
  await input.observe?.({
922
905
  type: "result_review_requested",
@@ -950,6 +933,20 @@ function positiveNumber(value, name) {
950
933
  }
951
934
  return void 0;
952
935
  }
936
+ function positiveInteger(value, name) {
937
+ if (!Number.isInteger(value) || value <= 0) {
938
+ return `${name} must be a positive integer.`;
939
+ }
940
+ return void 0;
941
+ }
942
+ function readTextLines(text, offset, limit) {
943
+ if (offset === void 0 && limit === void 0) {
944
+ return text;
945
+ }
946
+ const start = (offset ?? 1) - 1;
947
+ const lines = text.split(/\r\n|\n|\r/);
948
+ return lines.slice(start, limit === void 0 ? void 0 : start + limit).join("\n");
949
+ }
953
950
  async function captureStream(stream, maxBytes) {
954
951
  const reader = stream.getReader();
955
952
  const chunks = [];
@@ -989,17 +986,25 @@ async function captureStream(stream, maxBytes) {
989
986
  function createReadTool(context) {
990
987
  return {
991
988
  name: "read",
992
- description: "Reads a text file within the workspace.",
989
+ description: "Read a file in the workspace.",
993
990
  parameters: ReadArgsSchema,
994
- promptSnippet: "Read a text file (max 64KB default).",
995
- promptGuidelines: [
996
- "Always read a file before editing or writing to understand its current content.",
997
- "Use maxBytes to limit output for large files."
998
- ],
991
+ promptSnippet: "Read file contents.",
992
+ promptGuidelines: ["Read files before editing them."],
999
993
  async execute(args, toolContext) {
1000
994
  const parsed = ReadArgsValidator.Parse(args);
995
+ const offsetError = parsed.offset === void 0 ? void 0 : positiveInteger(parsed.offset, "offset");
996
+ const limitError = parsed.limit === void 0 ? void 0 : positiveInteger(parsed.limit, "limit");
997
+ if (offsetError || limitError) {
998
+ return toolResult({
999
+ context: toolContext,
1000
+ toolName: "read",
1001
+ ok: false,
1002
+ content: null,
1003
+ error: offsetError ?? limitError
1004
+ });
1005
+ }
1001
1006
  const resolved = resolveCoreToolPath(context, parsed.path);
1002
- const maxBytes = parsed.maxBytes ?? context.maxReadBytes;
1007
+ const maxBytes = context.maxReadBytes;
1003
1008
  const invalidLimit = positiveNumber(maxBytes, "maxBytes");
1004
1009
  if (invalidLimit) {
1005
1010
  return toolResult({
@@ -1021,9 +1026,12 @@ function createReadTool(context) {
1021
1026
  });
1022
1027
  }
1023
1028
  const bytes = await readFile2(resolved.absolutePath);
1024
- const sliced = bytes.subarray(0, maxBytes);
1029
+ const source = new TextDecoder().decode(bytes);
1030
+ const selected = readTextLines(source, parsed.offset, parsed.limit);
1031
+ const selectedBytes = new TextEncoder().encode(selected);
1032
+ const sliced = selectedBytes.subarray(0, maxBytes);
1025
1033
  const text = new TextDecoder().decode(sliced);
1026
- const resourceType = parsed.type ?? detectResourceType(resolved.absolutePath);
1034
+ const resourceType = detectResourceType(resolved.absolutePath);
1027
1035
  let name;
1028
1036
  let baseDir;
1029
1037
  if (resourceType === "skill" || resourceType === "phase") {
@@ -1034,16 +1042,14 @@ function createReadTool(context) {
1034
1042
  } else {
1035
1043
  name = inferResourceName(resolved.absolutePath, basename2(resolved.absolutePath));
1036
1044
  }
1045
+ const formatted = resourceType === "skill" || resourceType === "phase" ? formatResourceOutput({ type: resourceType, name, location: resolved.absolutePath, content: text, baseDir }) : text;
1046
+ const content = selectedBytes.byteLength > maxBytes ? `${formatted}
1047
+ [truncated]` : formatted;
1037
1048
  return toolResult({
1038
1049
  context: toolContext,
1039
1050
  toolName: "read",
1040
1051
  ok: true,
1041
- content: {
1042
- path: resolved.relativePath,
1043
- content: formatResourceOutput({ type: resourceType, name, location: resolved.absolutePath, content: text, baseDir }),
1044
- sizeBytes: bytes.byteLength,
1045
- truncated: bytes.byteLength > maxBytes
1046
- }
1052
+ content
1047
1053
  });
1048
1054
  }
1049
1055
  };
@@ -1051,13 +1057,10 @@ function createReadTool(context) {
1051
1057
  function createWriteTool(context) {
1052
1058
  return {
1053
1059
  name: "write",
1054
- description: "Writes provided text content to a workspace file, creating parent directories as needed.",
1060
+ description: "Create or overwrite a file in the workspace.",
1055
1061
  parameters: WriteArgsSchema,
1056
- promptSnippet: "Write content to a file (creates parent dirs automatically).",
1057
- promptGuidelines: [
1058
- "Use write for new files or full file rewrites.",
1059
- "For partial edits, prefer the edit tool to avoid overwriting unchanged content."
1060
- ],
1062
+ promptSnippet: "Create or overwrite files.",
1063
+ promptGuidelines: ["Use edit for partial changes."],
1061
1064
  async execute(args, toolContext) {
1062
1065
  const parsed = WriteArgsValidator.Parse(args);
1063
1066
  const resolved = resolveCoreToolPath(context, parsed.path);
@@ -1067,69 +1070,74 @@ function createWriteTool(context) {
1067
1070
  context: toolContext,
1068
1071
  toolName: "write",
1069
1072
  ok: true,
1070
- content: {
1071
- path: resolved.relativePath,
1072
- bytesWritten: new TextEncoder().encode(parsed.content).byteLength
1073
- }
1073
+ content: `Successfully wrote ${parsed.content.length} bytes to ${resolved.relativePath}.`
1074
1074
  });
1075
1075
  }
1076
1076
  };
1077
1077
  }
1078
+ function applyEditReplacements(current, edits) {
1079
+ if (edits.length === 0) {
1080
+ throw new Error("edits must contain at least one replacement.");
1081
+ }
1082
+ const matches = [];
1083
+ for (const edit of edits) {
1084
+ if (!edit.oldText) throw new Error("oldText must not be empty.");
1085
+ const start = current.indexOf(edit.oldText);
1086
+ if (start < 0) throw new Error(`oldText not found in file.`);
1087
+ const second = current.indexOf(edit.oldText, start + edit.oldText.length);
1088
+ if (second >= 0) {
1089
+ const count = current.split(edit.oldText).length - 1;
1090
+ throw new Error(`oldText appears ${count} times; provide more context.`);
1091
+ }
1092
+ matches.push({ start, end: start + edit.oldText.length, newText: edit.newText });
1093
+ }
1094
+ matches.sort((a, b) => a.start - b.start);
1095
+ for (let index = 1; index < matches.length; index += 1) {
1096
+ const previous = matches[index - 1];
1097
+ const currentMatch = matches[index];
1098
+ if (currentMatch.start < previous.end) {
1099
+ throw new Error("edits must not overlap.");
1100
+ }
1101
+ }
1102
+ let content = current;
1103
+ for (let index = matches.length - 1; index >= 0; index -= 1) {
1104
+ const match = matches[index];
1105
+ content = content.slice(0, match.start) + match.newText + content.slice(match.end);
1106
+ }
1107
+ return { content, replacements: matches.length };
1108
+ }
1078
1109
  function createEditTool(context) {
1079
1110
  return {
1080
1111
  name: "edit",
1081
- description: "Edits a workspace text file by replacing exact oldText with newText.",
1112
+ description: "Apply exact text replacements to a workspace file.",
1082
1113
  parameters: EditArgsSchema,
1083
- promptSnippet: "Replace exact text in a file (oldText \u2192 newText).",
1084
- promptGuidelines: [
1085
- "Read the file first to get the exact oldText to replace.",
1086
- "oldText must be an exact match including whitespace and indentation.",
1087
- "If oldText appears multiple times, set replaceAll=true or provide more surrounding context."
1088
- ],
1114
+ promptSnippet: "Apply exact text replacements.",
1115
+ promptGuidelines: ["Read the file first; each oldText must match exactly once."],
1089
1116
  async execute(args, toolContext) {
1090
1117
  const parsed = EditArgsValidator.Parse(args);
1091
- if (!parsed.oldText) {
1092
- return toolResult({
1093
- context: toolContext,
1094
- toolName: "edit",
1095
- ok: false,
1096
- content: null,
1097
- error: "oldText must not be empty."
1098
- });
1099
- }
1100
1118
  const resolved = resolveCoreToolPath(context, parsed.path);
1101
1119
  const current = await readFile2(resolved.absolutePath, "utf8");
1102
- if (!current.includes(parsed.oldText)) {
1103
- return toolResult({
1104
- context: toolContext,
1105
- toolName: "edit",
1106
- ok: false,
1107
- content: null,
1108
- error: `oldText not found in ${resolved.relativePath}.`
1109
- });
1110
- }
1111
- const matches = current.split(parsed.oldText).length - 1;
1112
- if (matches > 1 && !parsed.replaceAll) {
1120
+ let next;
1121
+ let replacements;
1122
+ try {
1123
+ const result = applyEditReplacements(current, parsed.edits);
1124
+ next = result.content;
1125
+ replacements = result.replacements;
1126
+ } catch (error) {
1113
1127
  return toolResult({
1114
1128
  context: toolContext,
1115
1129
  toolName: "edit",
1116
1130
  ok: false,
1117
1131
  content: null,
1118
- error: `oldText appears ${matches} times in ${resolved.relativePath}; set replaceAll=true or provide more context.`
1132
+ error: error instanceof Error ? error.message : String(error)
1119
1133
  });
1120
1134
  }
1121
- const replacements = parsed.replaceAll ? matches : 1;
1122
- const next = parsed.replaceAll ? current.split(parsed.oldText).join(parsed.newText) : current.replace(parsed.oldText, parsed.newText);
1123
1135
  await writeFile(resolved.absolutePath, next, "utf8");
1124
1136
  return toolResult({
1125
1137
  context: toolContext,
1126
1138
  toolName: "edit",
1127
1139
  ok: true,
1128
- content: {
1129
- path: resolved.relativePath,
1130
- replacements,
1131
- bytesWritten: new TextEncoder().encode(next).byteLength
1132
- }
1140
+ content: `Successfully replaced ${replacements} block(s) in ${resolved.relativePath}.`
1133
1141
  });
1134
1142
  }
1135
1143
  };
@@ -1137,19 +1145,15 @@ function createEditTool(context) {
1137
1145
  function createBashTool(context) {
1138
1146
  return {
1139
1147
  name: "bash",
1140
- description: "Runs a bash command within the workspace.",
1148
+ description: "Run a bash command in the workspace.",
1141
1149
  parameters: BashArgsSchema,
1142
- promptSnippet: "Execute a bash command (30s timeout, 64KB output limit).",
1143
- promptGuidelines: [
1144
- "Use bash for build commands, tests, git operations, and system tools.",
1145
- "Prefer dedicated tools (read/write/edit) for file operations.",
1146
- "Set timeoutMs for long-running commands."
1147
- ],
1150
+ promptSnippet: "Run shell commands.",
1151
+ promptGuidelines: ["Use read/write/edit for file operations."],
1148
1152
  async execute(args, toolContext, signal) {
1149
1153
  const parsed = BashArgsValidator.Parse(args);
1150
- const timeoutMs = parsed.timeoutMs ?? context.bashTimeoutMs;
1151
- const maxOutputBytes = parsed.maxOutputBytes ?? context.maxBashOutputBytes;
1152
- const invalidTimeout = positiveNumber(timeoutMs, "timeoutMs");
1154
+ const timeoutMs = parsed.timeout === void 0 ? context.bashTimeoutMs : parsed.timeout * 1e3;
1155
+ const maxOutputBytes = context.maxBashOutputBytes;
1156
+ const invalidTimeout = positiveNumber(timeoutMs, "timeout");
1153
1157
  const invalidOutputLimit = positiveNumber(maxOutputBytes, "maxOutputBytes");
1154
1158
  if (invalidTimeout || invalidOutputLimit) {
1155
1159
  return toolResult({
@@ -1160,7 +1164,7 @@ function createBashTool(context) {
1160
1164
  error: invalidTimeout ?? invalidOutputLimit
1161
1165
  });
1162
1166
  }
1163
- const cwd = resolveCoreToolPath(context, parsed.cwd ?? ".");
1167
+ const cwd = resolveCoreToolPath(context, ".");
1164
1168
  let timedOut = false;
1165
1169
  let aborted = false;
1166
1170
  const proc = Bun.spawn(["bash", "-lc", parsed.command], {
@@ -1187,19 +1191,14 @@ function createBashTool(context) {
1187
1191
  proc.exited
1188
1192
  ]);
1189
1193
  const ok = exitCode === 0 && !timedOut && !aborted;
1194
+ const output = [stdout.text, stderr.text].filter(Boolean).join(stdout.text && stderr.text ? "\n" : "");
1195
+ const content = stdout.truncated || stderr.truncated ? `${output}
1196
+ [truncated]` : output;
1190
1197
  return toolResult({
1191
1198
  context: toolContext,
1192
1199
  toolName: "bash",
1193
1200
  ok,
1194
- content: {
1195
- command: parsed.command,
1196
- cwd: cwd.relativePath,
1197
- exitCode,
1198
- stdout: stdout.text,
1199
- stderr: stderr.text,
1200
- stdoutTruncated: stdout.truncated,
1201
- stderrTruncated: stderr.truncated
1202
- },
1201
+ content,
1203
1202
  ...ok ? {} : {
1204
1203
  error: timedOut ? `Command timed out after ${timeoutMs}ms.` : aborted ? "Command aborted." : `Command exited with ${exitCode}.`
1205
1204
  }
@@ -1215,9 +1214,9 @@ function createCoreTools(input = {}) {
1215
1214
  const context = createCoreToolContext(input);
1216
1215
  return [
1217
1216
  createReadTool(context),
1218
- createWriteTool(context),
1217
+ createBashTool(context),
1219
1218
  createEditTool(context),
1220
- createBashTool(context)
1219
+ createWriteTool(context)
1221
1220
  ];
1222
1221
  }
1223
1222
 
@@ -1366,11 +1365,17 @@ function compactMessages(messages, options = {}) {
1366
1365
  );
1367
1366
  const recentStart = Math.max(messages.length - keepRecent, firstUserIdx + 1);
1368
1367
  const oldMessages = messages.slice(firstUserIdx >= 0 ? firstUserIdx + 1 : 0, recentStart);
1369
- if (oldMessages.length < minCompact) {
1368
+ const protectedPhaseMessages = oldMessages.filter(
1369
+ (message) => message.metadata?.kind === "phase_prompt"
1370
+ );
1371
+ const summarizableMessages = oldMessages.filter(
1372
+ (message) => message.metadata?.kind !== "phase_prompt"
1373
+ );
1374
+ if (summarizableMessages.length < minCompact) {
1370
1375
  return { compacted: false, messages };
1371
1376
  }
1372
1377
  const recentMessages = messages.slice(recentStart);
1373
- const summary = buildSummary(oldMessages);
1378
+ const summary = buildSummary(summarizableMessages);
1374
1379
  const result = [];
1375
1380
  if (firstUserIdx >= 0) {
1376
1381
  result.push(messages[firstUserIdx]);
@@ -1380,14 +1385,15 @@ function compactMessages(messages, options = {}) {
1380
1385
 
1381
1386
  ${summary}`, {
1382
1387
  type: "compaction_summary",
1383
- compactedCount: oldMessages.length
1388
+ compactedCount: summarizableMessages.length
1384
1389
  })
1385
1390
  );
1391
+ result.push(...protectedPhaseMessages);
1386
1392
  result.push(...recentMessages);
1387
1393
  return {
1388
1394
  compacted: true,
1389
1395
  messages: result,
1390
- summarizedCount: oldMessages.length,
1396
+ summarizedCount: summarizableMessages.length,
1391
1397
  summary
1392
1398
  };
1393
1399
  }
@@ -1401,6 +1407,23 @@ function removePhaseMessage(messages, msgId) {
1401
1407
  const idx = messages.findIndex((m) => m.id === msgId);
1402
1408
  if (idx !== -1) messages.splice(idx, 1);
1403
1409
  }
1410
+ function findLatestUserInputMessage(messages) {
1411
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1412
+ const message = messages[index];
1413
+ const kind = message.metadata?.kind;
1414
+ if (message.role === "user" && kind !== "phase_prompt" && kind !== "phase_input") {
1415
+ return message;
1416
+ }
1417
+ }
1418
+ return void 0;
1419
+ }
1420
+ function moveMessageBefore(messages, messageId, targetId) {
1421
+ const messageIndex = messages.findIndex((message2) => message2.id === messageId);
1422
+ const targetIndex = messages.findIndex((message2) => message2.id === targetId);
1423
+ if (messageIndex === -1 || targetIndex === -1 || messageIndex < targetIndex) return;
1424
+ const [message] = messages.splice(messageIndex, 1);
1425
+ if (message) messages.splice(targetIndex, 0, message);
1426
+ }
1404
1427
  function normalizePayload(payload) {
1405
1428
  if (typeof payload === "string") {
1406
1429
  try {
@@ -1417,17 +1440,20 @@ function applyFirstDecision(route, output) {
1417
1440
  if (first.reason) output.routeReason = first.reason;
1418
1441
  if (first.payload !== void 0) output.payload = normalizePayload(first.payload);
1419
1442
  }
1420
- function injectPhaseContent(phase, output, messageManager) {
1443
+ function injectPhaseContent(phase, output, messages, mirror) {
1421
1444
  try {
1422
1445
  const phaseContent = phase.filePath ? readPhaseContent(phase) : phase.content ?? phase.description ?? "";
1423
1446
  const content = buildPhaseDirectiveMessage(
1424
1447
  { name: phase.id, content: phaseContent },
1425
- output,
1426
- `phase_${phase.id}`
1448
+ output
1427
1449
  );
1428
- const msgId = messageManager.start("tool", content, { phase: phase.id });
1429
- messageManager.end(msgId);
1430
- return msgId;
1450
+ const message = createMessage("user", content, {
1451
+ kind: "phase_prompt",
1452
+ phase: phase.id
1453
+ });
1454
+ messages.push(message);
1455
+ if (mirror && mirror !== messages) mirror.push(message);
1456
+ return message.id;
1431
1457
  } catch {
1432
1458
  return void 0;
1433
1459
  }
@@ -1534,6 +1560,15 @@ function createToolResultContent(result) {
1534
1560
  }
1535
1561
  ];
1536
1562
  }
1563
+ function createRouteToolResultContent(toolCall) {
1564
+ return [
1565
+ {
1566
+ type: "tool_result",
1567
+ toolUseId: toolCall.id,
1568
+ content: '{"ok": true}'
1569
+ }
1570
+ ];
1571
+ }
1537
1572
  async function executePhaseWithModel(ctx) {
1538
1573
  const executableToolNames = new Set(
1539
1574
  ctx.context.tools.filter((tool) => tool.name !== PhaseRouteTool).map((tool) => tool.name)
@@ -1556,6 +1591,13 @@ async function executePhaseWithModel(ctx) {
1556
1591
  phase: ctx.phase.name,
1557
1592
  toolCalls: collected.toolCalls
1558
1593
  };
1594
+ for (const toolCall of collected.toolCalls) {
1595
+ if (toolCall.name !== PhaseRouteTool) continue;
1596
+ const messageId = ctx.messageManager.start("tool", createRouteToolResultContent(toolCall), {
1597
+ phase: ctx.phase.id
1598
+ });
1599
+ await ctx.messageManager.end(messageId);
1600
+ }
1559
1601
  const executableToolCalls = collected.toolCalls.filter(
1560
1602
  (toolCall) => executableToolNames.has(toolCall.name)
1561
1603
  );
@@ -1590,12 +1632,17 @@ async function startPhaseLoop(config, state) {
1590
1632
  return runPhaseLoop(config, state, registry);
1591
1633
  }
1592
1634
  async function runPhaseLoop(config, state, registry) {
1593
- let currentPhaseId = registry.entryPhaseId;
1594
- let isContinuing = false;
1595
- let previousPayload = void 0;
1596
- let previousPhaseMsgId = void 0;
1597
- let previousResults = [];
1598
- let pendingInstruction = void 0;
1635
+ const resumingSuspendedRun = state.status === "suspended" && Boolean(state.currentPhase);
1636
+ let currentPhaseId = resumingSuspendedRun ? state.currentPhase : registry.entryPhaseId;
1637
+ let isContinuing = resumingSuspendedRun ? state.continuation?.isContinuing ?? true : false;
1638
+ if (resumingSuspendedRun) {
1639
+ state.status = "running";
1640
+ }
1641
+ let previousPayload = resumingSuspendedRun ? state.continuation?.previousPayload : void 0;
1642
+ let previousPhaseMsgId = resumingSuspendedRun ? state.continuation?.previousPhaseMessageId : void 0;
1643
+ let previousPhaseInputMsgId;
1644
+ let previousResults = resumingSuspendedRun ? state.continuation?.previousResults?.map((result) => ({ ...result })) ?? [] : [];
1645
+ let pendingInstruction = resumingSuspendedRun ? state.continuation?.pendingInstruction : void 0;
1599
1646
  while (currentPhaseId) {
1600
1647
  const availablePhases = [];
1601
1648
  for (const [, phase2] of registry.phases) {
@@ -1603,6 +1650,10 @@ async function runPhaseLoop(config, state, registry) {
1603
1650
  }
1604
1651
  const abortResult = LoopGuard.checkAbort(config.signal);
1605
1652
  if (abortResult.stopReason !== "none") {
1653
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1654
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1655
+ previousPhaseMsgId = void 0;
1656
+ previousPhaseInputMsgId = void 0;
1606
1657
  return completeRun(config, state, createOutcome.aborted());
1607
1658
  }
1608
1659
  state.metrics.iterations++;
@@ -1640,6 +1691,10 @@ async function runPhaseLoop(config, state, registry) {
1640
1691
  messages: messageManager.visible(),
1641
1692
  tools: phaseTools,
1642
1693
  skills: phaseSkills,
1694
+ invocation: {
1695
+ mode: "serial",
1696
+ instanceId: currentPhaseId
1697
+ },
1643
1698
  state: {
1644
1699
  current: currentPhaseId,
1645
1700
  available: Array.from(registry.phases.keys()),
@@ -1656,10 +1711,18 @@ async function runPhaseLoop(config, state, registry) {
1656
1711
  const extBefore = await config.beforePhase(currentPhaseId, phaseContext);
1657
1712
  if (extBefore.abort) {
1658
1713
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1714
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1715
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1716
+ previousPhaseMsgId = void 0;
1717
+ previousPhaseInputMsgId = void 0;
1659
1718
  return completeRun(config, state, extBefore.abort);
1660
1719
  }
1661
1720
  if (extBefore.skip) {
1662
1721
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1722
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1723
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1724
+ previousPhaseMsgId = void 0;
1725
+ previousPhaseInputMsgId = void 0;
1663
1726
  if (extBefore.skip.route === "stop") {
1664
1727
  return completeRun(config, state, {
1665
1728
  id: "skip",
@@ -1673,21 +1736,45 @@ async function runPhaseLoop(config, state, registry) {
1673
1736
  phaseContext = extBefore.input;
1674
1737
  }
1675
1738
  }
1676
- removePhaseMessage(config.context.messages, previousPhaseMsgId);
1677
- previousPhaseMsgId = void 0;
1678
- if (enteringNewPhase) {
1679
- previousPhaseMsgId = injectPhaseContent(phase, { results: previousResults, instruction: pendingInstruction }, messageManager);
1739
+ const phaseMessageIsPresent = previousPhaseMsgId !== void 0 && config.context.messages.some((message) => message.id === previousPhaseMsgId);
1740
+ if (enteringNewPhase || !phaseMessageIsPresent) {
1741
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1742
+ removePhaseMessage(phaseContext.messages, previousPhaseMsgId);
1743
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1744
+ removePhaseMessage(phaseContext.messages, previousPhaseInputMsgId);
1745
+ previousPhaseMsgId = void 0;
1746
+ previousPhaseInputMsgId = void 0;
1747
+ const latestUserInputMessage = findLatestUserInputMessage(config.context.messages);
1748
+ const lastMessageBeforePhase = config.context.messages.at(-1);
1749
+ previousPhaseMsgId = injectPhaseContent(
1750
+ phase,
1751
+ { results: previousResults, instruction: pendingInstruction },
1752
+ config.context.messages,
1753
+ phaseContext.messages
1754
+ );
1755
+ if (previousPhaseMsgId) {
1756
+ if (lastMessageBeforePhase?.role === "user") {
1757
+ moveMessageBefore(config.context.messages, previousPhaseMsgId, lastMessageBeforePhase.id);
1758
+ moveMessageBefore(phaseContext.messages, previousPhaseMsgId, lastMessageBeforePhase.id);
1759
+ } else if (latestUserInputMessage) {
1760
+ const phaseInputMessage = createMessage("user", latestUserInputMessage.content, {
1761
+ kind: "phase_input",
1762
+ phase: phase.id
1763
+ });
1764
+ config.context.messages.push(phaseInputMessage);
1765
+ phaseContext.messages.push(phaseInputMessage);
1766
+ previousPhaseInputMsgId = phaseInputMessage.id;
1767
+ }
1768
+ }
1680
1769
  previousResults = [];
1681
1770
  pendingInstruction = void 0;
1682
1771
  }
1683
1772
  const runtime = { phase, config, state, execution, messageManager, registry, context: phaseContext };
1684
1773
  let output = await executePhase(runtime);
1685
- let routeToolCalled = false;
1686
1774
  let routeDecision;
1687
1775
  if (output.toolCalls && output.toolCalls.length > 0) {
1688
1776
  routeDecision = extractRouteCall(output.toolCalls);
1689
1777
  if (routeDecision) {
1690
- routeToolCalled = true;
1691
1778
  applyFirstDecision(routeDecision, output);
1692
1779
  }
1693
1780
  }
@@ -1695,6 +1782,10 @@ async function runPhaseLoop(config, state, registry) {
1695
1782
  const extAfter = await config.afterPhase(currentPhaseId, output);
1696
1783
  if (extAfter.abort) {
1697
1784
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1785
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1786
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1787
+ previousPhaseMsgId = void 0;
1788
+ previousPhaseInputMsgId = void 0;
1698
1789
  return completeRun(config, state, extAfter.abort);
1699
1790
  }
1700
1791
  if (extAfter.retry && (phase.run || phase.factory)) {
@@ -1714,28 +1805,52 @@ async function runPhaseLoop(config, state, registry) {
1714
1805
  if (preAbort.stopReason !== "none") {
1715
1806
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1716
1807
  removePhaseMessage(config.context.messages, previousPhaseMsgId);
1808
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1717
1809
  previousPhaseMsgId = void 0;
1810
+ previousPhaseInputMsgId = void 0;
1718
1811
  return completeRun(config, state, createOutcome.aborted());
1719
1812
  }
1720
- config.emit?.({ type: "user_prompt_requested", phase: currentPhaseId, ts: createTimestamp() });
1721
- const userMessages = await config.waitForInput();
1813
+ const requestedAt = createTimestamp();
1814
+ const inputRequest = {
1815
+ phase: currentPhaseId,
1816
+ prompt: output.message,
1817
+ requestedAt
1818
+ };
1819
+ config.emit?.({
1820
+ type: "user_prompt_requested",
1821
+ phase: currentPhaseId,
1822
+ ts: requestedAt
1823
+ });
1824
+ state.status = "suspended";
1825
+ state.continuation = {
1826
+ isContinuing,
1827
+ previousPayload,
1828
+ previousResults: previousResults.map((result) => ({ ...result })),
1829
+ pendingInstruction,
1830
+ previousPhaseMessageId: previousPhaseMsgId
1831
+ };
1832
+ const userMessages = await config.waitForInput(state, inputRequest);
1833
+ state.status = "running";
1722
1834
  const abortResult2 = LoopGuard.checkAbort(config.signal);
1723
1835
  if (abortResult2.stopReason !== "none") {
1724
1836
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1725
1837
  removePhaseMessage(config.context.messages, previousPhaseMsgId);
1838
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1726
1839
  previousPhaseMsgId = void 0;
1840
+ previousPhaseInputMsgId = void 0;
1727
1841
  return completeRun(config, state, createOutcome.aborted());
1728
1842
  }
1729
1843
  for (const message of userMessages) {
1730
1844
  config.context.messages.push(message);
1731
1845
  }
1732
- removePhaseMessage(config.context.messages, previousPhaseMsgId);
1733
- previousPhaseMsgId = void 0;
1734
1846
  isContinuing = true;
1735
1847
  continue;
1736
1848
  }
1737
1849
  config.emit?.({ type: "phase_end", phase: currentPhaseId, ts: createTimestamp() });
1738
1850
  removePhaseMessage(config.context.messages, previousPhaseMsgId);
1851
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1852
+ previousPhaseMsgId = void 0;
1853
+ previousPhaseInputMsgId = void 0;
1739
1854
  return completeRun(config, state, createOutcome.default(output, config.context.messages));
1740
1855
  }
1741
1856
  if (output.route === "continue") {
@@ -1747,6 +1862,8 @@ async function runPhaseLoop(config, state, registry) {
1747
1862
  const contextSnapshot = snapshotMessages(config.context.messages);
1748
1863
  const parallelTasks = /* @__PURE__ */ new Map();
1749
1864
  const instanceIds = buildInstanceIds(routeDecision.decision.map((t) => t.phase));
1865
+ const groupId = createId("phase-group");
1866
+ const count = routeDecision.decision.length;
1750
1867
  for (let i = 0; i < routeDecision.decision.length; i++) {
1751
1868
  const target = routeDecision.decision[i];
1752
1869
  const pt = registry.phases.get(target.phase);
@@ -1754,7 +1871,20 @@ async function runPhaseLoop(config, state, registry) {
1754
1871
  const instanceId = instanceIds[i];
1755
1872
  const context = pt.isolated ? [] : contextSnapshot;
1756
1873
  const payload = target.payload !== void 0 ? normalizePayload(target.payload) : void 0;
1757
- const promise = executeParallelPhase(config, state, registry, pt, payload, context, availablePhases, currentPhaseId);
1874
+ const promise = executeParallelPhase(
1875
+ config,
1876
+ state,
1877
+ registry,
1878
+ pt,
1879
+ payload,
1880
+ context,
1881
+ availablePhases,
1882
+ instanceId,
1883
+ groupId,
1884
+ i,
1885
+ count,
1886
+ currentPhaseId
1887
+ );
1758
1888
  parallelTasks.set(instanceId, { promise, phaseId: target.phase });
1759
1889
  }
1760
1890
  const successfulResults = await waitForBackgroundTasks(parallelTasks);
@@ -1762,6 +1892,10 @@ async function runPhaseLoop(config, state, registry) {
1762
1892
  pendingInstruction = routeDecision.instruction;
1763
1893
  const entryPhaseId = phase.target ?? registry.entryPhaseId;
1764
1894
  if (entryPhaseId === "stop") {
1895
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1896
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1897
+ previousPhaseMsgId = void 0;
1898
+ previousPhaseInputMsgId = void 0;
1765
1899
  return completeRun(config, state, createTerminalOutcome(phase, output, config.context.messages));
1766
1900
  }
1767
1901
  currentPhaseId = entryPhaseId;
@@ -1777,12 +1911,18 @@ async function runPhaseLoop(config, state, registry) {
1777
1911
  nextRoute = "stop";
1778
1912
  }
1779
1913
  if (nextRoute === "stop") {
1780
- if (routeToolCalled) removePhaseMessage(config.context.messages, previousPhaseMsgId);
1914
+ removePhaseMessage(config.context.messages, previousPhaseMsgId);
1915
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1916
+ previousPhaseMsgId = void 0;
1917
+ previousPhaseInputMsgId = void 0;
1781
1918
  return completeRun(config, state, createTerminalOutcome(phase, output, config.context.messages));
1782
1919
  }
1783
1920
  const targetPhaseId = nextRoute;
1784
1921
  if (!registry.phases.has(targetPhaseId)) {
1785
1922
  removePhaseMessage(config.context.messages, previousPhaseMsgId);
1923
+ removePhaseMessage(config.context.messages, previousPhaseInputMsgId);
1924
+ previousPhaseMsgId = void 0;
1925
+ previousPhaseInputMsgId = void 0;
1786
1926
  return completeRun(config, state, createOutcome.phaseNotFound(output));
1787
1927
  }
1788
1928
  state.metrics.phaseTransitions.push({
@@ -1898,24 +2038,31 @@ async function executePhase(ctx) {
1898
2038
  return executePhaseWithModel(ctx);
1899
2039
  }
1900
2040
  async function executeToolCall(input) {
2041
+ let result;
1901
2042
  if (input.config.runtime?.tools) {
1902
- return input.config.runtime.tools({
2043
+ result = await input.config.runtime.tools({
1903
2044
  config: input.config,
1904
2045
  toolCall: input.toolCall
1905
2046
  });
2047
+ } else {
2048
+ const toolContext = {
2049
+ skills: input.config.context.skills,
2050
+ toolCallId: input.toolCall.id
2051
+ };
2052
+ result = await executeRuntimeToolCall({
2053
+ tools: input.tools,
2054
+ toolCall: input.toolCall,
2055
+ toolContext,
2056
+ beforeToolCall: input.config.beforeToolCall,
2057
+ afterToolCall: input.config.afterToolCall,
2058
+ signal: input.config.signal
2059
+ });
1906
2060
  }
1907
- const toolContext = {
1908
- skills: input.config.context.skills,
1909
- toolCallId: input.toolCall.id
2061
+ return {
2062
+ ...result,
2063
+ toolCallId: input.toolCall.id,
2064
+ toolName: input.toolCall.name
1910
2065
  };
1911
- return executeRuntimeToolCall({
1912
- tools: input.tools,
1913
- toolCall: input.toolCall,
1914
- toolContext,
1915
- beforeToolCall: input.config.beforeToolCall,
1916
- afterToolCall: input.config.afterToolCall,
1917
- signal: input.config.signal
1918
- });
1919
2066
  }
1920
2067
  function createPhaseExecution(config, state, allTools, phase, messageManager, toolExecutionManager, registry) {
1921
2068
  return {
@@ -1999,17 +2146,25 @@ function createPhaseExecution(config, state, allTools, phase, messageManager, to
1999
2146
  }
2000
2147
  };
2001
2148
  }
2002
- async function executeParallelPhase(config, state, registry, phase, payload, context, availablePhases, currentPhaseId) {
2149
+ async function executeParallelPhase(config, state, registry, phase, payload, context, availablePhases, instanceId, groupId, index, count, sourcePhaseId) {
2003
2150
  const messages = [...context];
2004
2151
  const allTools = buildToolsWithRouting(config, availablePhases);
2005
2152
  const phaseTools = phase.tools ? allTools.filter((t) => t.name === PhaseRouteTool || phase.tools.includes(t.name)) : allTools;
2006
2153
  const phaseSkills = phase.skills ? config.context.skills.filter((s) => phase.skills.includes(s.name)) : config.context.skills;
2007
- const systemPrompt = phase.isolated ? readPhaseContent(phase) : config.context.systemPrompt;
2154
+ const systemPrompt = config.context.systemPrompt;
2008
2155
  const phaseContext = {
2009
2156
  systemPrompt,
2010
2157
  messages,
2011
2158
  tools: phaseTools,
2012
2159
  skills: phaseSkills,
2160
+ invocation: {
2161
+ mode: "parallel",
2162
+ instanceId,
2163
+ groupId,
2164
+ index,
2165
+ count,
2166
+ sourcePhaseId
2167
+ },
2013
2168
  state: {
2014
2169
  current: phase.id,
2015
2170
  available: Array.from(registry.phases.keys()),
@@ -2018,10 +2173,10 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
2018
2173
  }
2019
2174
  };
2020
2175
  const messageManager = createMessageManager({ messages }, config.emit, config.onMessage);
2021
- const phaseMsgId = phase.isolated ? void 0 : injectPhaseContent(
2176
+ const phaseMsgId = injectPhaseContent(
2022
2177
  phase,
2023
- { results: payload !== void 0 ? [{ name: currentPhaseId, output: payload }] : [] },
2024
- messageManager
2178
+ { results: payload !== void 0 ? [{ name: sourcePhaseId, output: payload }] : [] },
2179
+ messages
2025
2180
  );
2026
2181
  const toolExecutionManager = createToolExecutionManager(config.emit);
2027
2182
  const execution = createPhaseExecution(config, state, phaseTools, phase, messageManager, toolExecutionManager, registry);
@@ -2030,7 +2185,7 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
2030
2185
  if (phaseMsgId) removePhaseMessage(messages, phaseMsgId);
2031
2186
  const decision = output.toolCalls ? extractRouteCall(output.toolCalls) : void 0;
2032
2187
  const resultPayload = decision?.decision[0]?.payload !== void 0 ? normalizePayload(decision.decision[0].payload) : output.payload;
2033
- return { instanceId: "", phaseId: phase.id, payload: resultPayload, content: output.message };
2188
+ return { instanceId, phaseId: phase.id, payload: resultPayload, content: output.message };
2034
2189
  }
2035
2190
  async function waitForBackgroundTasks(backgroundTasks) {
2036
2191
  const entries = Array.from(backgroundTasks.entries());
@@ -3224,19 +3379,29 @@ var AgentExecution = class {
3224
3379
  runWithMessage(message, options, internalHooks = {}) {
3225
3380
  const activeRun = this.activeRun;
3226
3381
  if (activeRun?.resume) {
3382
+ if (internalHooks.onSuspend) activeRun.onSuspend = internalHooks.onSuspend;
3227
3383
  activeRun.resume([message]);
3228
3384
  return activeRun.promise;
3229
3385
  }
3230
3386
  if (activeRun) {
3231
3387
  return Promise.reject(new Error("Agent is already running."));
3232
3388
  }
3233
- this.appendMessage(message);
3389
+ if (!this.options.context.messages.some((candidate) => candidate.id === message.id)) {
3390
+ this.appendMessage(message);
3391
+ }
3234
3392
  return this.run(options, internalHooks);
3235
3393
  }
3236
3394
  /** Internal Runtime seam: executes one leased Agent Input. */
3237
- async executeAgentInput(input, runId, control) {
3395
+ async executeAgentInput(input, runId, control, executionState) {
3238
3396
  this.runtimeRunId = runId;
3239
- const internal = { onSuspend: control.suspend };
3397
+ this.options.sessionState = executionState ? restoreSessionState(executionState) : void 0;
3398
+ const internal = {
3399
+ onSuspend: (reason, state, inputRequest) => control.suspend(
3400
+ reason,
3401
+ state ? snapshotExecutionState(state) : void 0,
3402
+ inputRequest
3403
+ )
3404
+ };
3240
3405
  try {
3241
3406
  return (await this.runWithMessage(input, void 0, internal)).outcome;
3242
3407
  } finally {
@@ -3473,18 +3638,20 @@ var AgentExecution = class {
3473
3638
  }
3474
3639
  const abortController = new AbortController();
3475
3640
  let suspensionRequested = false;
3476
- const waitForInput = () => {
3477
- if (!suspensionRequested) {
3478
- suspensionRequested = true;
3479
- void hooks.onSuspend?.("Agent requested input.");
3480
- }
3481
- return new Promise((resolve7) => {
3641
+ const waitForInput = (state, inputRequest) => {
3642
+ const waiting = new Promise((resolve7) => {
3482
3643
  const activeRun = this.activeRun;
3483
3644
  activeRun.resume = (messages) => {
3484
3645
  activeRun.resume = void 0;
3646
+ suspensionRequested = false;
3485
3647
  resolve7(messages);
3486
3648
  };
3487
3649
  });
3650
+ if (!suspensionRequested) {
3651
+ suspensionRequested = true;
3652
+ void this.activeRun?.onSuspend?.("Agent requested input.", state, inputRequest);
3653
+ }
3654
+ return waiting;
3488
3655
  };
3489
3656
  const promise = Promise.resolve().then(() => executor({ signal: abortController.signal, waitForInput })).catch((error) => {
3490
3657
  this.handleRunFailure(error, abortController.signal.aborted);
@@ -3492,7 +3659,7 @@ var AgentExecution = class {
3492
3659
  }).finally(() => {
3493
3660
  this.finishRun();
3494
3661
  });
3495
- this.activeRun = { promise, abortController };
3662
+ this.activeRun = { promise, abortController, onSuspend: hooks.onSuspend };
3496
3663
  this.state.running = true;
3497
3664
  return promise;
3498
3665
  }
@@ -3525,7 +3692,8 @@ var AgentExecution = class {
3525
3692
  const extensions = resolved.extensions ?? [];
3526
3693
  await this.loadExtensions(extensions, resolved.cwd);
3527
3694
  const runContext = prepareAgentContext(resolved.context, this.extensionRunner);
3528
- const entryPhaseId = this.state.initialized ? DEFAULT_PHASE_ID : runContext.phases?.entryPhaseId ?? DEFAULT_PHASE_ID;
3695
+ const resumingSuspendedRun = resolved.sessionState?.status === "suspended";
3696
+ const entryPhaseId = resumingSuspendedRun ? resolved.sessionState?.currentPhase || runContext.phases?.entryPhaseId || DEFAULT_PHASE_ID : this.state.initialized ? DEFAULT_PHASE_ID : runContext.phases?.entryPhaseId ?? DEFAULT_PHASE_ID;
3529
3697
  const loopContext = {
3530
3698
  ...runContext,
3531
3699
  phases: {
@@ -3570,6 +3738,7 @@ var AgentExecution = class {
3570
3738
  model: resolved.model,
3571
3739
  stream: resolved.stream,
3572
3740
  maxAttempts: resolved.maxAttempts,
3741
+ sessionState: resolved.sessionState,
3573
3742
  signal,
3574
3743
  beforeToolCall,
3575
3744
  afterToolCall,
@@ -3594,7 +3763,8 @@ var AgentExecution = class {
3594
3763
  this.options = {
3595
3764
  ...resolved,
3596
3765
  sessionId: result.sessionId,
3597
- context: nextContext
3766
+ context: nextContext,
3767
+ sessionState: void 0
3598
3768
  };
3599
3769
  return result;
3600
3770
  }, internalHooks);
@@ -3602,6 +3772,9 @@ var AgentExecution = class {
3602
3772
  abort(reason = "Aborted by caller.") {
3603
3773
  this.abortLocal(reason);
3604
3774
  }
3775
+ isSuspended() {
3776
+ return Boolean(this.activeRun?.resume);
3777
+ }
3605
3778
  abortLocal(reason) {
3606
3779
  const activeRun = this.activeRun;
3607
3780
  activeRun?.resume?.([]);
@@ -3676,6 +3849,50 @@ ${additionalInstructions}` : content;
3676
3849
  };
3677
3850
  }
3678
3851
  };
3852
+ function restoreSessionState(state) {
3853
+ const persisted = parsePersistedExecutionState(state);
3854
+ return {
3855
+ ...persisted,
3856
+ status: "suspended",
3857
+ metrics: {
3858
+ ...persisted.metrics,
3859
+ phaseTransitions: persisted.metrics.phaseTransitions.map((transition) => ({ ...transition }))
3860
+ },
3861
+ ...persisted.continuation ? {
3862
+ continuation: {
3863
+ ...persisted.continuation,
3864
+ previousResults: persisted.continuation.previousResults.map((result) => ({ ...result }))
3865
+ }
3866
+ } : {}
3867
+ };
3868
+ }
3869
+ function snapshotExecutionState(state) {
3870
+ return {
3871
+ version: 1,
3872
+ currentPhase: state.currentPhase,
3873
+ attempt: state.attempt,
3874
+ metrics: {
3875
+ ...state.metrics,
3876
+ phaseTransitions: state.metrics.phaseTransitions.map((transition) => ({ ...transition }))
3877
+ },
3878
+ ...state.continuation ? {
3879
+ continuation: {
3880
+ ...state.continuation,
3881
+ previousResults: state.continuation.previousResults.map((result) => ({ ...result }))
3882
+ }
3883
+ } : {}
3884
+ };
3885
+ }
3886
+ function parsePersistedExecutionState(state) {
3887
+ if (!state || state.version !== 1 || typeof state.currentPhase !== "string" || typeof state.attempt !== "number") {
3888
+ throw new Error("Invalid Agent Run execution checkpoint.");
3889
+ }
3890
+ const metrics = state.metrics;
3891
+ if (!metrics || !Array.isArray(metrics.phaseTransitions)) {
3892
+ throw new Error("Invalid Agent Run execution checkpoint metrics.");
3893
+ }
3894
+ return state;
3895
+ }
3679
3896
  function clonePhaseRegistry(registry) {
3680
3897
  return {
3681
3898
  phases: new Map(registry.phases),
@@ -3755,6 +3972,8 @@ async function attachAgent(input) {
3755
3972
  phases: input.options.context.phases
3756
3973
  };
3757
3974
  const persistInput = async (message) => {
3975
+ const context2 = await input.manager.buildAgentContext();
3976
+ if (context2.messages.some((candidate) => candidate.id === message.id)) return;
3758
3977
  await input.manager.appendMessage(message);
3759
3978
  };
3760
3979
  let execution;
@@ -3813,7 +4032,9 @@ async function attachAgent(input) {
3813
4032
  agent,
3814
4033
  binding: {
3815
4034
  abort: (reason) => execution.abortFromRuntime(reason),
3816
- execute: (message, runId, control) => execution.executeAgentInput(message, runId, control)
4035
+ isSuspended: () => execution.isSuspended(),
4036
+ persistInput,
4037
+ execute: (message, runId, control, executionState) => execution.executeAgentInput(message, runId, control, executionState)
3817
4038
  }
3818
4039
  };
3819
4040
  }
@@ -4240,8 +4461,8 @@ var LocalJsonlSessionManager = class _LocalJsonlSessionManager {
4240
4461
  }
4241
4462
  };
4242
4463
 
4243
- // src/harness/session/provider.ts
4244
- var InMemorySessionProvider = class {
4464
+ // src/harness/session/store.ts
4465
+ var InMemorySessionStore = class {
4245
4466
  sessions = /* @__PURE__ */ new Map();
4246
4467
  async create(input) {
4247
4468
  const session = InMemorySessionManager.create(input);
@@ -4252,7 +4473,7 @@ var InMemorySessionProvider = class {
4252
4473
  return this.sessions.get(sessionId);
4253
4474
  }
4254
4475
  };
4255
- var LocalJsonlSessionProvider = class {
4476
+ var JsonlSessionStore = class {
4256
4477
  constructor(sessionsDir) {
4257
4478
  this.sessionsDir = sessionsDir;
4258
4479
  }
@@ -4268,6 +4489,9 @@ var LocalJsonlSessionProvider = class {
4268
4489
  }
4269
4490
  };
4270
4491
 
4492
+ // src/runtime/agent-runtime.ts
4493
+ import { createModelStream } from "@rowan-agent/models";
4494
+
4271
4495
  // src/runtime/tool-runtime.ts
4272
4496
  function failed(toolCall, message) {
4273
4497
  return {
@@ -4469,6 +4693,9 @@ var AgentRun = class _AgentRun {
4469
4693
  get state() {
4470
4694
  return this.current.state;
4471
4695
  }
4696
+ get inputRequest() {
4697
+ return this.current.inputRequest ? structuredClone(this.current.inputRequest) : void 0;
4698
+ }
4472
4699
  async getStatus() {
4473
4700
  const run = await this.host.getRun(this.id);
4474
4701
  if (run) this.notify(run);
@@ -4533,8 +4760,8 @@ var AgentRuntime = class _AgentRuntime {
4533
4760
  leaseDurationMs;
4534
4761
  leaseRenewalIntervalMs;
4535
4762
  toolRuntime;
4536
- factories;
4537
4763
  bindings = /* @__PURE__ */ new Map();
4764
+ agents = /* @__PURE__ */ new Map();
4538
4765
  runHandles = /* @__PURE__ */ new Map();
4539
4766
  runWaiters = /* @__PURE__ */ new Map();
4540
4767
  pendingRuns = [];
@@ -4546,6 +4773,7 @@ var AgentRuntime = class _AgentRuntime {
4546
4773
  runningRuns = 0;
4547
4774
  pumping = false;
4548
4775
  nextWorkerId = 0;
4776
+ leaseRecoveryTimer;
4549
4777
  stopped = false;
4550
4778
  constructor(options) {
4551
4779
  this.stateStore = options.stateStore;
@@ -4555,10 +4783,6 @@ var AgentRuntime = class _AgentRuntime {
4555
4783
  this.leaseDurationMs = options.leaseDurationMs ?? 6e4;
4556
4784
  this.leaseRenewalIntervalMs = options.leaseRenewalIntervalMs ?? Math.max(1, Math.floor(this.leaseDurationMs / 2));
4557
4785
  this.toolRuntime = new ToolRuntime(options.stateStore, options.toolPolicy, () => this.publishEvents());
4558
- this.factories = options.factories instanceof Map ? new Map([...options.factories.entries()].map(([id, factory]) => [String(id), factory])) : new Map(Object.entries(options.factories ?? {}));
4559
- for (const id of this.factories.keys()) {
4560
- if (id.trim().length === 0) throw new Error("Factory ID must not be empty.");
4561
- }
4562
4786
  }
4563
4787
  static async start(options) {
4564
4788
  if (activeRuntime) {
@@ -4585,6 +4809,7 @@ var AgentRuntime = class _AgentRuntime {
4585
4809
  activeRuntime = runtime;
4586
4810
  try {
4587
4811
  await runtime.recover();
4812
+ runtime.startLeaseRecovery();
4588
4813
  return runtime;
4589
4814
  } catch (error) {
4590
4815
  await runtime.stop().catch(() => void 0);
@@ -4593,20 +4818,16 @@ var AgentRuntime = class _AgentRuntime {
4593
4818
  }
4594
4819
  async createAgent(options) {
4595
4820
  this.assertRunning();
4596
- if (options.factoryId !== void 0 && options.factoryId.trim().length === 0) {
4597
- throw new Error("Factory ID must not be empty.");
4598
- }
4821
+ assertAgentOptions(options);
4599
4822
  const provider = this.sessionProvider;
4600
4823
  if (!provider) throw new Error("Agent Runtime requires a SessionManager provider to create an Agent.");
4601
4824
  const manager = await provider.create({
4602
4825
  systemPrompt: options.context.systemPrompt,
4603
- input: options.input ?? "",
4826
+ input: "",
4604
4827
  skills: options.context.skills
4605
4828
  });
4606
- if (options.input) await manager.appendMessage(createMessage("user", options.input));
4607
4829
  const record = await this.stateStore.createAgent({
4608
- sessionId: manager.getSessionId(),
4609
- ...options.factoryId ? { factoryId: options.factoryId } : {}
4830
+ sessionId: manager.getSessionId()
4610
4831
  });
4611
4832
  this.pausedAgents.delete(record.id);
4612
4833
  const agent = await this.attachAgent(record, manager, options);
@@ -4615,6 +4836,7 @@ var AgentRuntime = class _AgentRuntime {
4615
4836
  }
4616
4837
  async reconstructAgent(agentId, options) {
4617
4838
  this.assertRunning();
4839
+ assertAgentOptions(options);
4618
4840
  const record = await this.stateStore.getAgent(agentId);
4619
4841
  if (!record) throw new Error(`Agent not found: ${agentId}.`);
4620
4842
  if (record.state === "paused") this.pausedAgents.add(record.id);
@@ -4630,10 +4852,23 @@ var AgentRuntime = class _AgentRuntime {
4630
4852
  async stop() {
4631
4853
  if (this.stopped) return;
4632
4854
  this.stopped = true;
4633
- for (const binding of this.bindings.values()) {
4634
- binding.abort("Agent Runtime stopped.");
4855
+ if (this.leaseRecoveryTimer) {
4856
+ clearInterval(this.leaseRecoveryTimer);
4857
+ this.leaseRecoveryTimer = void 0;
4858
+ }
4859
+ let suspendedAgents;
4860
+ try {
4861
+ suspendedAgents = new Set(
4862
+ (await this.stateStore.listRuns({ states: ["suspended"] })).map((run) => run.agentId)
4863
+ );
4864
+ } catch {
4865
+ suspendedAgents = /* @__PURE__ */ new Set();
4866
+ }
4867
+ for (const [agentId, binding] of this.bindings) {
4868
+ if (!suspendedAgents.has(agentId) && !binding.isSuspended()) binding.abort("Agent Runtime stopped.");
4635
4869
  }
4636
4870
  this.bindings.clear();
4871
+ this.agents.clear();
4637
4872
  this.pendingRuns.length = 0;
4638
4873
  this.scheduledRunIds.clear();
4639
4874
  this.pausedAgents.clear();
@@ -4653,6 +4888,7 @@ var AgentRuntime = class _AgentRuntime {
4653
4888
  throw new Error(`Agent ${agentId} is already bound to a live Agent.`);
4654
4889
  }
4655
4890
  this.bindings.set(agentId, agent);
4891
+ void this.pump();
4656
4892
  if (!this.pausedAgents.has(agentId)) void this.scheduleQueuedRuns(agentId);
4657
4893
  }
4658
4894
  registerRunHandle(runId, handle) {
@@ -4702,6 +4938,24 @@ var AgentRuntime = class _AgentRuntime {
4702
4938
  void this.pump();
4703
4939
  this.publishEvents();
4704
4940
  }
4941
+ async getRun(runId) {
4942
+ return this.stateStore.getRun(runId);
4943
+ }
4944
+ async listActiveRuns() {
4945
+ return this.stateStore.listActiveRuns();
4946
+ }
4947
+ async listRuns(input) {
4948
+ return this.stateStore.listRuns(input);
4949
+ }
4950
+ getAgent(agentId) {
4951
+ return this.agents.get(agentId);
4952
+ }
4953
+ async getMessage(messageId) {
4954
+ return this.stateStore.getMessage(messageId);
4955
+ }
4956
+ async getToolCall(toolCallId) {
4957
+ return this.stateStore.getToolCall(toolCallId);
4958
+ }
4705
4959
  async abortRun(runId, reason = "Agent Run aborted by caller.") {
4706
4960
  const run = await this.stateStore.getRun(runId);
4707
4961
  if (!run || ["completed", "failed", "cancelled"].includes(run.state)) return;
@@ -4722,6 +4976,11 @@ var AgentRuntime = class _AgentRuntime {
4722
4976
  this.publishEvents();
4723
4977
  }
4724
4978
  consumeEvents(consumerId, listener) {
4979
+ const subscription = this.registerEventConsumer(consumerId, listener);
4980
+ void subscription.caughtUp.catch(() => void 0);
4981
+ return subscription;
4982
+ }
4983
+ registerEventConsumer(consumerId, listener) {
4725
4984
  this.assertRunning();
4726
4985
  if (consumerId.trim().length === 0) {
4727
4986
  throw new Error("Runtime Event Consumer ID must not be empty.");
@@ -4736,58 +4995,78 @@ var AgentRuntime = class _AgentRuntime {
4736
4995
  redeliver: false
4737
4996
  };
4738
4997
  this.eventSubscriptions.set(consumerId, subscription);
4739
- void this.deliverEvents(subscription).catch(() => void 0);
4740
- return () => {
4998
+ let caughtUpSettled = false;
4999
+ let resolveCaughtUp;
5000
+ let rejectCaughtUp;
5001
+ const caughtUp = new Promise((resolve7, reject) => {
5002
+ resolveCaughtUp = resolve7;
5003
+ rejectCaughtUp = reject;
5004
+ });
5005
+ const stop = () => {
4741
5006
  if (this.eventSubscriptions.get(consumerId) === subscription) {
4742
5007
  this.eventSubscriptions.delete(consumerId);
4743
5008
  }
5009
+ if (!caughtUpSettled) {
5010
+ caughtUpSettled = true;
5011
+ const error = new Error("Runtime Event Consumer stopped before catch-up completed.");
5012
+ error.name = "AbortError";
5013
+ rejectCaughtUp(error);
5014
+ }
4744
5015
  };
5016
+ void this.deliverEvents(subscription).then(
5017
+ () => {
5018
+ if (!caughtUpSettled) {
5019
+ caughtUpSettled = true;
5020
+ resolveCaughtUp();
5021
+ }
5022
+ },
5023
+ (error) => {
5024
+ if (!caughtUpSettled) {
5025
+ caughtUpSettled = true;
5026
+ rejectCaughtUp(error);
5027
+ }
5028
+ }
5029
+ );
5030
+ return { caughtUp, stop };
4745
5031
  }
4746
5032
  async listEvents(cursor) {
4747
5033
  return this.stateStore.listEvents(cursor);
4748
5034
  }
4749
5035
  async recover() {
4750
- await this.stateStore.recoverLeases();
5036
+ await this.recoverExpiredLeases();
4751
5037
  const agents = await this.stateStore.listAgents();
4752
5038
  for (const record of agents) {
4753
5039
  if (record.state === "paused") this.pausedAgents.add(record.id);
4754
5040
  }
4755
- for (const record of agents) {
4756
- if (record.state !== "active" || !record.factoryId) continue;
4757
- const factory = this.factories.get(String(record.factoryId));
4758
- if (!factory) {
4759
- await this.stateStore.recordEvent({ kind: "factory_missing", related: { agentId: record.id }, payload: { factoryId: record.factoryId } });
4760
- continue;
4761
- }
4762
- try {
4763
- const options = await factory({ agentId: record.id, sessionId: record.sessionId, factoryId: record.factoryId });
4764
- if (!options) {
4765
- await this.stateStore.recordEvent({
4766
- kind: "agent_recovery_failed",
4767
- related: { agentId: record.id },
4768
- payload: { factoryId: record.factoryId, error: "Factory returned no reconstruction options." }
4769
- });
4770
- continue;
4771
- }
4772
- await this.reconstructAgent(record.id, options);
4773
- await this.stateStore.recordEvent({ kind: "agent_recovered", related: { agentId: record.id }, payload: { factoryId: record.factoryId } });
4774
- } catch (error) {
4775
- await this.stateStore.recordEvent({ kind: "agent_recovery_failed", related: { agentId: record.id }, payload: { factoryId: record.factoryId, error: error instanceof Error ? error.message : String(error) } });
4776
- }
4777
- }
4778
- for (const record of await this.stateStore.listAgents()) {
4779
- if (this.bindings.has(record.id)) await this.scheduleQueuedRuns(record.id);
4780
- }
4781
5041
  this.publishEvents();
4782
5042
  }
5043
+ startLeaseRecovery() {
5044
+ this.leaseRecoveryTimer = setInterval(() => {
5045
+ void this.recoverExpiredLeases().catch(() => void 0);
5046
+ }, this.leaseRenewalIntervalMs);
5047
+ }
5048
+ async recoverExpiredLeases() {
5049
+ const recovered = await this.stateStore.recoverExpiredLeases();
5050
+ for (const run of recovered) {
5051
+ this.notifyRun(run);
5052
+ if (this.bindings.has(run.agentId)) this.scheduleRun(run.agentId, run.id);
5053
+ }
5054
+ if (recovered.length > 0) this.publishEvents();
5055
+ }
4783
5056
  async scheduleQueuedRuns(agentId) {
4784
5057
  if (!this.bindings.has(agentId)) return;
4785
5058
  const runs = await this.stateStore.listRuns({ agentId, states: ["queued"] });
4786
5059
  for (const run of runs) this.scheduleRun(agentId, run.id);
4787
5060
  }
4788
5061
  async attachAgent(record, manager, options) {
5062
+ const model = { provider: options.model.provider, id: options.model.id };
5063
+ const resolvedOptions = {
5064
+ ...options,
5065
+ model,
5066
+ stream: options.stream ?? createModelStream(options.model)
5067
+ };
4789
5068
  const attached = await attachAgent({
4790
- options,
5069
+ options: resolvedOptions,
4791
5070
  agentId: record.id,
4792
5071
  sessionId: record.sessionId,
4793
5072
  manager,
@@ -4795,6 +5074,7 @@ var AgentRuntime = class _AgentRuntime {
4795
5074
  executeTool: (input) => this.toolRuntime.execute(input)
4796
5075
  });
4797
5076
  this.bindAgent(record.id, attached.binding);
5077
+ this.agents.set(record.id, attached.agent);
4798
5078
  return attached.agent;
4799
5079
  }
4800
5080
  async submitAgentInput(agentId, input, persist) {
@@ -4802,6 +5082,7 @@ var AgentRuntime = class _AgentRuntime {
4802
5082
  if (!this.bindings.has(agentId)) throw new Error(`Agent ${agentId} has no live Agent Binding.`);
4803
5083
  const enqueued = await this.stateStore.enqueueAgentInput({ agentId, input });
4804
5084
  await persist();
5085
+ if (enqueued.resumed) this.notifyRun(enqueued.run);
4805
5086
  const run = createAgentRun({
4806
5087
  register: (handle) => this.registerRunHandle(enqueued.run.id, handle),
4807
5088
  getRun: (runId) => this.stateStore.getRun(runId),
@@ -4849,10 +5130,10 @@ var AgentRuntime = class _AgentRuntime {
4849
5130
  suspendedResolve = resolve7;
4850
5131
  });
4851
5132
  const control = {
4852
- suspend: async (reason) => {
5133
+ suspend: async (reason, executionState, inputRequest) => {
4853
5134
  if (suspended) return;
4854
5135
  suspended = true;
4855
- const current = await this.stateStore.suspendRun({ runId: job.runId, reason });
5136
+ const current = await this.stateStore.suspendRun({ runId: job.runId, reason, executionState, inputRequest });
4856
5137
  this.notifyRun(current);
4857
5138
  this.publishEvents();
4858
5139
  suspendedResolve?.();
@@ -4871,6 +5152,11 @@ var AgentRuntime = class _AgentRuntime {
4871
5152
  leaseDurationMs: this.leaseDurationMs
4872
5153
  });
4873
5154
  this.notifyRun(leased.run);
5155
+ try {
5156
+ await binding.persistInput(leased.message.input);
5157
+ } catch (error) {
5158
+ throw new InfrastructureFailureError("Agent Input persistence failed.", { cause: error });
5159
+ }
4874
5160
  renewalTimer = setInterval(() => {
4875
5161
  void this.stateStore.renewLease({
4876
5162
  runId: job.runId,
@@ -4884,7 +5170,7 @@ var AgentRuntime = class _AgentRuntime {
4884
5170
  failRenewal(failure);
4885
5171
  });
4886
5172
  }, this.leaseRenewalIntervalMs);
4887
- const execution = binding.execute(leased.message.input, job.runId, control);
5173
+ const execution = binding.execute(leased.message.input, job.runId, control, leased.run.executionState);
4888
5174
  const outcome = await Promise.race([
4889
5175
  execution.then((value) => ({ kind: "terminal", value })).catch((error) => ({ kind: "error", error })),
4890
5176
  suspendedSignal.then(() => ({ kind: "suspended" })),
@@ -4976,8 +5262,21 @@ var AgentRuntime = class _AgentRuntime {
4976
5262
  );
4977
5263
  for (const event of events) {
4978
5264
  if (this.eventSubscriptions.get(subscription.consumerId) !== subscription) return;
4979
- await subscription.listener(structuredClone(event));
4980
- await this.stateStore.acknowledgeEvent(subscription.consumerId, event.id);
5265
+ const disposition = await subscription.listener(structuredClone(event));
5266
+ if (disposition?.type === "enqueue") {
5267
+ const delivered = await this.stateStore.acknowledgeEventAndEnqueueAgentInput({
5268
+ consumerId: subscription.consumerId,
5269
+ eventId: event.id,
5270
+ agentId: disposition.agentId,
5271
+ input: disposition.input
5272
+ });
5273
+ if (delivered.enqueued) {
5274
+ this.scheduleRun(delivered.enqueued.run.agentId, delivered.enqueued.run.id);
5275
+ this.publishEvents();
5276
+ }
5277
+ } else {
5278
+ await this.stateStore.acknowledgeEvent(subscription.consumerId, event.id);
5279
+ }
4981
5280
  }
4982
5281
  } while (subscription.redeliver);
4983
5282
  } finally {
@@ -4988,11 +5287,25 @@ var AgentRuntime = class _AgentRuntime {
4988
5287
  if (this.stopped || activeRuntime !== this) throw new Error("Agent Runtime is stopped.");
4989
5288
  }
4990
5289
  };
5290
+ function isModelConfig(value) {
5291
+ if (typeof value !== "object" || value === null) return false;
5292
+ return "protocol" in value && "baseUrl" in value && "apiKey" in value;
5293
+ }
5294
+ function assertAgentOptions(options) {
5295
+ if (options.stream && isModelConfig(options.model)) {
5296
+ throw new Error("AgentOptions accepts either a complete model config or a custom stream, not both.");
5297
+ }
5298
+ }
4991
5299
  function isRetryableInfrastructureError(error) {
4992
5300
  if (error instanceof InfrastructureFailureError) return true;
4993
5301
  return typeof error === "object" && error !== null && "retryable" in error && error.retryable === true;
4994
5302
  }
4995
5303
 
5304
+ // src/runtime/domain.ts
5305
+ function runEventPayload(metadata, payload = {}) {
5306
+ return metadata ? { ...payload, metadata: structuredClone(metadata) } : payload;
5307
+ }
5308
+
4996
5309
  // src/runtime/memory-store.ts
4997
5310
  function clone2(value) {
4998
5311
  return structuredClone(value);
@@ -5021,7 +5334,6 @@ var InMemoryRuntimeStateStore = class {
5021
5334
  const agent = {
5022
5335
  id: createId("agt"),
5023
5336
  sessionId: input.sessionId,
5024
- ...input.factoryId ? { factoryId: input.factoryId } : {},
5025
5337
  state: "active",
5026
5338
  createdAt: timestamp,
5027
5339
  updatedAt: timestamp
@@ -5047,6 +5359,9 @@ var InMemoryRuntimeStateStore = class {
5047
5359
  return clone2(agent);
5048
5360
  }
5049
5361
  async enqueueAgentInput(input) {
5362
+ return this.enqueueAgentInputState(input);
5363
+ }
5364
+ enqueueAgentInputState(input) {
5050
5365
  this.requireAgent(input.agentId);
5051
5366
  const suspended = [...this.runs.values()].filter((run2) => run2.agentId === input.agentId && run2.state === "suspended").sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
5052
5367
  const { timestamp } = now();
@@ -5067,6 +5382,7 @@ var InMemoryRuntimeStateStore = class {
5067
5382
  suspended.state = "queued";
5068
5383
  suspended.messageId = messageId;
5069
5384
  delete suspended.suspensionReason;
5385
+ delete suspended.inputRequest;
5070
5386
  suspended.updatedAt = timestamp;
5071
5387
  message.runId = suspended.id;
5072
5388
  }
@@ -5076,13 +5392,14 @@ var InMemoryRuntimeStateStore = class {
5076
5392
  messageId,
5077
5393
  state: "queued",
5078
5394
  attempt: 0,
5395
+ ...suspended?.metadata ? { metadata: clone2(suspended.metadata) } : input.input.metadata ? { metadata: clone2(input.input.metadata) } : {},
5079
5396
  createdAt: timestamp,
5080
5397
  updatedAt: timestamp
5081
5398
  };
5082
5399
  this.messages.set(message.id, message);
5083
5400
  this.runs.set(run.id, suspended ?? run);
5084
5401
  this.recordEvent("message_enqueued", { agentId: input.agentId, messageId });
5085
- this.recordEvent("run_enqueued", { agentId: input.agentId, messageId, runId });
5402
+ this.recordEvent("run_enqueued", { agentId: input.agentId, messageId, runId }, runEventPayload(suspended?.metadata ?? input.input.metadata));
5086
5403
  return { message: clone2(message), run: clone2(suspended ?? run), resumed: Boolean(suspended) };
5087
5404
  }
5088
5405
  async getMessage(messageId) {
@@ -5094,7 +5411,10 @@ var InMemoryRuntimeStateStore = class {
5094
5411
  return run ? clone2(run) : void 0;
5095
5412
  }
5096
5413
  async listRuns(input = {}) {
5097
- return clone2([...this.runs.values()].filter((run) => input.agentId === void 0 || run.agentId === input.agentId).filter((run) => !input.states || input.states.includes(run.state)).sort((a, b) => a.createdAt.localeCompare(b.createdAt)));
5414
+ return clone2([...this.runs.values()].filter((run) => input.agentId === void 0 || run.agentId === input.agentId).filter((run) => !input.states || input.states.includes(run.state)).sort((a, b) => a.createdAt.localeCompare(b.createdAt) || String(a.id).localeCompare(String(b.id))));
5415
+ }
5416
+ async listActiveRuns() {
5417
+ return this.listRuns({ states: ["queued", "running", "suspended"] });
5098
5418
  }
5099
5419
  async leaseRun(input) {
5100
5420
  const run = this.requireRun(input.runId);
@@ -5159,15 +5479,17 @@ var InMemoryRuntimeStateStore = class {
5159
5479
  const { timestamp } = now();
5160
5480
  run.state = "suspended";
5161
5481
  run.suspensionReason = input.reason;
5482
+ if (input.inputRequest) run.inputRequest = clone2(input.inputRequest);
5483
+ if (input.executionState) run.executionState = clone2(input.executionState);
5162
5484
  delete run.leaseId;
5163
5485
  run.updatedAt = timestamp;
5164
5486
  requireTransition("Runtime Message", message.id, message.state, "acknowledge", ["leased"]);
5165
5487
  message.state = "acknowledged";
5166
5488
  delete message.lease;
5167
5489
  message.updatedAt = timestamp;
5168
- this.recordEvent("run_suspended", { agentId: run.agentId, messageId: message.id, runId: run.id }, {
5490
+ this.recordEvent("run_suspended", { agentId: run.agentId, messageId: message.id, runId: run.id }, runEventPayload(run.metadata, {
5169
5491
  reason: input.reason
5170
- });
5492
+ }));
5171
5493
  return clone2(run);
5172
5494
  }
5173
5495
  async completeRun(input) {
@@ -5179,15 +5501,17 @@ var InMemoryRuntimeStateStore = class {
5179
5501
  const state = input.state ?? "completed";
5180
5502
  run.state = state;
5181
5503
  run.outcome = clone2(input.outcome);
5504
+ delete run.inputRequest;
5505
+ delete run.executionState;
5182
5506
  delete run.leaseId;
5183
5507
  run.updatedAt = timestamp;
5184
5508
  message.state = "acknowledged";
5185
5509
  delete message.lease;
5186
5510
  message.updatedAt = timestamp;
5187
- this.recordEvent("run_completed", { agentId: run.agentId, messageId: run.messageId, runId: run.id }, {
5511
+ this.recordEvent("run_completed", { agentId: run.agentId, messageId: run.messageId, runId: run.id }, runEventPayload(run.metadata, {
5188
5512
  state,
5189
5513
  outcome: input.outcome
5190
- });
5514
+ }));
5191
5515
  this.recordEvent("message_acknowledged", { agentId: message.agentId, messageId: message.id });
5192
5516
  return clone2(run);
5193
5517
  }
@@ -5218,16 +5542,18 @@ var InMemoryRuntimeStateStore = class {
5218
5542
  const { timestamp } = now();
5219
5543
  run.state = "failed";
5220
5544
  run.outcome = clone2(input.outcome);
5545
+ delete run.inputRequest;
5546
+ delete run.executionState;
5221
5547
  delete run.leaseId;
5222
5548
  run.updatedAt = timestamp;
5223
5549
  message.state = "dead_lettered";
5224
5550
  message.deadLetterReason = input.reason;
5225
5551
  delete message.lease;
5226
5552
  message.updatedAt = timestamp;
5227
- this.recordEvent("run_completed", { agentId: run.agentId, messageId: message.id, runId: run.id }, {
5553
+ this.recordEvent("run_completed", { agentId: run.agentId, messageId: message.id, runId: run.id }, runEventPayload(run.metadata, {
5228
5554
  state: "failed",
5229
5555
  outcome: input.outcome
5230
- });
5556
+ }));
5231
5557
  this.recordEvent("message_dead_lettered", { agentId: run.agentId, messageId: message.id }, {
5232
5558
  reason: input.reason
5233
5559
  });
@@ -5240,6 +5566,8 @@ var InMemoryRuntimeStateStore = class {
5240
5566
  const { timestamp } = now();
5241
5567
  run.state = "cancelled";
5242
5568
  run.outcome = clone2(input.outcome);
5569
+ delete run.inputRequest;
5570
+ delete run.executionState;
5243
5571
  delete run.leaseId;
5244
5572
  run.updatedAt = timestamp;
5245
5573
  if (message.state === "queued" || message.state === "leased") {
@@ -5247,9 +5575,10 @@ var InMemoryRuntimeStateStore = class {
5247
5575
  delete message.lease;
5248
5576
  message.updatedAt = timestamp;
5249
5577
  }
5250
- this.recordEvent("run_aborted", { agentId: run.agentId, messageId: message.id, runId: run.id }, {
5578
+ this.recordEvent("run_aborted", { agentId: run.agentId, messageId: message.id, runId: run.id }, runEventPayload(run.metadata, {
5579
+ state: "cancelled",
5251
5580
  outcome: input.outcome
5252
- });
5581
+ }));
5253
5582
  return clone2(run);
5254
5583
  }
5255
5584
  async recoverExpiredLeases(input) {
@@ -5390,6 +5719,29 @@ var InMemoryRuntimeStateStore = class {
5390
5719
  this.eventCheckpoints.set(consumerId, checkpoint);
5391
5720
  return clone2(checkpoint);
5392
5721
  }
5722
+ async acknowledgeEventAndEnqueueAgentInput(input) {
5723
+ const event = this.events.find((candidate) => candidate.id === input.eventId);
5724
+ if (!event) throw new Error(`Runtime Event not found: ${input.eventId}.`);
5725
+ const current = this.eventCheckpoints.get(input.consumerId) ?? {
5726
+ consumerId: input.consumerId,
5727
+ sequence: 0,
5728
+ updatedAt: createTimestamp(/* @__PURE__ */ new Date(0))
5729
+ };
5730
+ if (event.sequence <= current.sequence) return { checkpoint: clone2(current) };
5731
+ if (event.sequence !== current.sequence + 1) {
5732
+ throw new Error(`Runtime Event Consumer Checkpoint cannot advance from sequence ${current.sequence} to ${event.sequence}.`);
5733
+ }
5734
+ this.requireAgent(input.agentId);
5735
+ const enqueued = this.enqueueAgentInputState(input);
5736
+ const checkpoint = {
5737
+ consumerId: input.consumerId,
5738
+ sequence: event.sequence,
5739
+ eventId: event.id,
5740
+ updatedAt: createTimestamp()
5741
+ };
5742
+ this.eventCheckpoints.set(input.consumerId, checkpoint);
5743
+ return { checkpoint: clone2(checkpoint), enqueued };
5744
+ }
5393
5745
  requireAgent(agentId) {
5394
5746
  const agent = this.agents.get(agentId);
5395
5747
  if (!agent) {
@@ -5438,7 +5790,6 @@ var RUNTIME_SCHEMA_SQL = `
5438
5790
  CREATE TABLE IF NOT EXISTS agents (
5439
5791
  id TEXT PRIMARY KEY NOT NULL,
5440
5792
  session_id TEXT NOT NULL,
5441
- factory_id TEXT,
5442
5793
  state TEXT NOT NULL CHECK (state IN ('active', 'paused')),
5443
5794
  created_at TEXT NOT NULL,
5444
5795
  updated_at TEXT NOT NULL
@@ -5466,6 +5817,9 @@ var RUNTIME_SCHEMA_SQL = `
5466
5817
  lease_id TEXT,
5467
5818
  outcome_json TEXT,
5468
5819
  suspension_reason TEXT,
5820
+ input_request_json TEXT,
5821
+ execution_state_json TEXT,
5822
+ metadata_json TEXT,
5469
5823
  created_at TEXT NOT NULL,
5470
5824
  updated_at TEXT NOT NULL
5471
5825
  );
@@ -5528,6 +5882,11 @@ function initializeRuntimeSchema(database) {
5528
5882
  database.run(sql);
5529
5883
  }
5530
5884
  }
5885
+ try {
5886
+ database.run("ALTER TABLE agent_runs ADD COLUMN metadata_json TEXT");
5887
+ } catch (error) {
5888
+ if (!(error instanceof Error) || !/duplicate column name/i.test(error.message)) throw error;
5889
+ }
5531
5890
  });
5532
5891
  initialize();
5533
5892
  }
@@ -5572,15 +5931,14 @@ var SqliteRuntimeStateStore = class {
5572
5931
  const agent = {
5573
5932
  id: createId("agt"),
5574
5933
  sessionId: input.sessionId,
5575
- ...input.factoryId ? { factoryId: input.factoryId } : {},
5576
5934
  state: "active",
5577
5935
  createdAt: timestamp,
5578
5936
  updatedAt: timestamp
5579
5937
  };
5580
5938
  const create = this.database.transaction(() => {
5581
5939
  this.database.run(
5582
- "INSERT INTO agents (id, session_id, factory_id, state, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)",
5583
- [agent.id, agent.sessionId, agent.factoryId ?? null, agent.state, agent.createdAt, agent.updatedAt]
5940
+ "INSERT INTO agents (id, session_id, state, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",
5941
+ [agent.id, agent.sessionId, agent.state, agent.createdAt, agent.updatedAt]
5584
5942
  );
5585
5943
  this.recordEvent("agent_created", { agentId: agent.id });
5586
5944
  });
@@ -5607,6 +5965,10 @@ var SqliteRuntimeStateStore = class {
5607
5965
  return clone3(updated);
5608
5966
  }
5609
5967
  async enqueueAgentInput(input) {
5968
+ const enqueue = this.database.transaction(() => this.enqueueAgentInputState(input));
5969
+ return clone3(enqueue());
5970
+ }
5971
+ enqueueAgentInputState(input) {
5610
5972
  this.requireAgent(input.agentId);
5611
5973
  const { timestamp } = timestampFor();
5612
5974
  const messageId = createId("rmsg");
@@ -5631,30 +5993,28 @@ var SqliteRuntimeStateStore = class {
5631
5993
  messageId,
5632
5994
  state: "queued",
5633
5995
  attempt: 0,
5996
+ ...suspendedRow?.metadata_json ? { metadata: parse(suspendedRow.metadata_json) } : input.input.metadata ? { metadata: clone3(input.input.metadata) } : {},
5634
5997
  createdAt: timestamp,
5635
5998
  updatedAt: timestamp
5636
5999
  };
5637
6000
  if (suspendedRow) {
5638
6001
  message.runId = runId;
5639
6002
  }
5640
- const enqueue = this.database.transaction(() => {
5641
- this.insertMessage(message);
5642
- if (suspendedRow) {
5643
- this.database.run(
5644
- "UPDATE agent_runs SET message_id = ?, state = 'queued', lease_id = NULL, suspension_reason = NULL, updated_at = ? WHERE id = ?",
5645
- [messageId, timestamp, runId]
5646
- );
5647
- } else {
5648
- this.database.run(
5649
- "INSERT INTO agent_runs (id, agent_id, message_id, state, attempt, lease_id, outcome_json, suspension_reason, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
5650
- [run.id, run.agentId, run.messageId, run.state, run.attempt, null, null, null, run.createdAt, run.updatedAt]
5651
- );
5652
- }
5653
- this.recordEvent("message_enqueued", { agentId: input.agentId, messageId });
5654
- this.recordEvent("run_enqueued", { agentId: input.agentId, messageId, runId });
5655
- });
5656
- enqueue();
6003
+ this.insertMessage(message);
6004
+ if (suspendedRow) {
6005
+ this.database.run(
6006
+ "UPDATE agent_runs SET message_id = ?, state = 'queued', lease_id = NULL, suspension_reason = NULL, input_request_json = NULL, updated_at = ? WHERE id = ?",
6007
+ [messageId, timestamp, runId]
6008
+ );
6009
+ } else {
6010
+ this.database.run(
6011
+ "INSERT INTO agent_runs (id, agent_id, message_id, state, attempt, lease_id, outcome_json, suspension_reason, input_request_json, execution_state_json, metadata_json, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
6012
+ [run.id, run.agentId, run.messageId, run.state, run.attempt, null, null, null, null, null, run.metadata ? json(run.metadata) : null, run.createdAt, run.updatedAt]
6013
+ );
6014
+ }
6015
+ this.recordEventInternal("message_enqueued", { agentId: input.agentId, messageId });
5657
6016
  const storedRun = this.requireRun(runId);
6017
+ this.recordEventInternal("run_enqueued", { agentId: input.agentId, messageId, runId }, runEventPayload(storedRun.metadata));
5658
6018
  return { message: clone3(message), run: clone3(storedRun), resumed: Boolean(suspendedRow) };
5659
6019
  }
5660
6020
  async getMessage(messageId) {
@@ -5680,6 +6040,12 @@ var SqliteRuntimeStateStore = class {
5680
6040
  const rows = this.database.query(`SELECT * FROM agent_runs ${where} ORDER BY created_at, id`).all(...params);
5681
6041
  return rows.map((row) => this.runFromRow(row));
5682
6042
  }
6043
+ async listActiveRuns() {
6044
+ const rows = this.database.query(
6045
+ "SELECT * FROM agent_runs WHERE state IN ('queued', 'running', 'suspended') ORDER BY created_at, id"
6046
+ ).all();
6047
+ return rows.map((row) => this.runFromRow(row));
6048
+ }
5683
6049
  async leaseRun(input) {
5684
6050
  const lease = this.database.transaction(() => {
5685
6051
  const run2 = this.requireRun(input.runId);
@@ -5754,17 +6120,17 @@ var SqliteRuntimeStateStore = class {
5754
6120
  requireTransition2("Runtime Message", message.id, message.state, "acknowledge", ["leased"]);
5755
6121
  const { timestamp } = timestampFor();
5756
6122
  this.database.run(
5757
- "UPDATE agent_runs SET state = ?, lease_id = NULL, suspension_reason = ?, updated_at = ? WHERE id = ?",
5758
- ["suspended", input.reason ?? null, timestamp, current.id]
6123
+ "UPDATE agent_runs SET state = ?, lease_id = NULL, suspension_reason = ?, input_request_json = ?, execution_state_json = ?, updated_at = ? WHERE id = ?",
6124
+ ["suspended", input.reason ?? null, input.inputRequest ? json(input.inputRequest) : null, input.executionState ? json(input.executionState) : null, timestamp, current.id]
5759
6125
  );
5760
6126
  this.database.run(
5761
6127
  "UPDATE runtime_messages SET state = ?, updated_at = ? WHERE id = ?",
5762
6128
  ["acknowledged", timestamp, message.id]
5763
6129
  );
5764
6130
  this.database.run("DELETE FROM runtime_leases WHERE run_id = ?", [current.id]);
5765
- this.recordEvent("run_suspended", { agentId: current.agentId, messageId: message.id, runId: current.id }, {
6131
+ this.recordEvent("run_suspended", { agentId: current.agentId, messageId: message.id, runId: current.id }, runEventPayload(current.metadata, {
5766
6132
  reason: input.reason
5767
- });
6133
+ }));
5768
6134
  return this.requireRun(current.id);
5769
6135
  })();
5770
6136
  return clone3(run);
@@ -5778,7 +6144,7 @@ var SqliteRuntimeStateStore = class {
5778
6144
  const { timestamp } = timestampFor();
5779
6145
  const state = input.state ?? "completed";
5780
6146
  this.database.run(
5781
- "UPDATE agent_runs SET state = ?, lease_id = NULL, outcome_json = ?, updated_at = ? WHERE id = ?",
6147
+ "UPDATE agent_runs SET state = ?, lease_id = NULL, outcome_json = ?, input_request_json = NULL, execution_state_json = NULL, updated_at = ? WHERE id = ?",
5782
6148
  [state, json(input.outcome), timestamp, current.id]
5783
6149
  );
5784
6150
  this.database.run(
@@ -5786,10 +6152,10 @@ var SqliteRuntimeStateStore = class {
5786
6152
  [timestamp, message.id]
5787
6153
  );
5788
6154
  this.database.run("DELETE FROM runtime_leases WHERE run_id = ?", [current.id]);
5789
- this.recordEvent("run_completed", { agentId: current.agentId, messageId: current.messageId, runId: current.id }, {
6155
+ this.recordEvent("run_completed", { agentId: current.agentId, messageId: current.messageId, runId: current.id }, runEventPayload(current.metadata, {
5790
6156
  state,
5791
6157
  outcome: input.outcome
5792
- });
6158
+ }));
5793
6159
  this.recordEvent("message_acknowledged", { agentId: message.agentId, messageId: message.id });
5794
6160
  return this.requireRun(current.id);
5795
6161
  })();
@@ -5828,7 +6194,7 @@ var SqliteRuntimeStateStore = class {
5828
6194
  requireTransition2("Runtime Message", message.id, message.state, "dead-letter", ["leased"]);
5829
6195
  const { timestamp } = timestampFor();
5830
6196
  this.database.run(
5831
- "UPDATE agent_runs SET state = 'failed', lease_id = NULL, outcome_json = ?, updated_at = ? WHERE id = ?",
6197
+ "UPDATE agent_runs SET state = 'failed', lease_id = NULL, outcome_json = ?, input_request_json = NULL, execution_state_json = NULL, updated_at = ? WHERE id = ?",
5832
6198
  [json(input.outcome), timestamp, current.id]
5833
6199
  );
5834
6200
  this.database.run(
@@ -5836,10 +6202,10 @@ var SqliteRuntimeStateStore = class {
5836
6202
  [input.reason, timestamp, message.id]
5837
6203
  );
5838
6204
  this.database.run("DELETE FROM runtime_leases WHERE run_id = ?", [current.id]);
5839
- this.recordEvent("run_completed", { agentId: current.agentId, messageId: message.id, runId: current.id }, {
6205
+ this.recordEvent("run_completed", { agentId: current.agentId, messageId: message.id, runId: current.id }, runEventPayload(current.metadata, {
5840
6206
  state: "failed",
5841
6207
  outcome: input.outcome
5842
- });
6208
+ }));
5843
6209
  this.recordEvent("message_dead_lettered", { agentId: current.agentId, messageId: message.id }, {
5844
6210
  reason: input.reason
5845
6211
  });
@@ -5854,7 +6220,7 @@ var SqliteRuntimeStateStore = class {
5854
6220
  const message = this.requireMessage(current.messageId);
5855
6221
  const { timestamp } = timestampFor();
5856
6222
  this.database.run(
5857
- "UPDATE agent_runs SET state = 'cancelled', lease_id = NULL, outcome_json = ?, updated_at = ? WHERE id = ?",
6223
+ "UPDATE agent_runs SET state = 'cancelled', lease_id = NULL, outcome_json = ?, input_request_json = NULL, execution_state_json = NULL, updated_at = ? WHERE id = ?",
5858
6224
  [json(input.outcome), timestamp, current.id]
5859
6225
  );
5860
6226
  if (message.state === "queued" || message.state === "leased") {
@@ -5864,9 +6230,10 @@ var SqliteRuntimeStateStore = class {
5864
6230
  ]);
5865
6231
  }
5866
6232
  this.database.run("DELETE FROM runtime_leases WHERE run_id = ?", [current.id]);
5867
- this.recordEvent("run_aborted", { agentId: current.agentId, messageId: message.id, runId: current.id }, {
6233
+ this.recordEvent("run_aborted", { agentId: current.agentId, messageId: message.id, runId: current.id }, runEventPayload(current.metadata, {
6234
+ state: "cancelled",
5868
6235
  outcome: input.outcome
5869
- });
6236
+ }));
5870
6237
  return this.requireRun(current.id);
5871
6238
  })();
5872
6239
  return clone3(run);
@@ -6040,27 +6407,41 @@ var SqliteRuntimeStateStore = class {
6040
6407
  return clone3(this.eventCheckpoint(consumerId));
6041
6408
  }
6042
6409
  async acknowledgeEvent(consumerId, eventId) {
6043
- const checkpoint = this.database.transaction(() => {
6044
- const event = this.requireEvent(eventId);
6045
- const current = this.eventCheckpoint(consumerId);
6046
- if (event.sequence <= current.sequence) return current;
6047
- if (event.sequence !== current.sequence + 1) {
6048
- throw new Error(`Runtime Event Consumer Checkpoint cannot advance from sequence ${current.sequence} to ${event.sequence}.`);
6049
- }
6050
- const updatedAt = createTimestamp();
6051
- this.database.run(
6052
- `INSERT INTO runtime_event_consumers (consumer_id, sequence, event_id, updated_at)
6053
- VALUES (?, ?, ?, ?)
6054
- ON CONFLICT(consumer_id) DO UPDATE SET
6055
- sequence = excluded.sequence,
6056
- event_id = excluded.event_id,
6057
- updated_at = excluded.updated_at`,
6058
- [consumerId, event.sequence, event.id, updatedAt]
6059
- );
6060
- return this.eventCheckpoint(consumerId);
6061
- })();
6410
+ const acknowledge = this.database.transaction(() => this.acknowledgeEventState(consumerId, eventId));
6411
+ const checkpoint = acknowledge();
6062
6412
  return clone3(checkpoint);
6063
6413
  }
6414
+ async acknowledgeEventAndEnqueueAgentInput(input) {
6415
+ const deliver = this.database.transaction(() => {
6416
+ const event = this.requireEvent(input.eventId);
6417
+ const current = this.eventCheckpoint(input.consumerId);
6418
+ if (event.sequence <= current.sequence) return { checkpoint: current };
6419
+ this.requireAgent(input.agentId);
6420
+ const enqueued = this.enqueueAgentInputState(input);
6421
+ const checkpoint = this.acknowledgeEventState(input.consumerId, input.eventId);
6422
+ return { checkpoint, enqueued };
6423
+ });
6424
+ return clone3(deliver());
6425
+ }
6426
+ acknowledgeEventState(consumerId, eventId) {
6427
+ const event = this.requireEvent(eventId);
6428
+ const current = this.eventCheckpoint(consumerId);
6429
+ if (event.sequence <= current.sequence) return current;
6430
+ if (event.sequence !== current.sequence + 1) {
6431
+ throw new Error(`Runtime Event Consumer Checkpoint cannot advance from sequence ${current.sequence} to ${event.sequence}.`);
6432
+ }
6433
+ const updatedAt = createTimestamp();
6434
+ this.database.run(
6435
+ `INSERT INTO runtime_event_consumers (consumer_id, sequence, event_id, updated_at)
6436
+ VALUES (?, ?, ?, ?)
6437
+ ON CONFLICT(consumer_id) DO UPDATE SET
6438
+ sequence = excluded.sequence,
6439
+ event_id = excluded.event_id,
6440
+ updated_at = excluded.updated_at`,
6441
+ [consumerId, event.sequence, event.id, updatedAt]
6442
+ );
6443
+ return this.eventCheckpoint(consumerId);
6444
+ }
6064
6445
  insertMessage(message) {
6065
6446
  this.database.run(
6066
6447
  "INSERT INTO runtime_messages (id, agent_id, kind, payload_json, state, attempts, run_id, dead_letter_reason, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
@@ -6071,7 +6452,6 @@ var SqliteRuntimeStateStore = class {
6071
6452
  return {
6072
6453
  id: row.id,
6073
6454
  sessionId: row.session_id,
6074
- ...row.factory_id ? { factoryId: row.factory_id } : {},
6075
6455
  state: row.state,
6076
6456
  createdAt: row.created_at,
6077
6457
  updatedAt: row.updated_at
@@ -6111,6 +6491,9 @@ var SqliteRuntimeStateStore = class {
6111
6491
  ...row.lease_id ? { leaseId: row.lease_id } : {},
6112
6492
  ...row.outcome_json ? { outcome: parse(row.outcome_json) } : {},
6113
6493
  ...row.suspension_reason ? { suspensionReason: row.suspension_reason } : {},
6494
+ ...row.input_request_json ? { inputRequest: parse(row.input_request_json) } : {},
6495
+ ...row.execution_state_json ? { executionState: parse(row.execution_state_json) } : {},
6496
+ ...row.metadata_json ? { metadata: parse(row.metadata_json) } : {},
6114
6497
  createdAt: row.created_at,
6115
6498
  updatedAt: row.updated_at
6116
6499
  };
@@ -6235,8 +6618,8 @@ export {
6235
6618
  AgentRun,
6236
6619
  AgentRuntime,
6237
6620
  InMemoryRuntimeStateStore,
6238
- InMemorySessionProvider,
6239
- LocalJsonlSessionProvider,
6621
+ InMemorySessionStore,
6622
+ JsonlSessionStore,
6240
6623
  SqliteRuntimeStateStore,
6241
6624
  createCoreTools,
6242
6625
  createMessage