@linnlabs/linnkit 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/linnkit.cjs +7 -0
  3. package/dist/{agentSpec-EkmviZjy.d.cts → agentSpec-Du4Iye0q.d.cts} +16 -1
  4. package/dist/{agentSpec-EkmviZjy.d.ts → agentSpec-Du4Iye0q.d.ts} +16 -1
  5. package/dist/cli.cjs +118 -65
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/cli.js +118 -65
  8. package/dist/cli.js.map +1 -1
  9. package/dist/context-manager.cjs +234 -32
  10. package/dist/context-manager.cjs.map +1 -1
  11. package/dist/context-manager.d.cts +52 -15
  12. package/dist/context-manager.d.ts +52 -15
  13. package/dist/context-manager.js +234 -33
  14. package/dist/context-manager.js.map +1 -1
  15. package/dist/{context-trace-HE2qY5Q-.d.cts → context-trace-BHKDS-eq.d.cts} +2 -2
  16. package/dist/{context-trace-DRi5M4lX.d.ts → context-trace-CHbqHmyE.d.ts} +2 -2
  17. package/dist/contracts.cjs +3 -1
  18. package/dist/contracts.cjs.map +1 -1
  19. package/dist/contracts.d.cts +3 -3
  20. package/dist/contracts.d.ts +3 -3
  21. package/dist/contracts.js +3 -1
  22. package/dist/contracts.js.map +1 -1
  23. package/dist/{defaultGraphExecutor-BBswR8wn.d.ts → defaultGraphExecutor-B29_qTHy.d.ts} +16 -15
  24. package/dist/{defaultGraphExecutor-BIjJj7WF.d.cts → defaultGraphExecutor-C2E59v_R.d.cts} +16 -15
  25. package/dist/{index-BanRABEt.d.cts → index-BAaUP9yU.d.cts} +26 -14
  26. package/dist/{index-Z8NXKNwI.d.ts → index-BaVpVNi2.d.ts} +26 -14
  27. package/dist/{index-DO4dQgf2.d.cts → index-BnYCS8Zg.d.cts} +2 -2
  28. package/dist/{index-CJeWHopy.d.ts → index-C0DAjsdX.d.ts} +2 -2
  29. package/dist/{index-Dl5PLgAv.d.cts → index-CKQzzZ5Y.d.cts} +2 -2
  30. package/dist/{index-CHqwkvGp.d.ts → index-D0mKxTR5.d.ts} +2 -2
  31. package/dist/index.cjs +186 -85
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +10 -10
  34. package/dist/index.d.ts +10 -10
  35. package/dist/index.js +186 -85
  36. package/dist/index.js.map +1 -1
  37. package/dist/{ports-DnLuKfpE.d.ts → ports-DpPTFhSd.d.ts} +2 -2
  38. package/dist/{ports-DaatKJXp.d.cts → ports-s-tSp3sB.d.cts} +2 -2
  39. package/dist/quickstart.cjs +119 -65
  40. package/dist/quickstart.cjs.map +1 -1
  41. package/dist/quickstart.d.cts +7 -7
  42. package/dist/quickstart.d.ts +7 -7
  43. package/dist/quickstart.js +119 -65
  44. package/dist/quickstart.js.map +1 -1
  45. package/dist/{runAgent-CPj_9e58.d.ts → runAgent-C6F-399C.d.ts} +5 -5
  46. package/dist/{runAgent-HYKlXbVr.d.cts → runAgent-ilEj66Ik.d.cts} +5 -5
  47. package/dist/{runHandle-D3gPsD7B.d.cts → runHandle-BNOqS-Bl.d.cts} +3 -3
  48. package/dist/{runHandle-CyXvzgzk.d.ts → runHandle-BdLXOFqF.d.ts} +3 -3
  49. package/dist/runtime-kernel/events.cjs +1 -0
  50. package/dist/runtime-kernel/events.cjs.map +1 -1
  51. package/dist/runtime-kernel/events.d.cts +4 -4
  52. package/dist/runtime-kernel/events.d.ts +4 -4
  53. package/dist/runtime-kernel/events.js +1 -0
  54. package/dist/runtime-kernel/events.js.map +1 -1
  55. package/dist/runtime-kernel.cjs +181 -82
  56. package/dist/runtime-kernel.cjs.map +1 -1
  57. package/dist/runtime-kernel.d.cts +8 -8
  58. package/dist/runtime-kernel.d.ts +8 -8
  59. package/dist/runtime-kernel.js +181 -83
  60. package/dist/runtime-kernel.js.map +1 -1
  61. package/dist/testkit.cjs +181 -82
  62. package/dist/testkit.cjs.map +1 -1
  63. package/dist/testkit.d.cts +8 -8
  64. package/dist/testkit.d.ts +8 -8
  65. package/dist/testkit.js +181 -82
  66. package/dist/testkit.js.map +1 -1
  67. package/dist/{todo-B1PmDlp3.d.cts → todo-Ca8llpRQ.d.cts} +1 -1
  68. package/dist/{todo-B1PmDlp3.d.ts → todo-Ca8llpRQ.d.ts} +1 -1
  69. package/dist/{toolContracts-CLkQmhTG.d.cts → toolContracts-Bm3EZ1UM.d.cts} +13 -2
  70. package/dist/{toolContracts-Blll0241.d.ts → toolContracts-f8lzZBNa.d.ts} +13 -2
  71. package/docs/integration/README.md +1 -1
  72. package/docs/integration/agent-registration-guide.md +1 -1
  73. package/docs/integration/child-runs.md +4 -1
  74. package/docs/integration/context-engineering.md +30 -15
  75. package/docs/integration/context-fences.md +32 -3
  76. package/docs/integration/llm-provider.md +1 -1
  77. package/docs/integration/persistence.md +1 -0
  78. package/docs/integration/run-supervisor.md +3 -0
  79. package/docs/integration/tool-development-guide.md +7 -5
  80. package/docs/integration/tool-history.md +43 -17
  81. package/package.json +4 -3
@@ -1,4 +1,4 @@
1
- import { O as OpenAIToolSchema, b as ToolParameterSchema, h as ToolDisplayOptions, y as ToolIdempotencyPolicy, a as ToolArgs, T as ToolExecutionContext } from './toolContracts-Blll0241.js';
1
+ import { O as OpenAIToolSchema, b as ToolParameterSchema, h as ToolDisplayOptions, y as ToolIdempotencyPolicy, T as ToolArgs, a as ToolExecutionContext } from './toolContracts-f8lzZBNa.js';
2
2
 
3
3
  /**
4
4
  * tool schema 生成阶段的最小上下文合同
@@ -87,4 +87,4 @@ interface ObservationPreviewPort {
87
87
  interface ToolRuntimePort extends ToolCatalogPort, ToolPresentationPort, ToolExecutionPort {
88
88
  }
89
89
 
90
- export type { ConversationArtifactContext as C, ObservationPreviewPort as O, ToolCatalogPort as T, ToolPresentationPort as a, ToolExecutionPort as b, ObservationPreviewContext as c, ObservationPreviewMeta as d, ObservationPreviewResult as e, ToolExecutionResult as f, ToolRuntimeDefinition as g, ToolRuntimePort as h, ToolSchemaContext as i };
90
+ export type { ConversationArtifactContext as C, ObservationPreviewPort as O, ToolRuntimeDefinition as T, ToolExecutionResult as a, ToolCatalogPort as b, ToolPresentationPort as c, ToolExecutionPort as d, ObservationPreviewContext as e, ObservationPreviewMeta as f, ObservationPreviewResult as g, ToolRuntimePort as h, ToolSchemaContext as i };
@@ -1,4 +1,4 @@
1
- import { O as OpenAIToolSchema, b as ToolParameterSchema, h as ToolDisplayOptions, y as ToolIdempotencyPolicy, a as ToolArgs, T as ToolExecutionContext } from './toolContracts-CLkQmhTG.cjs';
1
+ import { O as OpenAIToolSchema, b as ToolParameterSchema, h as ToolDisplayOptions, y as ToolIdempotencyPolicy, T as ToolArgs, a as ToolExecutionContext } from './toolContracts-Bm3EZ1UM.cjs';
2
2
 
3
3
  /**
4
4
  * tool schema 生成阶段的最小上下文合同
@@ -87,4 +87,4 @@ interface ObservationPreviewPort {
87
87
  interface ToolRuntimePort extends ToolCatalogPort, ToolPresentationPort, ToolExecutionPort {
88
88
  }
89
89
 
90
- export type { ConversationArtifactContext as C, ObservationPreviewPort as O, ToolCatalogPort as T, ToolPresentationPort as a, ToolExecutionPort as b, ObservationPreviewContext as c, ObservationPreviewMeta as d, ObservationPreviewResult as e, ToolExecutionResult as f, ToolRuntimeDefinition as g, ToolRuntimePort as h, ToolSchemaContext as i };
90
+ export type { ConversationArtifactContext as C, ObservationPreviewPort as O, ToolRuntimeDefinition as T, ToolExecutionResult as a, ToolCatalogPort as b, ToolPresentationPort as c, ToolExecutionPort as d, ObservationPreviewContext as e, ObservationPreviewMeta as f, ObservationPreviewResult as g, ToolRuntimePort as h, ToolSchemaContext as i };
@@ -168,6 +168,7 @@ var AgentSpecBudgetPolicy = zod.z.object({
168
168
  });
169
169
  var AgentSpecToolHistoryPolicy = zod.z.object({
170
170
  strategy: zod.z.enum(["per-pair", "per-run", "none"]).optional(),
171
+ retentionMode: zod.z.enum(["drop", "compress"]).optional(),
171
172
  keepLatestToolPairs: zod.z.number().int().nonnegative().optional(),
172
173
  keepLatestRuns: zod.z.number().int().nonnegative().optional(),
173
174
  maxInteractionGroups: zod.z.number().int().nonnegative().optional(),
@@ -282,12 +283,13 @@ var AgentSpecContextPolicy = zod.z.object({
282
283
  var DEFAULT_CONTEXT_POLICY = {
283
284
  profileId: "agent",
284
285
  budget: {
285
- maxTokens: 12e4,
286
+ maxTokens: 232e3,
286
287
  reservedForResponse: 2400,
287
288
  workingMemoryBudgetPercentage: 0.7
288
289
  },
289
290
  toolHistory: {
290
291
  strategy: "per-run",
292
+ retentionMode: "drop",
291
293
  keepLatestToolPairs: 2,
292
294
  keepLatestRuns: 1,
293
295
  maxInteractionGroups: 12,
@@ -1200,6 +1202,7 @@ var Logger = class {
1200
1202
  constructor(moduleName) {
1201
1203
  this.moduleName = moduleName;
1202
1204
  }
1205
+ moduleName;
1203
1206
  debug(message, data) {
1204
1207
  this.log(0 /* DEBUG */, "debug", message, data);
1205
1208
  }
@@ -1272,6 +1275,17 @@ var logger = new Logger("GraphExecutor");
1272
1275
  function asLocalRecord(local) {
1273
1276
  return local && typeof local === "object" ? { ...local } : {};
1274
1277
  }
1278
+ function readNonEmptyString(value) {
1279
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1280
+ }
1281
+ function readRuntimeConversationId(state) {
1282
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1283
+ return readNonEmptyString(local?.conversationId);
1284
+ }
1285
+ function readRuntimeTurnId(state) {
1286
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1287
+ return readNonEmptyString(local?.turnId);
1288
+ }
1275
1289
  var GraphExecutor = class {
1276
1290
  constructor(checkpointer, config = {}) {
1277
1291
  this.checkpointer = checkpointer;
@@ -1281,6 +1295,7 @@ var GraphExecutor = class {
1281
1295
  };
1282
1296
  this.telemetryPort = config.telemetryPort ?? noopTelemetry;
1283
1297
  }
1298
+ checkpointer;
1284
1299
  nodes = /* @__PURE__ */ new Map();
1285
1300
  ephemeralLocals = /* @__PURE__ */ new Map();
1286
1301
  config;
@@ -1288,8 +1303,8 @@ var GraphExecutor = class {
1288
1303
  registerNode(node) {
1289
1304
  this.nodes.set(node.id, node);
1290
1305
  }
1291
- async peekCheckpoint(conversationId) {
1292
- return await this.checkpointer.load(conversationId);
1306
+ async peekCheckpoint(checkpointKey) {
1307
+ return await this.checkpointer.load(checkpointKey);
1293
1308
  }
1294
1309
  sanitize(state) {
1295
1310
  const local = asLocalRecord(state.local);
@@ -1301,8 +1316,8 @@ var GraphExecutor = class {
1301
1316
  local
1302
1317
  };
1303
1318
  }
1304
- async prime(conversationId, local, nodeId = "user") {
1305
- this.ephemeralLocals.set(conversationId, { ...local || {} });
1319
+ async prime(checkpointKey, local, nodeId = "user") {
1320
+ this.ephemeralLocals.set(checkpointKey, { ...local || {} });
1306
1321
  const localSansMemory = { ...local || {} };
1307
1322
  if ("memory" in localSansMemory) delete localSansMemory.memory;
1308
1323
  const state = {
@@ -1310,10 +1325,10 @@ var GraphExecutor = class {
1310
1325
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1311
1326
  local: localSansMemory
1312
1327
  };
1313
- await this.checkpointer.save(conversationId, state);
1328
+ await this.checkpointer.save(checkpointKey, state);
1314
1329
  }
1315
- async setNode(conversationId, nodeId, localPatch) {
1316
- const current = await this.checkpointer.load(conversationId) || {
1330
+ async setNode(checkpointKey, nodeId, localPatch) {
1331
+ const current = await this.checkpointer.load(checkpointKey) || {
1317
1332
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1318
1333
  local: {}
1319
1334
  };
@@ -1324,19 +1339,46 @@ var GraphExecutor = class {
1324
1339
  schemaVersion: current.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
1325
1340
  local: mergedLocal
1326
1341
  };
1327
- await this.checkpointer.save(conversationId, next);
1342
+ await this.checkpointer.save(checkpointKey, next);
1328
1343
  }
1329
- async runUntilYield(conversationId) {
1344
+ async runUntilYield(checkpointKey) {
1330
1345
  const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1331
1346
  let lifecyclePhase = "completed";
1347
+ let initialState = null;
1348
+ try {
1349
+ initialState = await this.loadInitialState(checkpointKey);
1350
+ } catch (err) {
1351
+ lifecyclePhase = "failed";
1352
+ this.telemetryPort.emit({
1353
+ kind: "run_lifecycle",
1354
+ runId,
1355
+ phase: "spawned",
1356
+ scope: {}
1357
+ });
1358
+ this.telemetryPort.emit({
1359
+ kind: "run_lifecycle",
1360
+ runId,
1361
+ phase: lifecyclePhase,
1362
+ scope: {}
1363
+ });
1364
+ throw err;
1365
+ }
1366
+ let lifecycleConversationId = readRuntimeConversationId(initialState);
1367
+ let lifecycleTurnId = readRuntimeTurnId(initialState);
1332
1368
  this.telemetryPort.emit({
1333
1369
  kind: "run_lifecycle",
1334
1370
  runId,
1335
1371
  phase: "spawned",
1336
- scope: { conversationId: conversationId || void 0 }
1372
+ scope: {
1373
+ conversationId: lifecycleConversationId,
1374
+ turnId: lifecycleTurnId
1375
+ }
1337
1376
  });
1338
1377
  try {
1339
- return await this.runUntilYieldInternal(conversationId);
1378
+ const result = await this.runUntilYieldInternal(checkpointKey, initialState);
1379
+ lifecycleConversationId = readRuntimeConversationId(result.checkpoint);
1380
+ lifecycleTurnId = readRuntimeTurnId(result.checkpoint);
1381
+ return result;
1340
1382
  } catch (err) {
1341
1383
  lifecyclePhase = err?.name === "AbortError" ? "cancelled" : "failed";
1342
1384
  throw err;
@@ -1345,17 +1387,23 @@ var GraphExecutor = class {
1345
1387
  kind: "run_lifecycle",
1346
1388
  runId,
1347
1389
  phase: lifecyclePhase,
1348
- scope: { conversationId: conversationId || void 0 }
1390
+ scope: {
1391
+ conversationId: lifecycleConversationId,
1392
+ turnId: lifecycleTurnId
1393
+ }
1349
1394
  });
1350
1395
  }
1351
1396
  }
1352
- async runUntilYieldInternal(conversationId) {
1353
- let state = await this.checkpointer.load(conversationId) || {
1397
+ async loadInitialState(checkpointKey) {
1398
+ return await this.checkpointer.load(checkpointKey) || {
1354
1399
  nodeId: "user",
1355
1400
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1356
1401
  local: {}
1357
1402
  };
1358
- const ephemeral = this.ephemeralLocals.get(conversationId) || {};
1403
+ }
1404
+ async runUntilYieldInternal(checkpointKey, initialState) {
1405
+ let state = initialState;
1406
+ const ephemeral = this.ephemeralLocals.get(checkpointKey) || {};
1359
1407
  state = {
1360
1408
  ...state,
1361
1409
  schemaVersion: state.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
@@ -1384,7 +1432,7 @@ var GraphExecutor = class {
1384
1432
  const signalRaw = state.local?.signal;
1385
1433
  if (isAbortSignal2(signalRaw) && signalRaw.aborted) {
1386
1434
  logger.warn("[GraphExecutor] \u6536\u5230 AbortSignal\uFF0C\u7ACB\u5373\u505C\u6B62\u63A8\u7406\u5FAA\u73AF");
1387
- this.ephemeralLocals.delete(conversationId);
1435
+ this.ephemeralLocals.delete(checkpointKey);
1388
1436
  throwAbortError();
1389
1437
  }
1390
1438
  const isLastStep = cycleStepCount >= this.config.maxSteps;
@@ -1432,8 +1480,8 @@ var GraphExecutor = class {
1432
1480
  checkpointCount
1433
1481
  });
1434
1482
  const cp2 = this.sanitize(state);
1435
- await this.checkpointer.save(conversationId, cp2);
1436
- this.ephemeralLocals.delete(conversationId);
1483
+ await this.checkpointer.save(checkpointKey, cp2);
1484
+ this.ephemeralLocals.delete(checkpointKey);
1437
1485
  return { events: allEvents, checkpoint: cp2, stepCount };
1438
1486
  }
1439
1487
  logger.info("[GraphExecutor] \u8282\u70B9\u5207\u6362", {
@@ -1444,18 +1492,18 @@ var GraphExecutor = class {
1444
1492
  });
1445
1493
  const nodeRunStartedAt = Date.now();
1446
1494
  const nodeIdForTelemetry = state.nodeId;
1495
+ const conversationIdForTelemetry = readRuntimeConversationId(state);
1447
1496
  let result;
1448
1497
  try {
1449
1498
  result = await node.run(state);
1450
1499
  } finally {
1451
- const turnIdForTelemetry = typeof state.local?.turnId === "string" ? state.local.turnId : void 0;
1452
1500
  this.telemetryPort.emit({
1453
1501
  kind: "graph_node",
1454
1502
  nodeId: nodeIdForTelemetry,
1455
1503
  durationMs: Date.now() - nodeRunStartedAt,
1456
1504
  scope: {
1457
- conversationId: conversationId || void 0,
1458
- turnId: turnIdForTelemetry
1505
+ conversationId: conversationIdForTelemetry,
1506
+ turnId: readRuntimeTurnId(state)
1459
1507
  }
1460
1508
  });
1461
1509
  }
@@ -1494,7 +1542,7 @@ var GraphExecutor = class {
1494
1542
  });
1495
1543
  state = { ...state, nodeId: nextNodeId };
1496
1544
  const cp2 = this.sanitize(state);
1497
- await this.checkpointer.save(conversationId, cp2);
1545
+ await this.checkpointer.save(checkpointKey, cp2);
1498
1546
  continue;
1499
1547
  }
1500
1548
  if (result.kind === "yield") {
@@ -1505,7 +1553,7 @@ var GraphExecutor = class {
1505
1553
  checkpointCount
1506
1554
  });
1507
1555
  const cp2 = this.sanitize(state);
1508
- await this.checkpointer.save(conversationId, cp2);
1556
+ await this.checkpointer.save(checkpointKey, cp2);
1509
1557
  return { events: allEvents, checkpoint: cp2, stepCount };
1510
1558
  }
1511
1559
  if (result.kind === "pause") {
@@ -1516,7 +1564,7 @@ var GraphExecutor = class {
1516
1564
  checkpointCount
1517
1565
  });
1518
1566
  const cp2 = this.sanitize(state);
1519
- await this.checkpointer.save(conversationId, cp2);
1567
+ await this.checkpointer.save(checkpointKey, cp2);
1520
1568
  return { events: allEvents, checkpoint: cp2, stepCount };
1521
1569
  }
1522
1570
  }
@@ -1527,8 +1575,8 @@ var GraphExecutor = class {
1527
1575
  checkpointCount
1528
1576
  });
1529
1577
  const cp = this.sanitize(state);
1530
- await this.checkpointer.save(conversationId, cp);
1531
- this.ephemeralLocals.delete(conversationId);
1578
+ await this.checkpointer.save(checkpointKey, cp);
1579
+ this.ephemeralLocals.delete(checkpointKey);
1532
1580
  return { events: allEvents, checkpoint: cp, stepCount };
1533
1581
  }
1534
1582
  };
@@ -1691,15 +1739,15 @@ function splitConcatenatedJsonObjects(input) {
1691
1739
  }
1692
1740
 
1693
1741
  // src/runtime-kernel/graph-engine/tick-pipeline/helpers.ts
1694
- function readNonEmptyString(value) {
1742
+ function readNonEmptyString2(value) {
1695
1743
  if (typeof value !== "string") return void 0;
1696
1744
  const trimmed = value.trim();
1697
1745
  return trimmed.length > 0 ? trimmed : void 0;
1698
1746
  }
1699
1747
  function resolveConversationIdForRuntimeEvents(toolContext) {
1700
- const fromCamel = readNonEmptyString(toolContext?.conversationId);
1748
+ const fromCamel = readNonEmptyString2(toolContext?.conversationId);
1701
1749
  if (fromCamel) return fromCamel;
1702
- const fromSnake = toolContext ? readNonEmptyString(toolContext["conversation_id"]) : void 0;
1750
+ const fromSnake = toolContext ? readNonEmptyString2(toolContext["conversation_id"]) : void 0;
1703
1751
  if (fromSnake) return fromSnake;
1704
1752
  return generateMessageId();
1705
1753
  }
@@ -2056,7 +2104,7 @@ var runModelLockMiddleware = async (ctx, stage, next) => {
2056
2104
  if (stage.id !== "execute_llm") {
2057
2105
  return;
2058
2106
  }
2059
- const normalized = readNonEmptyString(ctx.cloudQuotaFallbackAppliedModelId);
2107
+ const normalized = readNonEmptyString2(ctx.cloudQuotaFallbackAppliedModelId);
2060
2108
  if (!normalized) {
2061
2109
  return;
2062
2110
  }
@@ -2644,7 +2692,7 @@ function createExecuteLlmStage(dependencies) {
2644
2692
  streamEventHandler,
2645
2693
  ctx.signal,
2646
2694
  (fallbackModelId) => {
2647
- ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString(fallbackModelId);
2695
+ ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString2(fallbackModelId);
2648
2696
  },
2649
2697
  (info) => {
2650
2698
  ctx.modelFallbackAudit = info;
@@ -2688,7 +2736,7 @@ function createPrepareCallStage(dependencies) {
2688
2736
  return {
2689
2737
  id: "prepare_call",
2690
2738
  async run(ctx) {
2691
- const lockedRunModelId = readNonEmptyString(ctx.executorLocal?.runLockedModelId);
2739
+ const lockedRunModelId = readNonEmptyString2(ctx.executorLocal?.runLockedModelId);
2692
2740
  const requestedModelId = lockedRunModelId ?? ctx.request.model_id;
2693
2741
  ctx.modelId = dependencies.modelResolver.resolveModelId(requestedModelId);
2694
2742
  await emitAuditEnvelope(ctx.audit, {
@@ -2760,7 +2808,7 @@ var GraphAgentExecutor = class {
2760
2808
  this.llmCaller = dependencies.llmCaller;
2761
2809
  this.toolRuntime = dependencies.toolRuntime;
2762
2810
  this.contextBuilder = dependencies.contextBuilder;
2763
- this.cloudQuotaFallbackModelId = readNonEmptyString(dependencies.cloudQuotaFallbackModelId);
2811
+ this.cloudQuotaFallbackModelId = readNonEmptyString2(dependencies.cloudQuotaFallbackModelId);
2764
2812
  this.modelCatalog = dependencies.modelCatalog ?? createEmptyModelCatalog();
2765
2813
  this.modelResolver = dependencies.modelResolver ?? new ModelResolver({
2766
2814
  modelCatalog: this.modelCatalog
@@ -2808,7 +2856,7 @@ var GraphAgentExecutor = class {
2808
2856
  llmMessages: [],
2809
2857
  mode: input.request.mode === "chat" ? "chat" : "agent",
2810
2858
  conversationId: resolveConversationIdForRuntimeEvents(input.toolContext),
2811
- turnId: readNonEmptyString(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
2859
+ turnId: readNonEmptyString2(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
2812
2860
  telemetry: this.telemetryPort,
2813
2861
  audit: this.auditPort
2814
2862
  };
@@ -2858,18 +2906,18 @@ function isSummarizationCallbacks(value) {
2858
2906
  function isGraphSseSink(value) {
2859
2907
  return typeof value === "function";
2860
2908
  }
2861
- function readNonEmptyString2(value) {
2909
+ function readNonEmptyString3(value) {
2862
2910
  if (typeof value !== "string") return void 0;
2863
2911
  const trimmed = value.trim();
2864
2912
  return trimmed.length > 0 ? trimmed : void 0;
2865
2913
  }
2866
2914
  function readGraphAgentLocal(local) {
2867
2915
  const source = local ?? {};
2868
- const answerId = readNonEmptyString2(source.answerId);
2916
+ const answerId = readNonEmptyString3(source.answerId);
2869
2917
  const chunkSeq = Number.isInteger(source.chunkSeq) ? Number(source.chunkSeq) : 0;
2870
2918
  return {
2871
- conversationId: readNonEmptyString2(source.conversationId) ?? "",
2872
- turnId: readNonEmptyString2(source.turnId),
2919
+ conversationId: readNonEmptyString3(source.conversationId) ?? "",
2920
+ turnId: readNonEmptyString3(source.turnId),
2873
2921
  request: isAgentInvocationRequest(source.request) ? source.request : void 0,
2874
2922
  toolContext: isToolExecutionContext(source.toolContext) ? source.toolContext : void 0,
2875
2923
  history: isRuntimeEventArray(source.history) ? source.history : [],
@@ -3634,7 +3682,7 @@ var LlmNode = class {
3634
3682
  function isRecord8(value) {
3635
3683
  return typeof value === "object" && value !== null && !Array.isArray(value);
3636
3684
  }
3637
- function readNonEmptyString3(value) {
3685
+ function readNonEmptyString4(value) {
3638
3686
  if (typeof value !== "string") {
3639
3687
  return void 0;
3640
3688
  }
@@ -3656,7 +3704,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3656
3704
  return void 0;
3657
3705
  }
3658
3706
  if (toolName === "write_report") {
3659
- const report = readNonEmptyString3(data.report);
3707
+ const report = readNonEmptyString4(data.report);
3660
3708
  if (!report) {
3661
3709
  throw new Error("[write_report] \u5DE5\u5177\u8F93\u51FA\u7F3A\u5C11 data.report\uFF08\u5FC5\u987B\u63D0\u4F9B\u5B8C\u6574\u62A5\u544A\u6B63\u6587\uFF09");
3662
3710
  }
@@ -3666,7 +3714,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3666
3714
  if (data.success !== true) {
3667
3715
  return void 0;
3668
3716
  }
3669
- const finalAnswer = readNonEmptyString3(data.final_answer);
3717
+ const finalAnswer = readNonEmptyString4(data.final_answer);
3670
3718
  if (!finalAnswer) {
3671
3719
  throw new Error("[research_run_writer] \u5DE5\u5177\u8F93\u51FA\u7F3A\u5C11 data.final_answer\uFF08success=true \u65F6\u5FC5\u987B\u63D0\u4F9B\u6700\u7EC8\u62A5\u544A\u6B63\u6587\uFF09");
3672
3720
  }
@@ -5000,12 +5048,12 @@ function asRecord(value) {
5000
5048
  }
5001
5049
  return value;
5002
5050
  }
5003
- function summarizeCheckpoint(conversationId, state, savedAt) {
5051
+ function summarizeCheckpoint(checkpointKey, state, savedAt) {
5004
5052
  const local = asRecord(state.local);
5005
5053
  const executorLocal = asRecord(local?.executorLocal);
5006
5054
  const pendingToolCalls = local?.pendingToolCalls;
5007
5055
  return {
5008
- conversationId,
5056
+ checkpointKey,
5009
5057
  schemaVersion: state.schemaVersion ?? 1,
5010
5058
  savedAt,
5011
5059
  currentNode: state.nodeId,
@@ -5024,25 +5072,25 @@ var MemoryCheckpointer = class {
5024
5072
  local: state.local && typeof state.local === "object" && !Array.isArray(state.local) ? { ...state.local } : state.local
5025
5073
  };
5026
5074
  }
5027
- async load(conversationId) {
5028
- const entry = this.store.get(conversationId);
5075
+ async load(checkpointKey) {
5076
+ const entry = this.store.get(checkpointKey);
5029
5077
  return entry ? this.cloneState(entry.state) : null;
5030
5078
  }
5031
- async save(conversationId, state) {
5032
- this.store.set(conversationId, {
5079
+ async save(checkpointKey, state) {
5080
+ this.store.set(checkpointKey, {
5033
5081
  state: this.cloneState(state),
5034
5082
  savedAt: Date.now()
5035
5083
  });
5036
5084
  }
5037
- async clear(conversationId) {
5038
- this.store.delete(conversationId);
5085
+ async clear(checkpointKey) {
5086
+ this.store.delete(checkpointKey);
5039
5087
  }
5040
- async peekMeta(conversationId) {
5041
- const entry = this.store.get(conversationId);
5042
- return entry ? summarizeCheckpoint(conversationId, entry.state, entry.savedAt) : null;
5088
+ async peekMeta(checkpointKey) {
5089
+ const entry = this.store.get(checkpointKey);
5090
+ return entry ? summarizeCheckpoint(checkpointKey, entry.state, entry.savedAt) : null;
5043
5091
  }
5044
5092
  async list(filter = {}) {
5045
- const summaries = Array.from(this.store.entries()).map(([conversationId, entry]) => summarizeCheckpoint(conversationId, entry.state, entry.savedAt)).filter((summary) => filter.savedAfter === void 0 ? true : summary.savedAt > filter.savedAfter).sort((left, right) => right.savedAt - left.savedAt);
5093
+ const summaries = Array.from(this.store.entries()).map(([checkpointKey, entry]) => summarizeCheckpoint(checkpointKey, entry.state, entry.savedAt)).filter((summary) => filter.savedAfter === void 0 ? true : summary.savedAt > filter.savedAfter).sort((left, right) => right.savedAt - left.savedAt);
5046
5094
  if (filter.limit === void 0) {
5047
5095
  return summaries;
5048
5096
  }
@@ -6582,7 +6630,7 @@ function cloneRunRecord(record) {
6582
6630
  ...record,
6583
6631
  iterationBudget: record.iterationBudget ? { ...record.iterationBudget } : void 0,
6584
6632
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0,
6585
- metadata: record.metadata ? { ...record.metadata } : void 0
6633
+ metadata: record.metadata ? structuredClone(record.metadata) : void 0
6586
6634
  };
6587
6635
  }
6588
6636
  function matchesStatus(candidate, filter) {
@@ -6994,7 +7042,7 @@ function isTerminalStatus(status) {
6994
7042
  return status === "completed" || status === "failed" || status === "cancelled";
6995
7043
  }
6996
7044
  function cloneMetadata(metadata) {
6997
- return metadata ? { ...metadata } : void 0;
7045
+ return metadata ? structuredClone(metadata) : void 0;
6998
7046
  }
6999
7047
  function recordToSnapshot(record) {
7000
7048
  return {
@@ -7081,7 +7129,7 @@ var DefaultRunSupervisor = class {
7081
7129
  startedAt,
7082
7130
  updatedAt: startedAt,
7083
7131
  iterationBudget: spec.iterationBudget ? { ...spec.iterationBudget } : void 0,
7084
- metadata: spec.metadata ? { ...spec.metadata } : void 0
7132
+ metadata: cloneMetadata(spec.metadata)
7085
7133
  };
7086
7134
  await this.registryStore.save(record);
7087
7135
  const handle = new DefaultRunHandle({
@@ -7255,12 +7303,13 @@ var DefaultRunSupervisor = class {
7255
7303
  }
7256
7304
  try {
7257
7305
  await handle.markRunning({ currentNode: "detached" });
7306
+ const registeredRecord = await this.registryStore.load(handle.runId);
7258
7307
  const executorOutcome = await this.executor.execute({
7259
7308
  runId: handle.runId,
7260
- parentRunId: spec.parentRunId,
7261
- conversationId: spec.conversationId,
7262
- agentSpec: spec.agentSpec,
7263
- request: spec.request,
7309
+ parentRunId: handle.parentRunId,
7310
+ conversationId: registeredRecord?.conversationId ?? spec.conversationId,
7311
+ agentSpec: await handle.spec(),
7312
+ request: await handle.request(),
7264
7313
  signal: handle.signal,
7265
7314
  eventBus: spec.eventBus,
7266
7315
  eventStore: spec.eventStore,
@@ -7269,7 +7318,7 @@ var DefaultRunSupervisor = class {
7269
7318
  contextFences: spec.contextFences,
7270
7319
  wakeSource: spec.wakeSource,
7271
7320
  ephemeral: spec.ephemeral,
7272
- metadata: spec.metadata
7321
+ metadata: cloneMetadata(registeredRecord?.metadata ?? spec.metadata)
7273
7322
  });
7274
7323
  const outcome = await this.persistExecutorOutcome(handle, executorOutcome);
7275
7324
  this.notifyTerminalWaiters(outcome);
@@ -7333,10 +7382,14 @@ var DefaultRunSupervisor = class {
7333
7382
  await this.registryStore.save(record);
7334
7383
  }
7335
7384
  const completedAt = executorOutcome?.completedAt ?? this.now();
7385
+ const fallbackMeta = record ? void 0 : await handle.meta();
7336
7386
  const outcome = recordToTerminalOutcome(record ?? {
7337
7387
  runId: handle.runId,
7338
7388
  parentRunId: handle.parentRunId,
7339
- status: executorOutcome?.status ?? "completed"}, completedAt);
7389
+ conversationId: fallbackMeta?.conversationId ?? "",
7390
+ agentSpecId: fallbackMeta?.agentSpecId,
7391
+ status: executorOutcome?.status ?? "completed",
7392
+ startedAt: fallbackMeta?.startedAt ?? completedAt}, completedAt);
7340
7393
  const nextOutcome = {
7341
7394
  ...outcome,
7342
7395
  metadata: {
@@ -7664,6 +7717,7 @@ async function emitRunEvent(event, sink) {
7664
7717
  async function runAgent(agent, options) {
7665
7718
  const modelId = resolveModelId(agent, options);
7666
7719
  const conversationId = options.conversationId ?? `conv_${Date.now()}`;
7720
+ const checkpointKey = conversationId;
7667
7721
  const runId = options.runId ?? generateRunId();
7668
7722
  const turnId = runId;
7669
7723
  const costCollector = new QuickstartRunCostCollector();
@@ -7718,7 +7772,7 @@ async function runAgent(agent, options) {
7718
7772
  };
7719
7773
  await handle.markRunning({ currentNode: "user" });
7720
7774
  try {
7721
- await executor.prime(conversationId, {
7775
+ await executor.prime(checkpointKey, {
7722
7776
  conversationId,
7723
7777
  turnId,
7724
7778
  request: {
@@ -7743,7 +7797,7 @@ async function runAgent(agent, options) {
7743
7797
  return void 0;
7744
7798
  }
7745
7799
  });
7746
- const result = await executor.runUntilYield(conversationId);
7800
+ const result = await executor.runUntilYield(checkpointKey);
7747
7801
  runtimeEvents.push(...result.events);
7748
7802
  for (const event of result.events) {
7749
7803
  if (event.type === "final_answer_chunk") continue;