@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
package/dist/testkit.cjs CHANGED
@@ -118,6 +118,7 @@ __export(runtime_kernel_exports, {
118
118
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
119
119
  consoleAudit: () => consoleAudit,
120
120
  contextBudgetWarningTemplate: () => contextBudgetWarningTemplate,
121
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
121
122
  countToolCallsInCurrentRequest: () => countToolCallsInCurrentRequest,
122
123
  createCompositeAudit: () => createCompositeAudit,
123
124
  createConsoleAudit: () => createConsoleAudit,
@@ -199,6 +200,7 @@ var Logger = class {
199
200
  constructor(moduleName) {
200
201
  this.moduleName = moduleName;
201
202
  }
203
+ moduleName;
202
204
  debug(message, data) {
203
205
  this.log(0 /* DEBUG */, "debug", message, data);
204
206
  }
@@ -421,6 +423,7 @@ var AgentSpecBudgetPolicy = zod.z.object({
421
423
  });
422
424
  var AgentSpecToolHistoryPolicy = zod.z.object({
423
425
  strategy: zod.z.enum(["per-pair", "per-run", "none"]).optional(),
426
+ retentionMode: zod.z.enum(["drop", "compress"]).optional(),
424
427
  keepLatestToolPairs: zod.z.number().int().nonnegative().optional(),
425
428
  keepLatestRuns: zod.z.number().int().nonnegative().optional(),
426
429
  maxInteractionGroups: zod.z.number().int().nonnegative().optional(),
@@ -1177,6 +1180,17 @@ var logger = new Logger("GraphExecutor");
1177
1180
  function asLocalRecord(local) {
1178
1181
  return local && typeof local === "object" ? { ...local } : {};
1179
1182
  }
1183
+ function readNonEmptyString(value) {
1184
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1185
+ }
1186
+ function readRuntimeConversationId(state) {
1187
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1188
+ return readNonEmptyString(local?.conversationId);
1189
+ }
1190
+ function readRuntimeTurnId(state) {
1191
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1192
+ return readNonEmptyString(local?.turnId);
1193
+ }
1180
1194
  var GraphExecutor = class {
1181
1195
  constructor(checkpointer, config = {}) {
1182
1196
  this.checkpointer = checkpointer;
@@ -1186,6 +1200,7 @@ var GraphExecutor = class {
1186
1200
  };
1187
1201
  this.telemetryPort = config.telemetryPort ?? noopTelemetry;
1188
1202
  }
1203
+ checkpointer;
1189
1204
  nodes = /* @__PURE__ */ new Map();
1190
1205
  ephemeralLocals = /* @__PURE__ */ new Map();
1191
1206
  config;
@@ -1193,8 +1208,8 @@ var GraphExecutor = class {
1193
1208
  registerNode(node) {
1194
1209
  this.nodes.set(node.id, node);
1195
1210
  }
1196
- async peekCheckpoint(conversationId) {
1197
- return await this.checkpointer.load(conversationId);
1211
+ async peekCheckpoint(checkpointKey) {
1212
+ return await this.checkpointer.load(checkpointKey);
1198
1213
  }
1199
1214
  sanitize(state) {
1200
1215
  const local = asLocalRecord(state.local);
@@ -1206,8 +1221,8 @@ var GraphExecutor = class {
1206
1221
  local
1207
1222
  };
1208
1223
  }
1209
- async prime(conversationId, local, nodeId = "user") {
1210
- this.ephemeralLocals.set(conversationId, { ...local || {} });
1224
+ async prime(checkpointKey, local, nodeId = "user") {
1225
+ this.ephemeralLocals.set(checkpointKey, { ...local || {} });
1211
1226
  const localSansMemory = { ...local || {} };
1212
1227
  if ("memory" in localSansMemory) delete localSansMemory.memory;
1213
1228
  const state = {
@@ -1215,10 +1230,10 @@ var GraphExecutor = class {
1215
1230
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1216
1231
  local: localSansMemory
1217
1232
  };
1218
- await this.checkpointer.save(conversationId, state);
1233
+ await this.checkpointer.save(checkpointKey, state);
1219
1234
  }
1220
- async setNode(conversationId, nodeId, localPatch) {
1221
- const current = await this.checkpointer.load(conversationId) || {
1235
+ async setNode(checkpointKey, nodeId, localPatch) {
1236
+ const current = await this.checkpointer.load(checkpointKey) || {
1222
1237
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1223
1238
  local: {}
1224
1239
  };
@@ -1229,19 +1244,46 @@ var GraphExecutor = class {
1229
1244
  schemaVersion: current.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
1230
1245
  local: mergedLocal
1231
1246
  };
1232
- await this.checkpointer.save(conversationId, next);
1247
+ await this.checkpointer.save(checkpointKey, next);
1233
1248
  }
1234
- async runUntilYield(conversationId) {
1249
+ async runUntilYield(checkpointKey) {
1235
1250
  const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1236
1251
  let lifecyclePhase = "completed";
1252
+ let initialState = null;
1253
+ try {
1254
+ initialState = await this.loadInitialState(checkpointKey);
1255
+ } catch (err) {
1256
+ lifecyclePhase = "failed";
1257
+ this.telemetryPort.emit({
1258
+ kind: "run_lifecycle",
1259
+ runId,
1260
+ phase: "spawned",
1261
+ scope: {}
1262
+ });
1263
+ this.telemetryPort.emit({
1264
+ kind: "run_lifecycle",
1265
+ runId,
1266
+ phase: lifecyclePhase,
1267
+ scope: {}
1268
+ });
1269
+ throw err;
1270
+ }
1271
+ let lifecycleConversationId = readRuntimeConversationId(initialState);
1272
+ let lifecycleTurnId = readRuntimeTurnId(initialState);
1237
1273
  this.telemetryPort.emit({
1238
1274
  kind: "run_lifecycle",
1239
1275
  runId,
1240
1276
  phase: "spawned",
1241
- scope: { conversationId: conversationId || void 0 }
1277
+ scope: {
1278
+ conversationId: lifecycleConversationId,
1279
+ turnId: lifecycleTurnId
1280
+ }
1242
1281
  });
1243
1282
  try {
1244
- return await this.runUntilYieldInternal(conversationId);
1283
+ const result = await this.runUntilYieldInternal(checkpointKey, initialState);
1284
+ lifecycleConversationId = readRuntimeConversationId(result.checkpoint);
1285
+ lifecycleTurnId = readRuntimeTurnId(result.checkpoint);
1286
+ return result;
1245
1287
  } catch (err) {
1246
1288
  lifecyclePhase = err?.name === "AbortError" ? "cancelled" : "failed";
1247
1289
  throw err;
@@ -1250,17 +1292,23 @@ var GraphExecutor = class {
1250
1292
  kind: "run_lifecycle",
1251
1293
  runId,
1252
1294
  phase: lifecyclePhase,
1253
- scope: { conversationId: conversationId || void 0 }
1295
+ scope: {
1296
+ conversationId: lifecycleConversationId,
1297
+ turnId: lifecycleTurnId
1298
+ }
1254
1299
  });
1255
1300
  }
1256
1301
  }
1257
- async runUntilYieldInternal(conversationId) {
1258
- let state = await this.checkpointer.load(conversationId) || {
1302
+ async loadInitialState(checkpointKey) {
1303
+ return await this.checkpointer.load(checkpointKey) || {
1259
1304
  nodeId: "user",
1260
1305
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1261
1306
  local: {}
1262
1307
  };
1263
- const ephemeral = this.ephemeralLocals.get(conversationId) || {};
1308
+ }
1309
+ async runUntilYieldInternal(checkpointKey, initialState) {
1310
+ let state = initialState;
1311
+ const ephemeral = this.ephemeralLocals.get(checkpointKey) || {};
1264
1312
  state = {
1265
1313
  ...state,
1266
1314
  schemaVersion: state.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
@@ -1289,7 +1337,7 @@ var GraphExecutor = class {
1289
1337
  const signalRaw = state.local?.signal;
1290
1338
  if (isAbortSignal2(signalRaw) && signalRaw.aborted) {
1291
1339
  logger.warn("[GraphExecutor] \u6536\u5230 AbortSignal\uFF0C\u7ACB\u5373\u505C\u6B62\u63A8\u7406\u5FAA\u73AF");
1292
- this.ephemeralLocals.delete(conversationId);
1340
+ this.ephemeralLocals.delete(checkpointKey);
1293
1341
  throwAbortError();
1294
1342
  }
1295
1343
  const isLastStep = cycleStepCount >= this.config.maxSteps;
@@ -1337,8 +1385,8 @@ var GraphExecutor = class {
1337
1385
  checkpointCount
1338
1386
  });
1339
1387
  const cp2 = this.sanitize(state);
1340
- await this.checkpointer.save(conversationId, cp2);
1341
- this.ephemeralLocals.delete(conversationId);
1388
+ await this.checkpointer.save(checkpointKey, cp2);
1389
+ this.ephemeralLocals.delete(checkpointKey);
1342
1390
  return { events: allEvents, checkpoint: cp2, stepCount };
1343
1391
  }
1344
1392
  logger.info("[GraphExecutor] \u8282\u70B9\u5207\u6362", {
@@ -1349,18 +1397,18 @@ var GraphExecutor = class {
1349
1397
  });
1350
1398
  const nodeRunStartedAt = Date.now();
1351
1399
  const nodeIdForTelemetry = state.nodeId;
1400
+ const conversationIdForTelemetry = readRuntimeConversationId(state);
1352
1401
  let result;
1353
1402
  try {
1354
1403
  result = await node.run(state);
1355
1404
  } finally {
1356
- const turnIdForTelemetry = typeof state.local?.turnId === "string" ? state.local.turnId : void 0;
1357
1405
  this.telemetryPort.emit({
1358
1406
  kind: "graph_node",
1359
1407
  nodeId: nodeIdForTelemetry,
1360
1408
  durationMs: Date.now() - nodeRunStartedAt,
1361
1409
  scope: {
1362
- conversationId: conversationId || void 0,
1363
- turnId: turnIdForTelemetry
1410
+ conversationId: conversationIdForTelemetry,
1411
+ turnId: readRuntimeTurnId(state)
1364
1412
  }
1365
1413
  });
1366
1414
  }
@@ -1399,7 +1447,7 @@ var GraphExecutor = class {
1399
1447
  });
1400
1448
  state = { ...state, nodeId: nextNodeId };
1401
1449
  const cp2 = this.sanitize(state);
1402
- await this.checkpointer.save(conversationId, cp2);
1450
+ await this.checkpointer.save(checkpointKey, cp2);
1403
1451
  continue;
1404
1452
  }
1405
1453
  if (result.kind === "yield") {
@@ -1410,7 +1458,7 @@ var GraphExecutor = class {
1410
1458
  checkpointCount
1411
1459
  });
1412
1460
  const cp2 = this.sanitize(state);
1413
- await this.checkpointer.save(conversationId, cp2);
1461
+ await this.checkpointer.save(checkpointKey, cp2);
1414
1462
  return { events: allEvents, checkpoint: cp2, stepCount };
1415
1463
  }
1416
1464
  if (result.kind === "pause") {
@@ -1421,7 +1469,7 @@ var GraphExecutor = class {
1421
1469
  checkpointCount
1422
1470
  });
1423
1471
  const cp2 = this.sanitize(state);
1424
- await this.checkpointer.save(conversationId, cp2);
1472
+ await this.checkpointer.save(checkpointKey, cp2);
1425
1473
  return { events: allEvents, checkpoint: cp2, stepCount };
1426
1474
  }
1427
1475
  }
@@ -1432,8 +1480,8 @@ var GraphExecutor = class {
1432
1480
  checkpointCount
1433
1481
  });
1434
1482
  const cp = this.sanitize(state);
1435
- await this.checkpointer.save(conversationId, cp);
1436
- this.ephemeralLocals.delete(conversationId);
1483
+ await this.checkpointer.save(checkpointKey, cp);
1484
+ this.ephemeralLocals.delete(checkpointKey);
1437
1485
  return { events: allEvents, checkpoint: cp, stepCount };
1438
1486
  }
1439
1487
  };
@@ -1630,15 +1678,15 @@ function splitConcatenatedJsonObjects(input) {
1630
1678
  }
1631
1679
 
1632
1680
  // src/runtime-kernel/graph-engine/tick-pipeline/helpers.ts
1633
- function readNonEmptyString(value) {
1681
+ function readNonEmptyString2(value) {
1634
1682
  if (typeof value !== "string") return void 0;
1635
1683
  const trimmed = value.trim();
1636
1684
  return trimmed.length > 0 ? trimmed : void 0;
1637
1685
  }
1638
1686
  function resolveConversationIdForRuntimeEvents(toolContext) {
1639
- const fromCamel = readNonEmptyString(toolContext?.conversationId);
1687
+ const fromCamel = readNonEmptyString2(toolContext?.conversationId);
1640
1688
  if (fromCamel) return fromCamel;
1641
- const fromSnake = toolContext ? readNonEmptyString(toolContext["conversation_id"]) : void 0;
1689
+ const fromSnake = toolContext ? readNonEmptyString2(toolContext["conversation_id"]) : void 0;
1642
1690
  if (fromSnake) return fromSnake;
1643
1691
  return generateMessageId();
1644
1692
  }
@@ -1997,7 +2045,7 @@ var runModelLockMiddleware = async (ctx, stage, next) => {
1997
2045
  if (stage.id !== "execute_llm") {
1998
2046
  return;
1999
2047
  }
2000
- const normalized = readNonEmptyString(ctx.cloudQuotaFallbackAppliedModelId);
2048
+ const normalized = readNonEmptyString2(ctx.cloudQuotaFallbackAppliedModelId);
2001
2049
  if (!normalized) {
2002
2050
  return;
2003
2051
  }
@@ -2598,7 +2646,7 @@ function createExecuteLlmStage(dependencies) {
2598
2646
  streamEventHandler,
2599
2647
  ctx.signal,
2600
2648
  (fallbackModelId) => {
2601
- ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString(fallbackModelId);
2649
+ ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString2(fallbackModelId);
2602
2650
  },
2603
2651
  (info) => {
2604
2652
  ctx.modelFallbackAudit = info;
@@ -2642,7 +2690,7 @@ function createPrepareCallStage(dependencies) {
2642
2690
  return {
2643
2691
  id: "prepare_call",
2644
2692
  async run(ctx) {
2645
- const lockedRunModelId = readNonEmptyString(ctx.executorLocal?.runLockedModelId);
2693
+ const lockedRunModelId = readNonEmptyString2(ctx.executorLocal?.runLockedModelId);
2646
2694
  const requestedModelId = lockedRunModelId ?? ctx.request.model_id;
2647
2695
  ctx.modelId = dependencies.modelResolver.resolveModelId(requestedModelId);
2648
2696
  await emitAuditEnvelope(ctx.audit, {
@@ -2714,7 +2762,7 @@ var GraphAgentExecutor = class {
2714
2762
  this.llmCaller = dependencies.llmCaller;
2715
2763
  this.toolRuntime = dependencies.toolRuntime;
2716
2764
  this.contextBuilder = dependencies.contextBuilder;
2717
- this.cloudQuotaFallbackModelId = readNonEmptyString(dependencies.cloudQuotaFallbackModelId);
2765
+ this.cloudQuotaFallbackModelId = readNonEmptyString2(dependencies.cloudQuotaFallbackModelId);
2718
2766
  this.modelCatalog = dependencies.modelCatalog ?? createEmptyModelCatalog();
2719
2767
  this.modelResolver = dependencies.modelResolver ?? new ModelResolver({
2720
2768
  modelCatalog: this.modelCatalog
@@ -2762,7 +2810,7 @@ var GraphAgentExecutor = class {
2762
2810
  llmMessages: [],
2763
2811
  mode: input.request.mode === "chat" ? "chat" : "agent",
2764
2812
  conversationId: resolveConversationIdForRuntimeEvents(input.toolContext),
2765
- turnId: readNonEmptyString(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
2813
+ turnId: readNonEmptyString2(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
2766
2814
  telemetry: this.telemetryPort,
2767
2815
  audit: this.auditPort
2768
2816
  };
@@ -2812,18 +2860,18 @@ function isSummarizationCallbacks(value) {
2812
2860
  function isGraphSseSink(value) {
2813
2861
  return typeof value === "function";
2814
2862
  }
2815
- function readNonEmptyString2(value) {
2863
+ function readNonEmptyString3(value) {
2816
2864
  if (typeof value !== "string") return void 0;
2817
2865
  const trimmed = value.trim();
2818
2866
  return trimmed.length > 0 ? trimmed : void 0;
2819
2867
  }
2820
2868
  function readGraphAgentLocal(local) {
2821
2869
  const source = local ?? {};
2822
- const answerId = readNonEmptyString2(source.answerId);
2870
+ const answerId = readNonEmptyString3(source.answerId);
2823
2871
  const chunkSeq = Number.isInteger(source.chunkSeq) ? Number(source.chunkSeq) : 0;
2824
2872
  return {
2825
- conversationId: readNonEmptyString2(source.conversationId) ?? "",
2826
- turnId: readNonEmptyString2(source.turnId),
2873
+ conversationId: readNonEmptyString3(source.conversationId) ?? "",
2874
+ turnId: readNonEmptyString3(source.turnId),
2827
2875
  request: isAgentInvocationRequest(source.request) ? source.request : void 0,
2828
2876
  toolContext: isToolExecutionContext(source.toolContext) ? source.toolContext : void 0,
2829
2877
  history: isRuntimeEventArray(source.history) ? source.history : [],
@@ -3588,7 +3636,7 @@ var LlmNode = class {
3588
3636
  function isRecord8(value) {
3589
3637
  return typeof value === "object" && value !== null && !Array.isArray(value);
3590
3638
  }
3591
- function readNonEmptyString3(value) {
3639
+ function readNonEmptyString4(value) {
3592
3640
  if (typeof value !== "string") {
3593
3641
  return void 0;
3594
3642
  }
@@ -3610,7 +3658,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3610
3658
  return void 0;
3611
3659
  }
3612
3660
  if (toolName === "write_report") {
3613
- const report = readNonEmptyString3(data.report);
3661
+ const report = readNonEmptyString4(data.report);
3614
3662
  if (!report) {
3615
3663
  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");
3616
3664
  }
@@ -3620,7 +3668,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3620
3668
  if (data.success !== true) {
3621
3669
  return void 0;
3622
3670
  }
3623
- const finalAnswer = readNonEmptyString3(data.final_answer);
3671
+ const finalAnswer = readNonEmptyString4(data.final_answer);
3624
3672
  if (!finalAnswer) {
3625
3673
  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");
3626
3674
  }
@@ -4165,6 +4213,31 @@ function ensureToolContextRuntimeCapability(params) {
4165
4213
  function getToolContextRuntimeBinding(context) {
4166
4214
  return readBinding(context);
4167
4215
  }
4216
+ function copyToolContextRuntimeCapability(source, target) {
4217
+ const sourceBinding = readBinding(source);
4218
+ if (!sourceBinding) {
4219
+ return void 0;
4220
+ }
4221
+ const existingTargetBinding = readBinding(target);
4222
+ if (existingTargetBinding) {
4223
+ exposeCompatibilitySurface(target, existingTargetBinding);
4224
+ return existingTargetBinding;
4225
+ }
4226
+ const targetBinding = createRuntimeBinding({
4227
+ context: target,
4228
+ persistedHistory: () => sourceBinding.getPersistedHistoryEvents(),
4229
+ workingHistory: () => sourceBinding.getWorkingHistoryEvents(),
4230
+ executionMeta: sourceBinding.readExecutionMeta()
4231
+ });
4232
+ Object.defineProperty(target, TOOL_CONTEXT_RUNTIME_BINDING_KEY, {
4233
+ value: targetBinding,
4234
+ enumerable: false,
4235
+ configurable: true,
4236
+ writable: false
4237
+ });
4238
+ exposeCompatibilitySurface(target, targetBinding);
4239
+ return targetBinding;
4240
+ }
4168
4241
  function readToolContextWorkingHistory(context) {
4169
4242
  if (context.conversationView) {
4170
4243
  return context.conversationView.getWorkingHistoryEvents();
@@ -5016,12 +5089,12 @@ function asRecord(value) {
5016
5089
  }
5017
5090
  return value;
5018
5091
  }
5019
- function summarizeCheckpoint(conversationId, state, savedAt) {
5092
+ function summarizeCheckpoint(checkpointKey, state, savedAt) {
5020
5093
  const local = asRecord(state.local);
5021
5094
  const executorLocal = asRecord(local?.executorLocal);
5022
5095
  const pendingToolCalls = local?.pendingToolCalls;
5023
5096
  return {
5024
- conversationId,
5097
+ checkpointKey,
5025
5098
  schemaVersion: state.schemaVersion ?? 1,
5026
5099
  savedAt,
5027
5100
  currentNode: state.nodeId,
@@ -5040,25 +5113,25 @@ var MemoryCheckpointer = class {
5040
5113
  local: state.local && typeof state.local === "object" && !Array.isArray(state.local) ? { ...state.local } : state.local
5041
5114
  };
5042
5115
  }
5043
- async load(conversationId) {
5044
- const entry = this.store.get(conversationId);
5116
+ async load(checkpointKey) {
5117
+ const entry = this.store.get(checkpointKey);
5045
5118
  return entry ? this.cloneState(entry.state) : null;
5046
5119
  }
5047
- async save(conversationId, state) {
5048
- this.store.set(conversationId, {
5120
+ async save(checkpointKey, state) {
5121
+ this.store.set(checkpointKey, {
5049
5122
  state: this.cloneState(state),
5050
5123
  savedAt: Date.now()
5051
5124
  });
5052
5125
  }
5053
- async clear(conversationId) {
5054
- this.store.delete(conversationId);
5126
+ async clear(checkpointKey) {
5127
+ this.store.delete(checkpointKey);
5055
5128
  }
5056
- async peekMeta(conversationId) {
5057
- const entry = this.store.get(conversationId);
5058
- return entry ? summarizeCheckpoint(conversationId, entry.state, entry.savedAt) : null;
5129
+ async peekMeta(checkpointKey) {
5130
+ const entry = this.store.get(checkpointKey);
5131
+ return entry ? summarizeCheckpoint(checkpointKey, entry.state, entry.savedAt) : null;
5059
5132
  }
5060
5133
  async list(filter = {}) {
5061
- 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);
5134
+ 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);
5062
5135
  if (filter.limit === void 0) {
5063
5136
  return summaries;
5064
5137
  }
@@ -5130,6 +5203,7 @@ __export(tools_exports, {
5130
5203
  CommonParameterTypes: () => CommonParameterTypes,
5131
5204
  ContextCheckpointTool: () => ContextCheckpointTool,
5132
5205
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
5206
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
5133
5207
  createContextCheckpointTool: () => createContextCheckpointTool,
5134
5208
  ensureToolContextRuntimeCapability: () => ensureToolContextRuntimeCapability,
5135
5209
  findCachedToolOutputByIdempotencyKey: () => findCachedToolOutputByIdempotencyKey,
@@ -5323,7 +5397,7 @@ function createContextCheckpointTool(options) {
5323
5397
  function isRecord15(value) {
5324
5398
  return !!value && typeof value === "object" && !Array.isArray(value);
5325
5399
  }
5326
- function readNonEmptyString4(value) {
5400
+ function readNonEmptyString5(value) {
5327
5401
  if (typeof value !== "string") {
5328
5402
  return void 0;
5329
5403
  }
@@ -5343,13 +5417,13 @@ function readToolContextUserQuery(context) {
5343
5417
  if (!context) {
5344
5418
  return void 0;
5345
5419
  }
5346
- return readNonEmptyString4(context["user_query"]);
5420
+ return readNonEmptyString5(context["user_query"]);
5347
5421
  }
5348
5422
  function readToolContextModelId(context) {
5349
5423
  if (!context) {
5350
5424
  return void 0;
5351
5425
  }
5352
- return readNonEmptyString4(context["modelId"]);
5426
+ return readNonEmptyString5(context["modelId"]);
5353
5427
  }
5354
5428
  function readToolContextRunContext(context) {
5355
5429
  if (!context) {
@@ -7057,6 +7131,7 @@ var DefaultTokenizerPort = class {
7057
7131
  constructor(config = {}) {
7058
7132
  this.config = config;
7059
7133
  }
7134
+ config;
7060
7135
  estimateText(text, _modelId) {
7061
7136
  return TokenCalculator.estimateTokens(text, {
7062
7137
  encoding: this.config.encoding,
@@ -7084,7 +7159,6 @@ __export(child_runs_exports, {
7084
7159
 
7085
7160
  // src/runtime-kernel/child-runs/childToolContext.ts
7086
7161
  function createChildRunToolContext(params) {
7087
- const inheritedConversationId = typeof params.parentToolContext.conversationId === "string" && params.parentToolContext.conversationId.trim().length > 0 ? params.parentToolContext.conversationId.trim() : void 0;
7088
7162
  const inheritedContext = stripRuntimeReservedToolContextPatch(params.parentToolContext);
7089
7163
  const childToolContext = {
7090
7164
  ...inheritedContext,
@@ -7096,7 +7170,7 @@ function createChildRunToolContext(params) {
7096
7170
  persistedHistory: params.seedHistory,
7097
7171
  workingHistory: params.seedHistory,
7098
7172
  executionMeta: {
7099
- conversationId: inheritedConversationId ?? params.internalConversationId,
7173
+ conversationId: params.conversationId,
7100
7174
  turnId: params.turnId,
7101
7175
  runId: params.runId,
7102
7176
  parentRunId: params.parentRunId
@@ -7198,6 +7272,8 @@ var FinalAnswerCollector = class {
7198
7272
  this.conversationId = conversationId;
7199
7273
  this.turnId = turnId;
7200
7274
  }
7275
+ conversationId;
7276
+ turnId;
7201
7277
  answerId;
7202
7278
  chunks = [];
7203
7279
  chunkCount = 0;
@@ -7414,7 +7490,7 @@ function readCheckpointHistory(checkpoint) {
7414
7490
  });
7415
7491
  }
7416
7492
  async function recoverChildRunEventsFromCheckpoint(params) {
7417
- const checkpoint = await params.checkpointer.load(params.conversationId);
7493
+ const checkpoint = await params.checkpointer.load(params.checkpointKey);
7418
7494
  const history = readCheckpointHistory(checkpoint);
7419
7495
  if (history.length === 0) {
7420
7496
  return [];
@@ -7422,7 +7498,7 @@ async function recoverChildRunEventsFromCheckpoint(params) {
7422
7498
  if (hasSeedHistoryPrefix(history, params.seedHistory)) {
7423
7499
  return history.slice(params.seedHistory.length);
7424
7500
  }
7425
- return history.filter((event) => event.conversation_id === params.internalConversationId);
7501
+ return history.filter((event) => event.conversation_id === params.childConversationId);
7426
7502
  }
7427
7503
 
7428
7504
  // src/runtime-kernel/child-runs/childRunInvoker.ts
@@ -7451,6 +7527,7 @@ var ChildRunInvoker = class {
7451
7527
  agentConfig,
7452
7528
  userMessage,
7453
7529
  parentToolContext,
7530
+ conversationId,
7454
7531
  runId,
7455
7532
  parentRunId,
7456
7533
  subrunTracePublisher,
@@ -7459,12 +7536,18 @@ var ChildRunInvoker = class {
7459
7536
  modelId,
7460
7537
  abortSignal
7461
7538
  } = config;
7462
- const internalConversationId = `internal_${generateMessageId()}`;
7539
+ const internalCheckpointKey = `internal_${generateMessageId()}`;
7540
+ const runtimeConversationId = resolveChildRunConversationId({
7541
+ explicitConversationId: conversationId,
7542
+ parentToolContext,
7543
+ fallbackConversationId: internalCheckpointKey
7544
+ });
7463
7545
  const turnId = `turn_${Date.now()}`;
7464
- const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalConversationId;
7546
+ const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalCheckpointKey;
7465
7547
  const resolvedParentRunId = typeof parentRunId === "string" && parentRunId.trim().length > 0 ? parentRunId.trim() : typeof parentToolContext.runId === "string" && parentToolContext.runId.trim().length > 0 ? parentToolContext.runId.trim() : void 0;
7466
7548
  logger13.info(`\u542F\u52A8 child-run: ${agentConfig.id}`, {
7467
- conversationId: internalConversationId,
7549
+ conversationId: runtimeConversationId,
7550
+ checkpointKey: internalCheckpointKey,
7468
7551
  maxSteps,
7469
7552
  userMessage: userMessage.slice(0, 100) + (userMessage.length > 100 ? "..." : "")
7470
7553
  });
@@ -7525,7 +7608,7 @@ var ChildRunInvoker = class {
7525
7608
  const seedHistory = Array.isArray(seedHistoryEvents) ? seedHistoryEvents : [];
7526
7609
  const childToolContext = createChildRunToolContext({
7527
7610
  parentToolContext,
7528
- internalConversationId,
7611
+ conversationId: runtimeConversationId,
7529
7612
  turnId,
7530
7613
  runId: childRunId,
7531
7614
  parentRunId: resolvedParentRunId,
@@ -7534,13 +7617,13 @@ var ChildRunInvoker = class {
7534
7617
  });
7535
7618
  const subrunSseSink = subrunTracePublisher ? createChildRunTraceSink({
7536
7619
  publisher: subrunTracePublisher,
7537
- conversationId: internalConversationId,
7620
+ conversationId: runtimeConversationId,
7538
7621
  turnId
7539
7622
  }) : void 0;
7540
7623
  const initialLocal = {
7541
7624
  request,
7542
7625
  history: seedHistory,
7543
- conversationId: internalConversationId,
7626
+ conversationId: runtimeConversationId,
7544
7627
  turnId,
7545
7628
  toolContext: childToolContext,
7546
7629
  ...abortSignal ? { signal: abortSignal } : {},
@@ -7548,7 +7631,7 @@ var ChildRunInvoker = class {
7548
7631
  ...subrunSseSink ? { sseSink: subrunSseSink } : {},
7549
7632
  systemPrompt
7550
7633
  };
7551
- await graphExecutor.prime(internalConversationId, initialLocal, "llm");
7634
+ await graphExecutor.prime(internalCheckpointKey, initialLocal, "llm");
7552
7635
  const allEvents = [];
7553
7636
  let stepCount = 0;
7554
7637
  let finalAnswer;
@@ -7560,7 +7643,7 @@ var ChildRunInvoker = class {
7560
7643
  err.name = "AbortError";
7561
7644
  throw err;
7562
7645
  }
7563
- const result = await graphExecutor.runUntilYield(internalConversationId);
7646
+ const result = await graphExecutor.runUntilYield(internalCheckpointKey);
7564
7647
  appendUniqueEvents(allEvents, result.events);
7565
7648
  stepCount = result.stepCount;
7566
7649
  if (subrunSseSink && typeof subrunSseSink.finalize === "function") {
@@ -7594,8 +7677,8 @@ var ChildRunInvoker = class {
7594
7677
  }
7595
7678
  const recoveredEvents = await recoverChildRunEventsFromCheckpoint({
7596
7679
  checkpointer,
7597
- conversationId: internalConversationId,
7598
- internalConversationId,
7680
+ checkpointKey: internalCheckpointKey,
7681
+ childConversationId: runtimeConversationId,
7599
7682
  seedHistory
7600
7683
  });
7601
7684
  appendUniqueEvents(allEvents, recoveredEvents);
@@ -7612,7 +7695,7 @@ var ChildRunInvoker = class {
7612
7695
  stack: err.stack
7613
7696
  } : { error: String(err) });
7614
7697
  }
7615
- await checkpointer.clear(internalConversationId);
7698
+ await checkpointer.clear(internalCheckpointKey);
7616
7699
  return {
7617
7700
  success: !error,
7618
7701
  runId: childRunId,
@@ -7625,6 +7708,16 @@ var ChildRunInvoker = class {
7625
7708
  };
7626
7709
  }
7627
7710
  };
7711
+ function readNonEmptyString6(value) {
7712
+ if (typeof value !== "string") {
7713
+ return void 0;
7714
+ }
7715
+ const trimmed = value.trim();
7716
+ return trimmed.length > 0 ? trimmed : void 0;
7717
+ }
7718
+ function resolveChildRunConversationId(params) {
7719
+ return readNonEmptyString6(params.explicitConversationId) ?? readNonEmptyString6(params.parentToolContext.conversationId) ?? params.fallbackConversationId;
7720
+ }
7628
7721
  function resolveChildRunSystemReminderPolicy(agentConfig) {
7629
7722
  const configured = agentConfig.systemReminderPolicy ?? agentConfig.contextPolicy?.systemReminder;
7630
7723
  const threshold = agentConfig.stepPolicy?.lastStepsHintThreshold;
@@ -7815,7 +7908,7 @@ function cloneRunRecord(record) {
7815
7908
  ...record,
7816
7909
  iterationBudget: record.iterationBudget ? { ...record.iterationBudget } : void 0,
7817
7910
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0,
7818
- metadata: record.metadata ? { ...record.metadata } : void 0
7911
+ metadata: record.metadata ? structuredClone(record.metadata) : void 0
7819
7912
  };
7820
7913
  }
7821
7914
  function matchesStatus(candidate, filter) {
@@ -8227,7 +8320,7 @@ function isTerminalStatus(status) {
8227
8320
  return status === "completed" || status === "failed" || status === "cancelled";
8228
8321
  }
8229
8322
  function cloneMetadata(metadata) {
8230
- return metadata ? { ...metadata } : void 0;
8323
+ return metadata ? structuredClone(metadata) : void 0;
8231
8324
  }
8232
8325
  function recordToSnapshot(record) {
8233
8326
  return {
@@ -8314,7 +8407,7 @@ var DefaultRunSupervisor = class {
8314
8407
  startedAt,
8315
8408
  updatedAt: startedAt,
8316
8409
  iterationBudget: spec.iterationBudget ? { ...spec.iterationBudget } : void 0,
8317
- metadata: spec.metadata ? { ...spec.metadata } : void 0
8410
+ metadata: cloneMetadata(spec.metadata)
8318
8411
  };
8319
8412
  await this.registryStore.save(record);
8320
8413
  const handle = new DefaultRunHandle({
@@ -8488,12 +8581,13 @@ var DefaultRunSupervisor = class {
8488
8581
  }
8489
8582
  try {
8490
8583
  await handle.markRunning({ currentNode: "detached" });
8584
+ const registeredRecord = await this.registryStore.load(handle.runId);
8491
8585
  const executorOutcome = await this.executor.execute({
8492
8586
  runId: handle.runId,
8493
- parentRunId: spec.parentRunId,
8494
- conversationId: spec.conversationId,
8495
- agentSpec: spec.agentSpec,
8496
- request: spec.request,
8587
+ parentRunId: handle.parentRunId,
8588
+ conversationId: registeredRecord?.conversationId ?? spec.conversationId,
8589
+ agentSpec: await handle.spec(),
8590
+ request: await handle.request(),
8497
8591
  signal: handle.signal,
8498
8592
  eventBus: spec.eventBus,
8499
8593
  eventStore: spec.eventStore,
@@ -8502,7 +8596,7 @@ var DefaultRunSupervisor = class {
8502
8596
  contextFences: spec.contextFences,
8503
8597
  wakeSource: spec.wakeSource,
8504
8598
  ephemeral: spec.ephemeral,
8505
- metadata: spec.metadata
8599
+ metadata: cloneMetadata(registeredRecord?.metadata ?? spec.metadata)
8506
8600
  });
8507
8601
  const outcome = await this.persistExecutorOutcome(handle, executorOutcome);
8508
8602
  this.notifyTerminalWaiters(outcome);
@@ -8566,10 +8660,14 @@ var DefaultRunSupervisor = class {
8566
8660
  await this.registryStore.save(record);
8567
8661
  }
8568
8662
  const completedAt = executorOutcome?.completedAt ?? this.now();
8663
+ const fallbackMeta = record ? void 0 : await handle.meta();
8569
8664
  const outcome = recordToTerminalOutcome(record ?? {
8570
8665
  runId: handle.runId,
8571
8666
  parentRunId: handle.parentRunId,
8572
- status: executorOutcome?.status ?? "completed"}, completedAt);
8667
+ conversationId: fallbackMeta?.conversationId ?? "",
8668
+ agentSpecId: fallbackMeta?.agentSpecId,
8669
+ status: executorOutcome?.status ?? "completed",
8670
+ startedAt: fallbackMeta?.startedAt ?? completedAt}, completedAt);
8573
8671
  const nextOutcome = {
8574
8672
  ...outcome,
8575
8673
  metadata: {
@@ -8797,6 +8895,7 @@ function createGraphLoopHarness(options) {
8797
8895
  };
8798
8896
  return {
8799
8897
  async run() {
8898
+ const checkpointKey = options.conversationId;
8800
8899
  const executor = createDefaultGraphExecutor({
8801
8900
  llmNode: options.createLlmNode({
8802
8901
  llmCaller: options.llmCaller,
@@ -8825,8 +8924,8 @@ function createGraphLoopHarness(options) {
8825
8924
  signal: options.signal ?? options.toolContext.abortSignal,
8826
8925
  executorLocal
8827
8926
  };
8828
- await executor.prime(options.conversationId, local, "user");
8829
- const result = await executor.runUntilYield(options.conversationId);
8927
+ await executor.prime(checkpointKey, local, "user");
8928
+ const result = await executor.runUntilYield(checkpointKey);
8830
8929
  return {
8831
8930
  checkpointNodeId: result.checkpoint.nodeId,
8832
8931
  stepCount: result.stepCount