@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/index.cjs CHANGED
@@ -59,6 +59,7 @@ __export(runtime_kernel_exports, {
59
59
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
60
60
  consoleAudit: () => consoleAudit,
61
61
  contextBudgetWarningTemplate: () => contextBudgetWarningTemplate,
62
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
62
63
  countToolCallsInCurrentRequest: () => countToolCallsInCurrentRequest,
63
64
  createCompositeAudit: () => createCompositeAudit,
64
65
  createConsoleAudit: () => createConsoleAudit,
@@ -140,6 +141,7 @@ var Logger = class {
140
141
  constructor(moduleName) {
141
142
  this.moduleName = moduleName;
142
143
  }
144
+ moduleName;
143
145
  debug(message, data) {
144
146
  this.log(0 /* DEBUG */, "debug", message, data);
145
147
  }
@@ -563,6 +565,7 @@ var AgentSpecBudgetPolicy = zod.z.object({
563
565
  });
564
566
  var AgentSpecToolHistoryPolicy = zod.z.object({
565
567
  strategy: zod.z.enum(["per-pair", "per-run", "none"]).optional(),
568
+ retentionMode: zod.z.enum(["drop", "compress"]).optional(),
566
569
  keepLatestToolPairs: zod.z.number().int().nonnegative().optional(),
567
570
  keepLatestRuns: zod.z.number().int().nonnegative().optional(),
568
571
  maxInteractionGroups: zod.z.number().int().nonnegative().optional(),
@@ -685,12 +688,13 @@ var AgentSpecContextPolicy = zod.z.object({
685
688
  var DEFAULT_CONTEXT_POLICY = {
686
689
  profileId: "agent",
687
690
  budget: {
688
- maxTokens: 12e4,
691
+ maxTokens: 232e3,
689
692
  reservedForResponse: 2400,
690
693
  workingMemoryBudgetPercentage: 0.7
691
694
  },
692
695
  toolHistory: {
693
696
  strategy: "per-run",
697
+ retentionMode: "drop",
694
698
  keepLatestToolPairs: 2,
695
699
  keepLatestRuns: 1,
696
700
  maxInteractionGroups: 12,
@@ -1542,6 +1546,17 @@ var logger = new Logger("GraphExecutor");
1542
1546
  function asLocalRecord(local) {
1543
1547
  return local && typeof local === "object" ? { ...local } : {};
1544
1548
  }
1549
+ function readNonEmptyString(value) {
1550
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1551
+ }
1552
+ function readRuntimeConversationId(state) {
1553
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1554
+ return readNonEmptyString(local?.conversationId);
1555
+ }
1556
+ function readRuntimeTurnId(state) {
1557
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1558
+ return readNonEmptyString(local?.turnId);
1559
+ }
1545
1560
  var GraphExecutor = class {
1546
1561
  constructor(checkpointer, config = {}) {
1547
1562
  this.checkpointer = checkpointer;
@@ -1551,6 +1566,7 @@ var GraphExecutor = class {
1551
1566
  };
1552
1567
  this.telemetryPort = config.telemetryPort ?? noopTelemetry;
1553
1568
  }
1569
+ checkpointer;
1554
1570
  nodes = /* @__PURE__ */ new Map();
1555
1571
  ephemeralLocals = /* @__PURE__ */ new Map();
1556
1572
  config;
@@ -1558,8 +1574,8 @@ var GraphExecutor = class {
1558
1574
  registerNode(node) {
1559
1575
  this.nodes.set(node.id, node);
1560
1576
  }
1561
- async peekCheckpoint(conversationId) {
1562
- return await this.checkpointer.load(conversationId);
1577
+ async peekCheckpoint(checkpointKey) {
1578
+ return await this.checkpointer.load(checkpointKey);
1563
1579
  }
1564
1580
  sanitize(state) {
1565
1581
  const local = asLocalRecord(state.local);
@@ -1571,8 +1587,8 @@ var GraphExecutor = class {
1571
1587
  local
1572
1588
  };
1573
1589
  }
1574
- async prime(conversationId, local, nodeId = "user") {
1575
- this.ephemeralLocals.set(conversationId, { ...local || {} });
1590
+ async prime(checkpointKey, local, nodeId = "user") {
1591
+ this.ephemeralLocals.set(checkpointKey, { ...local || {} });
1576
1592
  const localSansMemory = { ...local || {} };
1577
1593
  if ("memory" in localSansMemory) delete localSansMemory.memory;
1578
1594
  const state = {
@@ -1580,10 +1596,10 @@ var GraphExecutor = class {
1580
1596
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1581
1597
  local: localSansMemory
1582
1598
  };
1583
- await this.checkpointer.save(conversationId, state);
1599
+ await this.checkpointer.save(checkpointKey, state);
1584
1600
  }
1585
- async setNode(conversationId, nodeId, localPatch) {
1586
- const current = await this.checkpointer.load(conversationId) || {
1601
+ async setNode(checkpointKey, nodeId, localPatch) {
1602
+ const current = await this.checkpointer.load(checkpointKey) || {
1587
1603
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1588
1604
  local: {}
1589
1605
  };
@@ -1594,19 +1610,46 @@ var GraphExecutor = class {
1594
1610
  schemaVersion: current.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
1595
1611
  local: mergedLocal
1596
1612
  };
1597
- await this.checkpointer.save(conversationId, next);
1613
+ await this.checkpointer.save(checkpointKey, next);
1598
1614
  }
1599
- async runUntilYield(conversationId) {
1615
+ async runUntilYield(checkpointKey) {
1600
1616
  const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1601
1617
  let lifecyclePhase = "completed";
1618
+ let initialState = null;
1619
+ try {
1620
+ initialState = await this.loadInitialState(checkpointKey);
1621
+ } catch (err) {
1622
+ lifecyclePhase = "failed";
1623
+ this.telemetryPort.emit({
1624
+ kind: "run_lifecycle",
1625
+ runId,
1626
+ phase: "spawned",
1627
+ scope: {}
1628
+ });
1629
+ this.telemetryPort.emit({
1630
+ kind: "run_lifecycle",
1631
+ runId,
1632
+ phase: lifecyclePhase,
1633
+ scope: {}
1634
+ });
1635
+ throw err;
1636
+ }
1637
+ let lifecycleConversationId = readRuntimeConversationId(initialState);
1638
+ let lifecycleTurnId = readRuntimeTurnId(initialState);
1602
1639
  this.telemetryPort.emit({
1603
1640
  kind: "run_lifecycle",
1604
1641
  runId,
1605
1642
  phase: "spawned",
1606
- scope: { conversationId: conversationId || void 0 }
1643
+ scope: {
1644
+ conversationId: lifecycleConversationId,
1645
+ turnId: lifecycleTurnId
1646
+ }
1607
1647
  });
1608
1648
  try {
1609
- return await this.runUntilYieldInternal(conversationId);
1649
+ const result = await this.runUntilYieldInternal(checkpointKey, initialState);
1650
+ lifecycleConversationId = readRuntimeConversationId(result.checkpoint);
1651
+ lifecycleTurnId = readRuntimeTurnId(result.checkpoint);
1652
+ return result;
1610
1653
  } catch (err) {
1611
1654
  lifecyclePhase = err?.name === "AbortError" ? "cancelled" : "failed";
1612
1655
  throw err;
@@ -1615,17 +1658,23 @@ var GraphExecutor = class {
1615
1658
  kind: "run_lifecycle",
1616
1659
  runId,
1617
1660
  phase: lifecyclePhase,
1618
- scope: { conversationId: conversationId || void 0 }
1661
+ scope: {
1662
+ conversationId: lifecycleConversationId,
1663
+ turnId: lifecycleTurnId
1664
+ }
1619
1665
  });
1620
1666
  }
1621
1667
  }
1622
- async runUntilYieldInternal(conversationId) {
1623
- let state = await this.checkpointer.load(conversationId) || {
1668
+ async loadInitialState(checkpointKey) {
1669
+ return await this.checkpointer.load(checkpointKey) || {
1624
1670
  nodeId: "user",
1625
1671
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1626
1672
  local: {}
1627
1673
  };
1628
- const ephemeral = this.ephemeralLocals.get(conversationId) || {};
1674
+ }
1675
+ async runUntilYieldInternal(checkpointKey, initialState) {
1676
+ let state = initialState;
1677
+ const ephemeral = this.ephemeralLocals.get(checkpointKey) || {};
1629
1678
  state = {
1630
1679
  ...state,
1631
1680
  schemaVersion: state.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
@@ -1654,7 +1703,7 @@ var GraphExecutor = class {
1654
1703
  const signalRaw = state.local?.signal;
1655
1704
  if (isAbortSignal2(signalRaw) && signalRaw.aborted) {
1656
1705
  logger.warn("[GraphExecutor] \u6536\u5230 AbortSignal\uFF0C\u7ACB\u5373\u505C\u6B62\u63A8\u7406\u5FAA\u73AF");
1657
- this.ephemeralLocals.delete(conversationId);
1706
+ this.ephemeralLocals.delete(checkpointKey);
1658
1707
  throwAbortError();
1659
1708
  }
1660
1709
  const isLastStep = cycleStepCount >= this.config.maxSteps;
@@ -1702,8 +1751,8 @@ var GraphExecutor = class {
1702
1751
  checkpointCount
1703
1752
  });
1704
1753
  const cp2 = this.sanitize(state);
1705
- await this.checkpointer.save(conversationId, cp2);
1706
- this.ephemeralLocals.delete(conversationId);
1754
+ await this.checkpointer.save(checkpointKey, cp2);
1755
+ this.ephemeralLocals.delete(checkpointKey);
1707
1756
  return { events: allEvents, checkpoint: cp2, stepCount };
1708
1757
  }
1709
1758
  logger.info("[GraphExecutor] \u8282\u70B9\u5207\u6362", {
@@ -1714,18 +1763,18 @@ var GraphExecutor = class {
1714
1763
  });
1715
1764
  const nodeRunStartedAt = Date.now();
1716
1765
  const nodeIdForTelemetry = state.nodeId;
1766
+ const conversationIdForTelemetry = readRuntimeConversationId(state);
1717
1767
  let result;
1718
1768
  try {
1719
1769
  result = await node.run(state);
1720
1770
  } finally {
1721
- const turnIdForTelemetry = typeof state.local?.turnId === "string" ? state.local.turnId : void 0;
1722
1771
  this.telemetryPort.emit({
1723
1772
  kind: "graph_node",
1724
1773
  nodeId: nodeIdForTelemetry,
1725
1774
  durationMs: Date.now() - nodeRunStartedAt,
1726
1775
  scope: {
1727
- conversationId: conversationId || void 0,
1728
- turnId: turnIdForTelemetry
1776
+ conversationId: conversationIdForTelemetry,
1777
+ turnId: readRuntimeTurnId(state)
1729
1778
  }
1730
1779
  });
1731
1780
  }
@@ -1764,7 +1813,7 @@ var GraphExecutor = class {
1764
1813
  });
1765
1814
  state = { ...state, nodeId: nextNodeId };
1766
1815
  const cp2 = this.sanitize(state);
1767
- await this.checkpointer.save(conversationId, cp2);
1816
+ await this.checkpointer.save(checkpointKey, cp2);
1768
1817
  continue;
1769
1818
  }
1770
1819
  if (result.kind === "yield") {
@@ -1775,7 +1824,7 @@ var GraphExecutor = class {
1775
1824
  checkpointCount
1776
1825
  });
1777
1826
  const cp2 = this.sanitize(state);
1778
- await this.checkpointer.save(conversationId, cp2);
1827
+ await this.checkpointer.save(checkpointKey, cp2);
1779
1828
  return { events: allEvents, checkpoint: cp2, stepCount };
1780
1829
  }
1781
1830
  if (result.kind === "pause") {
@@ -1786,7 +1835,7 @@ var GraphExecutor = class {
1786
1835
  checkpointCount
1787
1836
  });
1788
1837
  const cp2 = this.sanitize(state);
1789
- await this.checkpointer.save(conversationId, cp2);
1838
+ await this.checkpointer.save(checkpointKey, cp2);
1790
1839
  return { events: allEvents, checkpoint: cp2, stepCount };
1791
1840
  }
1792
1841
  }
@@ -1797,8 +1846,8 @@ var GraphExecutor = class {
1797
1846
  checkpointCount
1798
1847
  });
1799
1848
  const cp = this.sanitize(state);
1800
- await this.checkpointer.save(conversationId, cp);
1801
- this.ephemeralLocals.delete(conversationId);
1849
+ await this.checkpointer.save(checkpointKey, cp);
1850
+ this.ephemeralLocals.delete(checkpointKey);
1802
1851
  return { events: allEvents, checkpoint: cp, stepCount };
1803
1852
  }
1804
1853
  };
@@ -1995,15 +2044,15 @@ function splitConcatenatedJsonObjects(input) {
1995
2044
  }
1996
2045
 
1997
2046
  // src/runtime-kernel/graph-engine/tick-pipeline/helpers.ts
1998
- function readNonEmptyString(value) {
2047
+ function readNonEmptyString2(value) {
1999
2048
  if (typeof value !== "string") return void 0;
2000
2049
  const trimmed = value.trim();
2001
2050
  return trimmed.length > 0 ? trimmed : void 0;
2002
2051
  }
2003
2052
  function resolveConversationIdForRuntimeEvents(toolContext) {
2004
- const fromCamel = readNonEmptyString(toolContext?.conversationId);
2053
+ const fromCamel = readNonEmptyString2(toolContext?.conversationId);
2005
2054
  if (fromCamel) return fromCamel;
2006
- const fromSnake = toolContext ? readNonEmptyString(toolContext["conversation_id"]) : void 0;
2055
+ const fromSnake = toolContext ? readNonEmptyString2(toolContext["conversation_id"]) : void 0;
2007
2056
  if (fromSnake) return fromSnake;
2008
2057
  return generateMessageId();
2009
2058
  }
@@ -2385,7 +2434,7 @@ var runModelLockMiddleware = async (ctx, stage, next) => {
2385
2434
  if (stage.id !== "execute_llm") {
2386
2435
  return;
2387
2436
  }
2388
- const normalized = readNonEmptyString(ctx.cloudQuotaFallbackAppliedModelId);
2437
+ const normalized = readNonEmptyString2(ctx.cloudQuotaFallbackAppliedModelId);
2389
2438
  if (!normalized) {
2390
2439
  return;
2391
2440
  }
@@ -2986,7 +3035,7 @@ function createExecuteLlmStage(dependencies) {
2986
3035
  streamEventHandler,
2987
3036
  ctx.signal,
2988
3037
  (fallbackModelId) => {
2989
- ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString(fallbackModelId);
3038
+ ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString2(fallbackModelId);
2990
3039
  },
2991
3040
  (info) => {
2992
3041
  ctx.modelFallbackAudit = info;
@@ -3030,7 +3079,7 @@ function createPrepareCallStage(dependencies) {
3030
3079
  return {
3031
3080
  id: "prepare_call",
3032
3081
  async run(ctx) {
3033
- const lockedRunModelId = readNonEmptyString(ctx.executorLocal?.runLockedModelId);
3082
+ const lockedRunModelId = readNonEmptyString2(ctx.executorLocal?.runLockedModelId);
3034
3083
  const requestedModelId = lockedRunModelId ?? ctx.request.model_id;
3035
3084
  ctx.modelId = dependencies.modelResolver.resolveModelId(requestedModelId);
3036
3085
  await emitAuditEnvelope(ctx.audit, {
@@ -3102,7 +3151,7 @@ var GraphAgentExecutor = class {
3102
3151
  this.llmCaller = dependencies.llmCaller;
3103
3152
  this.toolRuntime = dependencies.toolRuntime;
3104
3153
  this.contextBuilder = dependencies.contextBuilder;
3105
- this.cloudQuotaFallbackModelId = readNonEmptyString(dependencies.cloudQuotaFallbackModelId);
3154
+ this.cloudQuotaFallbackModelId = readNonEmptyString2(dependencies.cloudQuotaFallbackModelId);
3106
3155
  this.modelCatalog = dependencies.modelCatalog ?? createEmptyModelCatalog();
3107
3156
  this.modelResolver = dependencies.modelResolver ?? new ModelResolver({
3108
3157
  modelCatalog: this.modelCatalog
@@ -3150,7 +3199,7 @@ var GraphAgentExecutor = class {
3150
3199
  llmMessages: [],
3151
3200
  mode: input.request.mode === "chat" ? "chat" : "agent",
3152
3201
  conversationId: resolveConversationIdForRuntimeEvents(input.toolContext),
3153
- turnId: readNonEmptyString(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3202
+ turnId: readNonEmptyString2(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3154
3203
  telemetry: this.telemetryPort,
3155
3204
  audit: this.auditPort
3156
3205
  };
@@ -3200,18 +3249,18 @@ function isSummarizationCallbacks(value) {
3200
3249
  function isGraphSseSink(value) {
3201
3250
  return typeof value === "function";
3202
3251
  }
3203
- function readNonEmptyString2(value) {
3252
+ function readNonEmptyString3(value) {
3204
3253
  if (typeof value !== "string") return void 0;
3205
3254
  const trimmed = value.trim();
3206
3255
  return trimmed.length > 0 ? trimmed : void 0;
3207
3256
  }
3208
3257
  function readGraphAgentLocal(local) {
3209
3258
  const source = local ?? {};
3210
- const answerId = readNonEmptyString2(source.answerId);
3259
+ const answerId = readNonEmptyString3(source.answerId);
3211
3260
  const chunkSeq = Number.isInteger(source.chunkSeq) ? Number(source.chunkSeq) : 0;
3212
3261
  return {
3213
- conversationId: readNonEmptyString2(source.conversationId) ?? "",
3214
- turnId: readNonEmptyString2(source.turnId),
3262
+ conversationId: readNonEmptyString3(source.conversationId) ?? "",
3263
+ turnId: readNonEmptyString3(source.turnId),
3215
3264
  request: isAgentInvocationRequest(source.request) ? source.request : void 0,
3216
3265
  toolContext: isToolExecutionContext(source.toolContext) ? source.toolContext : void 0,
3217
3266
  history: isRuntimeEventArray(source.history) ? source.history : [],
@@ -3976,7 +4025,7 @@ var LlmNode = class {
3976
4025
  function isRecord8(value) {
3977
4026
  return typeof value === "object" && value !== null && !Array.isArray(value);
3978
4027
  }
3979
- function readNonEmptyString3(value) {
4028
+ function readNonEmptyString4(value) {
3980
4029
  if (typeof value !== "string") {
3981
4030
  return void 0;
3982
4031
  }
@@ -3998,7 +4047,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3998
4047
  return void 0;
3999
4048
  }
4000
4049
  if (toolName === "write_report") {
4001
- const report = readNonEmptyString3(data.report);
4050
+ const report = readNonEmptyString4(data.report);
4002
4051
  if (!report) {
4003
4052
  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");
4004
4053
  }
@@ -4008,7 +4057,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
4008
4057
  if (data.success !== true) {
4009
4058
  return void 0;
4010
4059
  }
4011
- const finalAnswer = readNonEmptyString3(data.final_answer);
4060
+ const finalAnswer = readNonEmptyString4(data.final_answer);
4012
4061
  if (!finalAnswer) {
4013
4062
  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");
4014
4063
  }
@@ -4558,6 +4607,31 @@ function ensureToolContextRuntimeCapability(params) {
4558
4607
  function getToolContextRuntimeBinding(context) {
4559
4608
  return readBinding(context);
4560
4609
  }
4610
+ function copyToolContextRuntimeCapability(source, target) {
4611
+ const sourceBinding = readBinding(source);
4612
+ if (!sourceBinding) {
4613
+ return void 0;
4614
+ }
4615
+ const existingTargetBinding = readBinding(target);
4616
+ if (existingTargetBinding) {
4617
+ exposeCompatibilitySurface(target, existingTargetBinding);
4618
+ return existingTargetBinding;
4619
+ }
4620
+ const targetBinding = createRuntimeBinding({
4621
+ context: target,
4622
+ persistedHistory: () => sourceBinding.getPersistedHistoryEvents(),
4623
+ workingHistory: () => sourceBinding.getWorkingHistoryEvents(),
4624
+ executionMeta: sourceBinding.readExecutionMeta()
4625
+ });
4626
+ Object.defineProperty(target, TOOL_CONTEXT_RUNTIME_BINDING_KEY, {
4627
+ value: targetBinding,
4628
+ enumerable: false,
4629
+ configurable: true,
4630
+ writable: false
4631
+ });
4632
+ exposeCompatibilitySurface(target, targetBinding);
4633
+ return targetBinding;
4634
+ }
4561
4635
  function readToolContextWorkingHistory(context) {
4562
4636
  if (context.conversationView) {
4563
4637
  return context.conversationView.getWorkingHistoryEvents();
@@ -5409,12 +5483,12 @@ function asRecord(value) {
5409
5483
  }
5410
5484
  return value;
5411
5485
  }
5412
- function summarizeCheckpoint(conversationId, state, savedAt) {
5486
+ function summarizeCheckpoint(checkpointKey, state, savedAt) {
5413
5487
  const local = asRecord(state.local);
5414
5488
  const executorLocal = asRecord(local?.executorLocal);
5415
5489
  const pendingToolCalls = local?.pendingToolCalls;
5416
5490
  return {
5417
- conversationId,
5491
+ checkpointKey,
5418
5492
  schemaVersion: state.schemaVersion ?? 1,
5419
5493
  savedAt,
5420
5494
  currentNode: state.nodeId,
@@ -5433,25 +5507,25 @@ var MemoryCheckpointer = class {
5433
5507
  local: state.local && typeof state.local === "object" && !Array.isArray(state.local) ? { ...state.local } : state.local
5434
5508
  };
5435
5509
  }
5436
- async load(conversationId) {
5437
- const entry = this.store.get(conversationId);
5510
+ async load(checkpointKey) {
5511
+ const entry = this.store.get(checkpointKey);
5438
5512
  return entry ? this.cloneState(entry.state) : null;
5439
5513
  }
5440
- async save(conversationId, state) {
5441
- this.store.set(conversationId, {
5514
+ async save(checkpointKey, state) {
5515
+ this.store.set(checkpointKey, {
5442
5516
  state: this.cloneState(state),
5443
5517
  savedAt: Date.now()
5444
5518
  });
5445
5519
  }
5446
- async clear(conversationId) {
5447
- this.store.delete(conversationId);
5520
+ async clear(checkpointKey) {
5521
+ this.store.delete(checkpointKey);
5448
5522
  }
5449
- async peekMeta(conversationId) {
5450
- const entry = this.store.get(conversationId);
5451
- return entry ? summarizeCheckpoint(conversationId, entry.state, entry.savedAt) : null;
5523
+ async peekMeta(checkpointKey) {
5524
+ const entry = this.store.get(checkpointKey);
5525
+ return entry ? summarizeCheckpoint(checkpointKey, entry.state, entry.savedAt) : null;
5452
5526
  }
5453
5527
  async list(filter = {}) {
5454
- 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);
5528
+ 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);
5455
5529
  if (filter.limit === void 0) {
5456
5530
  return summaries;
5457
5531
  }
@@ -5523,6 +5597,7 @@ __export(tools_exports, {
5523
5597
  CommonParameterTypes: () => CommonParameterTypes,
5524
5598
  ContextCheckpointTool: () => ContextCheckpointTool,
5525
5599
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
5600
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
5526
5601
  createContextCheckpointTool: () => createContextCheckpointTool,
5527
5602
  ensureToolContextRuntimeCapability: () => ensureToolContextRuntimeCapability,
5528
5603
  findCachedToolOutputByIdempotencyKey: () => findCachedToolOutputByIdempotencyKey,
@@ -5716,7 +5791,7 @@ function createContextCheckpointTool(options) {
5716
5791
  function isRecord15(value) {
5717
5792
  return !!value && typeof value === "object" && !Array.isArray(value);
5718
5793
  }
5719
- function readNonEmptyString4(value) {
5794
+ function readNonEmptyString5(value) {
5720
5795
  if (typeof value !== "string") {
5721
5796
  return void 0;
5722
5797
  }
@@ -5736,13 +5811,13 @@ function readToolContextUserQuery(context) {
5736
5811
  if (!context) {
5737
5812
  return void 0;
5738
5813
  }
5739
- return readNonEmptyString4(context["user_query"]);
5814
+ return readNonEmptyString5(context["user_query"]);
5740
5815
  }
5741
5816
  function readToolContextModelId(context) {
5742
5817
  if (!context) {
5743
5818
  return void 0;
5744
5819
  }
5745
- return readNonEmptyString4(context["modelId"]);
5820
+ return readNonEmptyString5(context["modelId"]);
5746
5821
  }
5747
5822
  function readToolContextRunContext(context) {
5748
5823
  if (!context) {
@@ -7450,6 +7525,7 @@ var DefaultTokenizerPort = class {
7450
7525
  constructor(config = {}) {
7451
7526
  this.config = config;
7452
7527
  }
7528
+ config;
7453
7529
  estimateText(text, _modelId) {
7454
7530
  return TokenCalculator.estimateTokens(text, {
7455
7531
  encoding: this.config.encoding,
@@ -7477,7 +7553,6 @@ __export(child_runs_exports, {
7477
7553
 
7478
7554
  // src/runtime-kernel/child-runs/childToolContext.ts
7479
7555
  function createChildRunToolContext(params) {
7480
- const inheritedConversationId = typeof params.parentToolContext.conversationId === "string" && params.parentToolContext.conversationId.trim().length > 0 ? params.parentToolContext.conversationId.trim() : void 0;
7481
7556
  const inheritedContext = stripRuntimeReservedToolContextPatch(params.parentToolContext);
7482
7557
  const childToolContext = {
7483
7558
  ...inheritedContext,
@@ -7489,7 +7564,7 @@ function createChildRunToolContext(params) {
7489
7564
  persistedHistory: params.seedHistory,
7490
7565
  workingHistory: params.seedHistory,
7491
7566
  executionMeta: {
7492
- conversationId: inheritedConversationId ?? params.internalConversationId,
7567
+ conversationId: params.conversationId,
7493
7568
  turnId: params.turnId,
7494
7569
  runId: params.runId,
7495
7570
  parentRunId: params.parentRunId
@@ -7591,6 +7666,8 @@ var FinalAnswerCollector = class {
7591
7666
  this.conversationId = conversationId;
7592
7667
  this.turnId = turnId;
7593
7668
  }
7669
+ conversationId;
7670
+ turnId;
7594
7671
  answerId;
7595
7672
  chunks = [];
7596
7673
  chunkCount = 0;
@@ -7807,7 +7884,7 @@ function readCheckpointHistory(checkpoint) {
7807
7884
  });
7808
7885
  }
7809
7886
  async function recoverChildRunEventsFromCheckpoint(params) {
7810
- const checkpoint = await params.checkpointer.load(params.conversationId);
7887
+ const checkpoint = await params.checkpointer.load(params.checkpointKey);
7811
7888
  const history = readCheckpointHistory(checkpoint);
7812
7889
  if (history.length === 0) {
7813
7890
  return [];
@@ -7815,7 +7892,7 @@ async function recoverChildRunEventsFromCheckpoint(params) {
7815
7892
  if (hasSeedHistoryPrefix(history, params.seedHistory)) {
7816
7893
  return history.slice(params.seedHistory.length);
7817
7894
  }
7818
- return history.filter((event) => event.conversation_id === params.internalConversationId);
7895
+ return history.filter((event) => event.conversation_id === params.childConversationId);
7819
7896
  }
7820
7897
 
7821
7898
  // src/runtime-kernel/child-runs/childRunInvoker.ts
@@ -7844,6 +7921,7 @@ var ChildRunInvoker = class {
7844
7921
  agentConfig,
7845
7922
  userMessage,
7846
7923
  parentToolContext,
7924
+ conversationId,
7847
7925
  runId,
7848
7926
  parentRunId,
7849
7927
  subrunTracePublisher,
@@ -7852,12 +7930,18 @@ var ChildRunInvoker = class {
7852
7930
  modelId,
7853
7931
  abortSignal
7854
7932
  } = config;
7855
- const internalConversationId = `internal_${generateMessageId()}`;
7933
+ const internalCheckpointKey = `internal_${generateMessageId()}`;
7934
+ const runtimeConversationId = resolveChildRunConversationId({
7935
+ explicitConversationId: conversationId,
7936
+ parentToolContext,
7937
+ fallbackConversationId: internalCheckpointKey
7938
+ });
7856
7939
  const turnId = `turn_${Date.now()}`;
7857
- const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalConversationId;
7940
+ const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalCheckpointKey;
7858
7941
  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;
7859
7942
  logger13.info(`\u542F\u52A8 child-run: ${agentConfig.id}`, {
7860
- conversationId: internalConversationId,
7943
+ conversationId: runtimeConversationId,
7944
+ checkpointKey: internalCheckpointKey,
7861
7945
  maxSteps,
7862
7946
  userMessage: userMessage.slice(0, 100) + (userMessage.length > 100 ? "..." : "")
7863
7947
  });
@@ -7918,7 +8002,7 @@ var ChildRunInvoker = class {
7918
8002
  const seedHistory = Array.isArray(seedHistoryEvents) ? seedHistoryEvents : [];
7919
8003
  const childToolContext = createChildRunToolContext({
7920
8004
  parentToolContext,
7921
- internalConversationId,
8005
+ conversationId: runtimeConversationId,
7922
8006
  turnId,
7923
8007
  runId: childRunId,
7924
8008
  parentRunId: resolvedParentRunId,
@@ -7927,13 +8011,13 @@ var ChildRunInvoker = class {
7927
8011
  });
7928
8012
  const subrunSseSink = subrunTracePublisher ? createChildRunTraceSink({
7929
8013
  publisher: subrunTracePublisher,
7930
- conversationId: internalConversationId,
8014
+ conversationId: runtimeConversationId,
7931
8015
  turnId
7932
8016
  }) : void 0;
7933
8017
  const initialLocal = {
7934
8018
  request,
7935
8019
  history: seedHistory,
7936
- conversationId: internalConversationId,
8020
+ conversationId: runtimeConversationId,
7937
8021
  turnId,
7938
8022
  toolContext: childToolContext,
7939
8023
  ...abortSignal ? { signal: abortSignal } : {},
@@ -7941,7 +8025,7 @@ var ChildRunInvoker = class {
7941
8025
  ...subrunSseSink ? { sseSink: subrunSseSink } : {},
7942
8026
  systemPrompt
7943
8027
  };
7944
- await graphExecutor.prime(internalConversationId, initialLocal, "llm");
8028
+ await graphExecutor.prime(internalCheckpointKey, initialLocal, "llm");
7945
8029
  const allEvents = [];
7946
8030
  let stepCount = 0;
7947
8031
  let finalAnswer;
@@ -7953,7 +8037,7 @@ var ChildRunInvoker = class {
7953
8037
  err.name = "AbortError";
7954
8038
  throw err;
7955
8039
  }
7956
- const result = await graphExecutor.runUntilYield(internalConversationId);
8040
+ const result = await graphExecutor.runUntilYield(internalCheckpointKey);
7957
8041
  appendUniqueEvents(allEvents, result.events);
7958
8042
  stepCount = result.stepCount;
7959
8043
  if (subrunSseSink && typeof subrunSseSink.finalize === "function") {
@@ -7987,8 +8071,8 @@ var ChildRunInvoker = class {
7987
8071
  }
7988
8072
  const recoveredEvents = await recoverChildRunEventsFromCheckpoint({
7989
8073
  checkpointer,
7990
- conversationId: internalConversationId,
7991
- internalConversationId,
8074
+ checkpointKey: internalCheckpointKey,
8075
+ childConversationId: runtimeConversationId,
7992
8076
  seedHistory
7993
8077
  });
7994
8078
  appendUniqueEvents(allEvents, recoveredEvents);
@@ -8005,7 +8089,7 @@ var ChildRunInvoker = class {
8005
8089
  stack: err.stack
8006
8090
  } : { error: String(err) });
8007
8091
  }
8008
- await checkpointer.clear(internalConversationId);
8092
+ await checkpointer.clear(internalCheckpointKey);
8009
8093
  return {
8010
8094
  success: !error,
8011
8095
  runId: childRunId,
@@ -8018,6 +8102,16 @@ var ChildRunInvoker = class {
8018
8102
  };
8019
8103
  }
8020
8104
  };
8105
+ function readNonEmptyString6(value) {
8106
+ if (typeof value !== "string") {
8107
+ return void 0;
8108
+ }
8109
+ const trimmed = value.trim();
8110
+ return trimmed.length > 0 ? trimmed : void 0;
8111
+ }
8112
+ function resolveChildRunConversationId(params) {
8113
+ return readNonEmptyString6(params.explicitConversationId) ?? readNonEmptyString6(params.parentToolContext.conversationId) ?? params.fallbackConversationId;
8114
+ }
8021
8115
  function resolveChildRunSystemReminderPolicy(agentConfig) {
8022
8116
  const configured = agentConfig.systemReminderPolicy ?? agentConfig.contextPolicy?.systemReminder;
8023
8117
  const threshold = agentConfig.stepPolicy?.lastStepsHintThreshold;
@@ -8208,7 +8302,7 @@ function cloneRunRecord(record) {
8208
8302
  ...record,
8209
8303
  iterationBudget: record.iterationBudget ? { ...record.iterationBudget } : void 0,
8210
8304
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0,
8211
- metadata: record.metadata ? { ...record.metadata } : void 0
8305
+ metadata: record.metadata ? structuredClone(record.metadata) : void 0
8212
8306
  };
8213
8307
  }
8214
8308
  function matchesStatus(candidate, filter) {
@@ -8620,7 +8714,7 @@ function isTerminalStatus(status) {
8620
8714
  return status === "completed" || status === "failed" || status === "cancelled";
8621
8715
  }
8622
8716
  function cloneMetadata(metadata) {
8623
- return metadata ? { ...metadata } : void 0;
8717
+ return metadata ? structuredClone(metadata) : void 0;
8624
8718
  }
8625
8719
  function recordToSnapshot(record) {
8626
8720
  return {
@@ -8707,7 +8801,7 @@ var DefaultRunSupervisor = class {
8707
8801
  startedAt,
8708
8802
  updatedAt: startedAt,
8709
8803
  iterationBudget: spec.iterationBudget ? { ...spec.iterationBudget } : void 0,
8710
- metadata: spec.metadata ? { ...spec.metadata } : void 0
8804
+ metadata: cloneMetadata(spec.metadata)
8711
8805
  };
8712
8806
  await this.registryStore.save(record);
8713
8807
  const handle = new DefaultRunHandle({
@@ -8881,12 +8975,13 @@ var DefaultRunSupervisor = class {
8881
8975
  }
8882
8976
  try {
8883
8977
  await handle.markRunning({ currentNode: "detached" });
8978
+ const registeredRecord = await this.registryStore.load(handle.runId);
8884
8979
  const executorOutcome = await this.executor.execute({
8885
8980
  runId: handle.runId,
8886
- parentRunId: spec.parentRunId,
8887
- conversationId: spec.conversationId,
8888
- agentSpec: spec.agentSpec,
8889
- request: spec.request,
8981
+ parentRunId: handle.parentRunId,
8982
+ conversationId: registeredRecord?.conversationId ?? spec.conversationId,
8983
+ agentSpec: await handle.spec(),
8984
+ request: await handle.request(),
8890
8985
  signal: handle.signal,
8891
8986
  eventBus: spec.eventBus,
8892
8987
  eventStore: spec.eventStore,
@@ -8895,7 +8990,7 @@ var DefaultRunSupervisor = class {
8895
8990
  contextFences: spec.contextFences,
8896
8991
  wakeSource: spec.wakeSource,
8897
8992
  ephemeral: spec.ephemeral,
8898
- metadata: spec.metadata
8993
+ metadata: cloneMetadata(registeredRecord?.metadata ?? spec.metadata)
8899
8994
  });
8900
8995
  const outcome = await this.persistExecutorOutcome(handle, executorOutcome);
8901
8996
  this.notifyTerminalWaiters(outcome);
@@ -8959,10 +9054,14 @@ var DefaultRunSupervisor = class {
8959
9054
  await this.registryStore.save(record);
8960
9055
  }
8961
9056
  const completedAt = executorOutcome?.completedAt ?? this.now();
9057
+ const fallbackMeta = record ? void 0 : await handle.meta();
8962
9058
  const outcome = recordToTerminalOutcome(record ?? {
8963
9059
  runId: handle.runId,
8964
9060
  parentRunId: handle.parentRunId,
8965
- status: executorOutcome?.status ?? "completed"}, completedAt);
9061
+ conversationId: fallbackMeta?.conversationId ?? "",
9062
+ agentSpecId: fallbackMeta?.agentSpecId,
9063
+ status: executorOutcome?.status ?? "completed",
9064
+ startedAt: fallbackMeta?.startedAt ?? completedAt}, completedAt);
8966
9065
  const nextOutcome = {
8967
9066
  ...outcome,
8968
9067
  metadata: {
@@ -9190,6 +9289,7 @@ function createGraphLoopHarness(options) {
9190
9289
  };
9191
9290
  return {
9192
9291
  async run() {
9292
+ const checkpointKey = options.conversationId;
9193
9293
  const executor = createDefaultGraphExecutor({
9194
9294
  llmNode: options.createLlmNode({
9195
9295
  llmCaller: options.llmCaller,
@@ -9218,8 +9318,8 @@ function createGraphLoopHarness(options) {
9218
9318
  signal: options.signal ?? options.toolContext.abortSignal,
9219
9319
  executorLocal
9220
9320
  };
9221
- await executor.prime(options.conversationId, local, "user");
9222
- const result = await executor.runUntilYield(options.conversationId);
9321
+ await executor.prime(checkpointKey, local, "user");
9322
+ const result = await executor.runUntilYield(checkpointKey);
9223
9323
  return {
9224
9324
  checkpointNodeId: result.checkpoint.nodeId,
9225
9325
  stepCount: result.stepCount
@@ -9562,6 +9662,7 @@ async function emitRunEvent(event, sink) {
9562
9662
  async function runAgent(agent, options) {
9563
9663
  const modelId = resolveModelId(agent, options);
9564
9664
  const conversationId = options.conversationId ?? `conv_${Date.now()}`;
9665
+ const checkpointKey = conversationId;
9565
9666
  const runId = options.runId ?? generateRunId();
9566
9667
  const turnId = runId;
9567
9668
  const costCollector = new QuickstartRunCostCollector();
@@ -9616,7 +9717,7 @@ async function runAgent(agent, options) {
9616
9717
  };
9617
9718
  await handle.markRunning({ currentNode: "user" });
9618
9719
  try {
9619
- await executor.prime(conversationId, {
9720
+ await executor.prime(checkpointKey, {
9620
9721
  conversationId,
9621
9722
  turnId,
9622
9723
  request: {
@@ -9641,7 +9742,7 @@ async function runAgent(agent, options) {
9641
9742
  return void 0;
9642
9743
  }
9643
9744
  });
9644
- const result = await executor.runUntilYield(conversationId);
9745
+ const result = await executor.runUntilYield(checkpointKey);
9645
9746
  runtimeEvents.push(...result.events);
9646
9747
  for (const event of result.events) {
9647
9748
  if (event.type === "final_answer_chunk") continue;