@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.js CHANGED
@@ -57,6 +57,7 @@ __export(runtime_kernel_exports, {
57
57
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
58
58
  consoleAudit: () => consoleAudit,
59
59
  contextBudgetWarningTemplate: () => contextBudgetWarningTemplate,
60
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
60
61
  countToolCallsInCurrentRequest: () => countToolCallsInCurrentRequest,
61
62
  createCompositeAudit: () => createCompositeAudit,
62
63
  createConsoleAudit: () => createConsoleAudit,
@@ -138,6 +139,7 @@ var Logger = class {
138
139
  constructor(moduleName) {
139
140
  this.moduleName = moduleName;
140
141
  }
142
+ moduleName;
141
143
  debug(message, data) {
142
144
  this.log(0 /* DEBUG */, "debug", message, data);
143
145
  }
@@ -561,6 +563,7 @@ var AgentSpecBudgetPolicy = z.object({
561
563
  });
562
564
  var AgentSpecToolHistoryPolicy = z.object({
563
565
  strategy: z.enum(["per-pair", "per-run", "none"]).optional(),
566
+ retentionMode: z.enum(["drop", "compress"]).optional(),
564
567
  keepLatestToolPairs: z.number().int().nonnegative().optional(),
565
568
  keepLatestRuns: z.number().int().nonnegative().optional(),
566
569
  maxInteractionGroups: z.number().int().nonnegative().optional(),
@@ -683,12 +686,13 @@ var AgentSpecContextPolicy = z.object({
683
686
  var DEFAULT_CONTEXT_POLICY = {
684
687
  profileId: "agent",
685
688
  budget: {
686
- maxTokens: 12e4,
689
+ maxTokens: 232e3,
687
690
  reservedForResponse: 2400,
688
691
  workingMemoryBudgetPercentage: 0.7
689
692
  },
690
693
  toolHistory: {
691
694
  strategy: "per-run",
695
+ retentionMode: "drop",
692
696
  keepLatestToolPairs: 2,
693
697
  keepLatestRuns: 1,
694
698
  maxInteractionGroups: 12,
@@ -1540,6 +1544,17 @@ var logger = new Logger("GraphExecutor");
1540
1544
  function asLocalRecord(local) {
1541
1545
  return local && typeof local === "object" ? { ...local } : {};
1542
1546
  }
1547
+ function readNonEmptyString(value) {
1548
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
1549
+ }
1550
+ function readRuntimeConversationId(state) {
1551
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1552
+ return readNonEmptyString(local?.conversationId);
1553
+ }
1554
+ function readRuntimeTurnId(state) {
1555
+ const local = state?.local && typeof state.local === "object" ? state.local : void 0;
1556
+ return readNonEmptyString(local?.turnId);
1557
+ }
1543
1558
  var GraphExecutor = class {
1544
1559
  constructor(checkpointer, config = {}) {
1545
1560
  this.checkpointer = checkpointer;
@@ -1549,6 +1564,7 @@ var GraphExecutor = class {
1549
1564
  };
1550
1565
  this.telemetryPort = config.telemetryPort ?? noopTelemetry;
1551
1566
  }
1567
+ checkpointer;
1552
1568
  nodes = /* @__PURE__ */ new Map();
1553
1569
  ephemeralLocals = /* @__PURE__ */ new Map();
1554
1570
  config;
@@ -1556,8 +1572,8 @@ var GraphExecutor = class {
1556
1572
  registerNode(node) {
1557
1573
  this.nodes.set(node.id, node);
1558
1574
  }
1559
- async peekCheckpoint(conversationId) {
1560
- return await this.checkpointer.load(conversationId);
1575
+ async peekCheckpoint(checkpointKey) {
1576
+ return await this.checkpointer.load(checkpointKey);
1561
1577
  }
1562
1578
  sanitize(state) {
1563
1579
  const local = asLocalRecord(state.local);
@@ -1569,8 +1585,8 @@ var GraphExecutor = class {
1569
1585
  local
1570
1586
  };
1571
1587
  }
1572
- async prime(conversationId, local, nodeId = "user") {
1573
- this.ephemeralLocals.set(conversationId, { ...local || {} });
1588
+ async prime(checkpointKey, local, nodeId = "user") {
1589
+ this.ephemeralLocals.set(checkpointKey, { ...local || {} });
1574
1590
  const localSansMemory = { ...local || {} };
1575
1591
  if ("memory" in localSansMemory) delete localSansMemory.memory;
1576
1592
  const state = {
@@ -1578,10 +1594,10 @@ var GraphExecutor = class {
1578
1594
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1579
1595
  local: localSansMemory
1580
1596
  };
1581
- await this.checkpointer.save(conversationId, state);
1597
+ await this.checkpointer.save(checkpointKey, state);
1582
1598
  }
1583
- async setNode(conversationId, nodeId, localPatch) {
1584
- const current = await this.checkpointer.load(conversationId) || {
1599
+ async setNode(checkpointKey, nodeId, localPatch) {
1600
+ const current = await this.checkpointer.load(checkpointKey) || {
1585
1601
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1586
1602
  local: {}
1587
1603
  };
@@ -1592,19 +1608,46 @@ var GraphExecutor = class {
1592
1608
  schemaVersion: current.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
1593
1609
  local: mergedLocal
1594
1610
  };
1595
- await this.checkpointer.save(conversationId, next);
1611
+ await this.checkpointer.save(checkpointKey, next);
1596
1612
  }
1597
- async runUntilYield(conversationId) {
1613
+ async runUntilYield(checkpointKey) {
1598
1614
  const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1599
1615
  let lifecyclePhase = "completed";
1616
+ let initialState = null;
1617
+ try {
1618
+ initialState = await this.loadInitialState(checkpointKey);
1619
+ } catch (err) {
1620
+ lifecyclePhase = "failed";
1621
+ this.telemetryPort.emit({
1622
+ kind: "run_lifecycle",
1623
+ runId,
1624
+ phase: "spawned",
1625
+ scope: {}
1626
+ });
1627
+ this.telemetryPort.emit({
1628
+ kind: "run_lifecycle",
1629
+ runId,
1630
+ phase: lifecyclePhase,
1631
+ scope: {}
1632
+ });
1633
+ throw err;
1634
+ }
1635
+ let lifecycleConversationId = readRuntimeConversationId(initialState);
1636
+ let lifecycleTurnId = readRuntimeTurnId(initialState);
1600
1637
  this.telemetryPort.emit({
1601
1638
  kind: "run_lifecycle",
1602
1639
  runId,
1603
1640
  phase: "spawned",
1604
- scope: { conversationId: conversationId || void 0 }
1641
+ scope: {
1642
+ conversationId: lifecycleConversationId,
1643
+ turnId: lifecycleTurnId
1644
+ }
1605
1645
  });
1606
1646
  try {
1607
- return await this.runUntilYieldInternal(conversationId);
1647
+ const result = await this.runUntilYieldInternal(checkpointKey, initialState);
1648
+ lifecycleConversationId = readRuntimeConversationId(result.checkpoint);
1649
+ lifecycleTurnId = readRuntimeTurnId(result.checkpoint);
1650
+ return result;
1608
1651
  } catch (err) {
1609
1652
  lifecyclePhase = err?.name === "AbortError" ? "cancelled" : "failed";
1610
1653
  throw err;
@@ -1613,17 +1656,23 @@ var GraphExecutor = class {
1613
1656
  kind: "run_lifecycle",
1614
1657
  runId,
1615
1658
  phase: lifecyclePhase,
1616
- scope: { conversationId: conversationId || void 0 }
1659
+ scope: {
1660
+ conversationId: lifecycleConversationId,
1661
+ turnId: lifecycleTurnId
1662
+ }
1617
1663
  });
1618
1664
  }
1619
1665
  }
1620
- async runUntilYieldInternal(conversationId) {
1621
- let state = await this.checkpointer.load(conversationId) || {
1666
+ async loadInitialState(checkpointKey) {
1667
+ return await this.checkpointer.load(checkpointKey) || {
1622
1668
  nodeId: "user",
1623
1669
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1624
1670
  local: {}
1625
1671
  };
1626
- const ephemeral = this.ephemeralLocals.get(conversationId) || {};
1672
+ }
1673
+ async runUntilYieldInternal(checkpointKey, initialState) {
1674
+ let state = initialState;
1675
+ const ephemeral = this.ephemeralLocals.get(checkpointKey) || {};
1627
1676
  state = {
1628
1677
  ...state,
1629
1678
  schemaVersion: state.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
@@ -1652,7 +1701,7 @@ var GraphExecutor = class {
1652
1701
  const signalRaw = state.local?.signal;
1653
1702
  if (isAbortSignal2(signalRaw) && signalRaw.aborted) {
1654
1703
  logger.warn("[GraphExecutor] \u6536\u5230 AbortSignal\uFF0C\u7ACB\u5373\u505C\u6B62\u63A8\u7406\u5FAA\u73AF");
1655
- this.ephemeralLocals.delete(conversationId);
1704
+ this.ephemeralLocals.delete(checkpointKey);
1656
1705
  throwAbortError();
1657
1706
  }
1658
1707
  const isLastStep = cycleStepCount >= this.config.maxSteps;
@@ -1700,8 +1749,8 @@ var GraphExecutor = class {
1700
1749
  checkpointCount
1701
1750
  });
1702
1751
  const cp2 = this.sanitize(state);
1703
- await this.checkpointer.save(conversationId, cp2);
1704
- this.ephemeralLocals.delete(conversationId);
1752
+ await this.checkpointer.save(checkpointKey, cp2);
1753
+ this.ephemeralLocals.delete(checkpointKey);
1705
1754
  return { events: allEvents, checkpoint: cp2, stepCount };
1706
1755
  }
1707
1756
  logger.info("[GraphExecutor] \u8282\u70B9\u5207\u6362", {
@@ -1712,18 +1761,18 @@ var GraphExecutor = class {
1712
1761
  });
1713
1762
  const nodeRunStartedAt = Date.now();
1714
1763
  const nodeIdForTelemetry = state.nodeId;
1764
+ const conversationIdForTelemetry = readRuntimeConversationId(state);
1715
1765
  let result;
1716
1766
  try {
1717
1767
  result = await node.run(state);
1718
1768
  } finally {
1719
- const turnIdForTelemetry = typeof state.local?.turnId === "string" ? state.local.turnId : void 0;
1720
1769
  this.telemetryPort.emit({
1721
1770
  kind: "graph_node",
1722
1771
  nodeId: nodeIdForTelemetry,
1723
1772
  durationMs: Date.now() - nodeRunStartedAt,
1724
1773
  scope: {
1725
- conversationId: conversationId || void 0,
1726
- turnId: turnIdForTelemetry
1774
+ conversationId: conversationIdForTelemetry,
1775
+ turnId: readRuntimeTurnId(state)
1727
1776
  }
1728
1777
  });
1729
1778
  }
@@ -1762,7 +1811,7 @@ var GraphExecutor = class {
1762
1811
  });
1763
1812
  state = { ...state, nodeId: nextNodeId };
1764
1813
  const cp2 = this.sanitize(state);
1765
- await this.checkpointer.save(conversationId, cp2);
1814
+ await this.checkpointer.save(checkpointKey, cp2);
1766
1815
  continue;
1767
1816
  }
1768
1817
  if (result.kind === "yield") {
@@ -1773,7 +1822,7 @@ var GraphExecutor = class {
1773
1822
  checkpointCount
1774
1823
  });
1775
1824
  const cp2 = this.sanitize(state);
1776
- await this.checkpointer.save(conversationId, cp2);
1825
+ await this.checkpointer.save(checkpointKey, cp2);
1777
1826
  return { events: allEvents, checkpoint: cp2, stepCount };
1778
1827
  }
1779
1828
  if (result.kind === "pause") {
@@ -1784,7 +1833,7 @@ var GraphExecutor = class {
1784
1833
  checkpointCount
1785
1834
  });
1786
1835
  const cp2 = this.sanitize(state);
1787
- await this.checkpointer.save(conversationId, cp2);
1836
+ await this.checkpointer.save(checkpointKey, cp2);
1788
1837
  return { events: allEvents, checkpoint: cp2, stepCount };
1789
1838
  }
1790
1839
  }
@@ -1795,8 +1844,8 @@ var GraphExecutor = class {
1795
1844
  checkpointCount
1796
1845
  });
1797
1846
  const cp = this.sanitize(state);
1798
- await this.checkpointer.save(conversationId, cp);
1799
- this.ephemeralLocals.delete(conversationId);
1847
+ await this.checkpointer.save(checkpointKey, cp);
1848
+ this.ephemeralLocals.delete(checkpointKey);
1800
1849
  return { events: allEvents, checkpoint: cp, stepCount };
1801
1850
  }
1802
1851
  };
@@ -1993,15 +2042,15 @@ function splitConcatenatedJsonObjects(input) {
1993
2042
  }
1994
2043
 
1995
2044
  // src/runtime-kernel/graph-engine/tick-pipeline/helpers.ts
1996
- function readNonEmptyString(value) {
2045
+ function readNonEmptyString2(value) {
1997
2046
  if (typeof value !== "string") return void 0;
1998
2047
  const trimmed = value.trim();
1999
2048
  return trimmed.length > 0 ? trimmed : void 0;
2000
2049
  }
2001
2050
  function resolveConversationIdForRuntimeEvents(toolContext) {
2002
- const fromCamel = readNonEmptyString(toolContext?.conversationId);
2051
+ const fromCamel = readNonEmptyString2(toolContext?.conversationId);
2003
2052
  if (fromCamel) return fromCamel;
2004
- const fromSnake = toolContext ? readNonEmptyString(toolContext["conversation_id"]) : void 0;
2053
+ const fromSnake = toolContext ? readNonEmptyString2(toolContext["conversation_id"]) : void 0;
2005
2054
  if (fromSnake) return fromSnake;
2006
2055
  return generateMessageId();
2007
2056
  }
@@ -2383,7 +2432,7 @@ var runModelLockMiddleware = async (ctx, stage, next) => {
2383
2432
  if (stage.id !== "execute_llm") {
2384
2433
  return;
2385
2434
  }
2386
- const normalized = readNonEmptyString(ctx.cloudQuotaFallbackAppliedModelId);
2435
+ const normalized = readNonEmptyString2(ctx.cloudQuotaFallbackAppliedModelId);
2387
2436
  if (!normalized) {
2388
2437
  return;
2389
2438
  }
@@ -2984,7 +3033,7 @@ function createExecuteLlmStage(dependencies) {
2984
3033
  streamEventHandler,
2985
3034
  ctx.signal,
2986
3035
  (fallbackModelId) => {
2987
- ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString(fallbackModelId);
3036
+ ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString2(fallbackModelId);
2988
3037
  },
2989
3038
  (info) => {
2990
3039
  ctx.modelFallbackAudit = info;
@@ -3028,7 +3077,7 @@ function createPrepareCallStage(dependencies) {
3028
3077
  return {
3029
3078
  id: "prepare_call",
3030
3079
  async run(ctx) {
3031
- const lockedRunModelId = readNonEmptyString(ctx.executorLocal?.runLockedModelId);
3080
+ const lockedRunModelId = readNonEmptyString2(ctx.executorLocal?.runLockedModelId);
3032
3081
  const requestedModelId = lockedRunModelId ?? ctx.request.model_id;
3033
3082
  ctx.modelId = dependencies.modelResolver.resolveModelId(requestedModelId);
3034
3083
  await emitAuditEnvelope(ctx.audit, {
@@ -3100,7 +3149,7 @@ var GraphAgentExecutor = class {
3100
3149
  this.llmCaller = dependencies.llmCaller;
3101
3150
  this.toolRuntime = dependencies.toolRuntime;
3102
3151
  this.contextBuilder = dependencies.contextBuilder;
3103
- this.cloudQuotaFallbackModelId = readNonEmptyString(dependencies.cloudQuotaFallbackModelId);
3152
+ this.cloudQuotaFallbackModelId = readNonEmptyString2(dependencies.cloudQuotaFallbackModelId);
3104
3153
  this.modelCatalog = dependencies.modelCatalog ?? createEmptyModelCatalog();
3105
3154
  this.modelResolver = dependencies.modelResolver ?? new ModelResolver({
3106
3155
  modelCatalog: this.modelCatalog
@@ -3148,7 +3197,7 @@ var GraphAgentExecutor = class {
3148
3197
  llmMessages: [],
3149
3198
  mode: input.request.mode === "chat" ? "chat" : "agent",
3150
3199
  conversationId: resolveConversationIdForRuntimeEvents(input.toolContext),
3151
- turnId: readNonEmptyString(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3200
+ turnId: readNonEmptyString2(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3152
3201
  telemetry: this.telemetryPort,
3153
3202
  audit: this.auditPort
3154
3203
  };
@@ -3198,18 +3247,18 @@ function isSummarizationCallbacks(value) {
3198
3247
  function isGraphSseSink(value) {
3199
3248
  return typeof value === "function";
3200
3249
  }
3201
- function readNonEmptyString2(value) {
3250
+ function readNonEmptyString3(value) {
3202
3251
  if (typeof value !== "string") return void 0;
3203
3252
  const trimmed = value.trim();
3204
3253
  return trimmed.length > 0 ? trimmed : void 0;
3205
3254
  }
3206
3255
  function readGraphAgentLocal(local) {
3207
3256
  const source = local ?? {};
3208
- const answerId = readNonEmptyString2(source.answerId);
3257
+ const answerId = readNonEmptyString3(source.answerId);
3209
3258
  const chunkSeq = Number.isInteger(source.chunkSeq) ? Number(source.chunkSeq) : 0;
3210
3259
  return {
3211
- conversationId: readNonEmptyString2(source.conversationId) ?? "",
3212
- turnId: readNonEmptyString2(source.turnId),
3260
+ conversationId: readNonEmptyString3(source.conversationId) ?? "",
3261
+ turnId: readNonEmptyString3(source.turnId),
3213
3262
  request: isAgentInvocationRequest(source.request) ? source.request : void 0,
3214
3263
  toolContext: isToolExecutionContext(source.toolContext) ? source.toolContext : void 0,
3215
3264
  history: isRuntimeEventArray(source.history) ? source.history : [],
@@ -3974,7 +4023,7 @@ var LlmNode = class {
3974
4023
  function isRecord8(value) {
3975
4024
  return typeof value === "object" && value !== null && !Array.isArray(value);
3976
4025
  }
3977
- function readNonEmptyString3(value) {
4026
+ function readNonEmptyString4(value) {
3978
4027
  if (typeof value !== "string") {
3979
4028
  return void 0;
3980
4029
  }
@@ -3996,7 +4045,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3996
4045
  return void 0;
3997
4046
  }
3998
4047
  if (toolName === "write_report") {
3999
- const report = readNonEmptyString3(data.report);
4048
+ const report = readNonEmptyString4(data.report);
4000
4049
  if (!report) {
4001
4050
  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");
4002
4051
  }
@@ -4006,7 +4055,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
4006
4055
  if (data.success !== true) {
4007
4056
  return void 0;
4008
4057
  }
4009
- const finalAnswer = readNonEmptyString3(data.final_answer);
4058
+ const finalAnswer = readNonEmptyString4(data.final_answer);
4010
4059
  if (!finalAnswer) {
4011
4060
  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");
4012
4061
  }
@@ -4556,6 +4605,31 @@ function ensureToolContextRuntimeCapability(params) {
4556
4605
  function getToolContextRuntimeBinding(context) {
4557
4606
  return readBinding(context);
4558
4607
  }
4608
+ function copyToolContextRuntimeCapability(source, target) {
4609
+ const sourceBinding = readBinding(source);
4610
+ if (!sourceBinding) {
4611
+ return void 0;
4612
+ }
4613
+ const existingTargetBinding = readBinding(target);
4614
+ if (existingTargetBinding) {
4615
+ exposeCompatibilitySurface(target, existingTargetBinding);
4616
+ return existingTargetBinding;
4617
+ }
4618
+ const targetBinding = createRuntimeBinding({
4619
+ context: target,
4620
+ persistedHistory: () => sourceBinding.getPersistedHistoryEvents(),
4621
+ workingHistory: () => sourceBinding.getWorkingHistoryEvents(),
4622
+ executionMeta: sourceBinding.readExecutionMeta()
4623
+ });
4624
+ Object.defineProperty(target, TOOL_CONTEXT_RUNTIME_BINDING_KEY, {
4625
+ value: targetBinding,
4626
+ enumerable: false,
4627
+ configurable: true,
4628
+ writable: false
4629
+ });
4630
+ exposeCompatibilitySurface(target, targetBinding);
4631
+ return targetBinding;
4632
+ }
4559
4633
  function readToolContextWorkingHistory(context) {
4560
4634
  if (context.conversationView) {
4561
4635
  return context.conversationView.getWorkingHistoryEvents();
@@ -5407,12 +5481,12 @@ function asRecord(value) {
5407
5481
  }
5408
5482
  return value;
5409
5483
  }
5410
- function summarizeCheckpoint(conversationId, state, savedAt) {
5484
+ function summarizeCheckpoint(checkpointKey, state, savedAt) {
5411
5485
  const local = asRecord(state.local);
5412
5486
  const executorLocal = asRecord(local?.executorLocal);
5413
5487
  const pendingToolCalls = local?.pendingToolCalls;
5414
5488
  return {
5415
- conversationId,
5489
+ checkpointKey,
5416
5490
  schemaVersion: state.schemaVersion ?? 1,
5417
5491
  savedAt,
5418
5492
  currentNode: state.nodeId,
@@ -5431,25 +5505,25 @@ var MemoryCheckpointer = class {
5431
5505
  local: state.local && typeof state.local === "object" && !Array.isArray(state.local) ? { ...state.local } : state.local
5432
5506
  };
5433
5507
  }
5434
- async load(conversationId) {
5435
- const entry = this.store.get(conversationId);
5508
+ async load(checkpointKey) {
5509
+ const entry = this.store.get(checkpointKey);
5436
5510
  return entry ? this.cloneState(entry.state) : null;
5437
5511
  }
5438
- async save(conversationId, state) {
5439
- this.store.set(conversationId, {
5512
+ async save(checkpointKey, state) {
5513
+ this.store.set(checkpointKey, {
5440
5514
  state: this.cloneState(state),
5441
5515
  savedAt: Date.now()
5442
5516
  });
5443
5517
  }
5444
- async clear(conversationId) {
5445
- this.store.delete(conversationId);
5518
+ async clear(checkpointKey) {
5519
+ this.store.delete(checkpointKey);
5446
5520
  }
5447
- async peekMeta(conversationId) {
5448
- const entry = this.store.get(conversationId);
5449
- return entry ? summarizeCheckpoint(conversationId, entry.state, entry.savedAt) : null;
5521
+ async peekMeta(checkpointKey) {
5522
+ const entry = this.store.get(checkpointKey);
5523
+ return entry ? summarizeCheckpoint(checkpointKey, entry.state, entry.savedAt) : null;
5450
5524
  }
5451
5525
  async list(filter = {}) {
5452
- 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);
5526
+ 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);
5453
5527
  if (filter.limit === void 0) {
5454
5528
  return summaries;
5455
5529
  }
@@ -5521,6 +5595,7 @@ __export(tools_exports, {
5521
5595
  CommonParameterTypes: () => CommonParameterTypes,
5522
5596
  ContextCheckpointTool: () => ContextCheckpointTool,
5523
5597
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
5598
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
5524
5599
  createContextCheckpointTool: () => createContextCheckpointTool,
5525
5600
  ensureToolContextRuntimeCapability: () => ensureToolContextRuntimeCapability,
5526
5601
  findCachedToolOutputByIdempotencyKey: () => findCachedToolOutputByIdempotencyKey,
@@ -5714,7 +5789,7 @@ function createContextCheckpointTool(options) {
5714
5789
  function isRecord15(value) {
5715
5790
  return !!value && typeof value === "object" && !Array.isArray(value);
5716
5791
  }
5717
- function readNonEmptyString4(value) {
5792
+ function readNonEmptyString5(value) {
5718
5793
  if (typeof value !== "string") {
5719
5794
  return void 0;
5720
5795
  }
@@ -5734,13 +5809,13 @@ function readToolContextUserQuery(context) {
5734
5809
  if (!context) {
5735
5810
  return void 0;
5736
5811
  }
5737
- return readNonEmptyString4(context["user_query"]);
5812
+ return readNonEmptyString5(context["user_query"]);
5738
5813
  }
5739
5814
  function readToolContextModelId(context) {
5740
5815
  if (!context) {
5741
5816
  return void 0;
5742
5817
  }
5743
- return readNonEmptyString4(context["modelId"]);
5818
+ return readNonEmptyString5(context["modelId"]);
5744
5819
  }
5745
5820
  function readToolContextRunContext(context) {
5746
5821
  if (!context) {
@@ -7448,6 +7523,7 @@ var DefaultTokenizerPort = class {
7448
7523
  constructor(config = {}) {
7449
7524
  this.config = config;
7450
7525
  }
7526
+ config;
7451
7527
  estimateText(text, _modelId) {
7452
7528
  return TokenCalculator.estimateTokens(text, {
7453
7529
  encoding: this.config.encoding,
@@ -7475,7 +7551,6 @@ __export(child_runs_exports, {
7475
7551
 
7476
7552
  // src/runtime-kernel/child-runs/childToolContext.ts
7477
7553
  function createChildRunToolContext(params) {
7478
- const inheritedConversationId = typeof params.parentToolContext.conversationId === "string" && params.parentToolContext.conversationId.trim().length > 0 ? params.parentToolContext.conversationId.trim() : void 0;
7479
7554
  const inheritedContext = stripRuntimeReservedToolContextPatch(params.parentToolContext);
7480
7555
  const childToolContext = {
7481
7556
  ...inheritedContext,
@@ -7487,7 +7562,7 @@ function createChildRunToolContext(params) {
7487
7562
  persistedHistory: params.seedHistory,
7488
7563
  workingHistory: params.seedHistory,
7489
7564
  executionMeta: {
7490
- conversationId: inheritedConversationId ?? params.internalConversationId,
7565
+ conversationId: params.conversationId,
7491
7566
  turnId: params.turnId,
7492
7567
  runId: params.runId,
7493
7568
  parentRunId: params.parentRunId
@@ -7589,6 +7664,8 @@ var FinalAnswerCollector = class {
7589
7664
  this.conversationId = conversationId;
7590
7665
  this.turnId = turnId;
7591
7666
  }
7667
+ conversationId;
7668
+ turnId;
7592
7669
  answerId;
7593
7670
  chunks = [];
7594
7671
  chunkCount = 0;
@@ -7805,7 +7882,7 @@ function readCheckpointHistory(checkpoint) {
7805
7882
  });
7806
7883
  }
7807
7884
  async function recoverChildRunEventsFromCheckpoint(params) {
7808
- const checkpoint = await params.checkpointer.load(params.conversationId);
7885
+ const checkpoint = await params.checkpointer.load(params.checkpointKey);
7809
7886
  const history = readCheckpointHistory(checkpoint);
7810
7887
  if (history.length === 0) {
7811
7888
  return [];
@@ -7813,7 +7890,7 @@ async function recoverChildRunEventsFromCheckpoint(params) {
7813
7890
  if (hasSeedHistoryPrefix(history, params.seedHistory)) {
7814
7891
  return history.slice(params.seedHistory.length);
7815
7892
  }
7816
- return history.filter((event) => event.conversation_id === params.internalConversationId);
7893
+ return history.filter((event) => event.conversation_id === params.childConversationId);
7817
7894
  }
7818
7895
 
7819
7896
  // src/runtime-kernel/child-runs/childRunInvoker.ts
@@ -7842,6 +7919,7 @@ var ChildRunInvoker = class {
7842
7919
  agentConfig,
7843
7920
  userMessage,
7844
7921
  parentToolContext,
7922
+ conversationId,
7845
7923
  runId,
7846
7924
  parentRunId,
7847
7925
  subrunTracePublisher,
@@ -7850,12 +7928,18 @@ var ChildRunInvoker = class {
7850
7928
  modelId,
7851
7929
  abortSignal
7852
7930
  } = config;
7853
- const internalConversationId = `internal_${generateMessageId()}`;
7931
+ const internalCheckpointKey = `internal_${generateMessageId()}`;
7932
+ const runtimeConversationId = resolveChildRunConversationId({
7933
+ explicitConversationId: conversationId,
7934
+ parentToolContext,
7935
+ fallbackConversationId: internalCheckpointKey
7936
+ });
7854
7937
  const turnId = `turn_${Date.now()}`;
7855
- const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalConversationId;
7938
+ const childRunId = typeof runId === "string" && runId.trim().length > 0 ? runId.trim() : internalCheckpointKey;
7856
7939
  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;
7857
7940
  logger13.info(`\u542F\u52A8 child-run: ${agentConfig.id}`, {
7858
- conversationId: internalConversationId,
7941
+ conversationId: runtimeConversationId,
7942
+ checkpointKey: internalCheckpointKey,
7859
7943
  maxSteps,
7860
7944
  userMessage: userMessage.slice(0, 100) + (userMessage.length > 100 ? "..." : "")
7861
7945
  });
@@ -7916,7 +8000,7 @@ var ChildRunInvoker = class {
7916
8000
  const seedHistory = Array.isArray(seedHistoryEvents) ? seedHistoryEvents : [];
7917
8001
  const childToolContext = createChildRunToolContext({
7918
8002
  parentToolContext,
7919
- internalConversationId,
8003
+ conversationId: runtimeConversationId,
7920
8004
  turnId,
7921
8005
  runId: childRunId,
7922
8006
  parentRunId: resolvedParentRunId,
@@ -7925,13 +8009,13 @@ var ChildRunInvoker = class {
7925
8009
  });
7926
8010
  const subrunSseSink = subrunTracePublisher ? createChildRunTraceSink({
7927
8011
  publisher: subrunTracePublisher,
7928
- conversationId: internalConversationId,
8012
+ conversationId: runtimeConversationId,
7929
8013
  turnId
7930
8014
  }) : void 0;
7931
8015
  const initialLocal = {
7932
8016
  request,
7933
8017
  history: seedHistory,
7934
- conversationId: internalConversationId,
8018
+ conversationId: runtimeConversationId,
7935
8019
  turnId,
7936
8020
  toolContext: childToolContext,
7937
8021
  ...abortSignal ? { signal: abortSignal } : {},
@@ -7939,7 +8023,7 @@ var ChildRunInvoker = class {
7939
8023
  ...subrunSseSink ? { sseSink: subrunSseSink } : {},
7940
8024
  systemPrompt
7941
8025
  };
7942
- await graphExecutor.prime(internalConversationId, initialLocal, "llm");
8026
+ await graphExecutor.prime(internalCheckpointKey, initialLocal, "llm");
7943
8027
  const allEvents = [];
7944
8028
  let stepCount = 0;
7945
8029
  let finalAnswer;
@@ -7951,7 +8035,7 @@ var ChildRunInvoker = class {
7951
8035
  err.name = "AbortError";
7952
8036
  throw err;
7953
8037
  }
7954
- const result = await graphExecutor.runUntilYield(internalConversationId);
8038
+ const result = await graphExecutor.runUntilYield(internalCheckpointKey);
7955
8039
  appendUniqueEvents(allEvents, result.events);
7956
8040
  stepCount = result.stepCount;
7957
8041
  if (subrunSseSink && typeof subrunSseSink.finalize === "function") {
@@ -7985,8 +8069,8 @@ var ChildRunInvoker = class {
7985
8069
  }
7986
8070
  const recoveredEvents = await recoverChildRunEventsFromCheckpoint({
7987
8071
  checkpointer,
7988
- conversationId: internalConversationId,
7989
- internalConversationId,
8072
+ checkpointKey: internalCheckpointKey,
8073
+ childConversationId: runtimeConversationId,
7990
8074
  seedHistory
7991
8075
  });
7992
8076
  appendUniqueEvents(allEvents, recoveredEvents);
@@ -8003,7 +8087,7 @@ var ChildRunInvoker = class {
8003
8087
  stack: err.stack
8004
8088
  } : { error: String(err) });
8005
8089
  }
8006
- await checkpointer.clear(internalConversationId);
8090
+ await checkpointer.clear(internalCheckpointKey);
8007
8091
  return {
8008
8092
  success: !error,
8009
8093
  runId: childRunId,
@@ -8016,6 +8100,16 @@ var ChildRunInvoker = class {
8016
8100
  };
8017
8101
  }
8018
8102
  };
8103
+ function readNonEmptyString6(value) {
8104
+ if (typeof value !== "string") {
8105
+ return void 0;
8106
+ }
8107
+ const trimmed = value.trim();
8108
+ return trimmed.length > 0 ? trimmed : void 0;
8109
+ }
8110
+ function resolveChildRunConversationId(params) {
8111
+ return readNonEmptyString6(params.explicitConversationId) ?? readNonEmptyString6(params.parentToolContext.conversationId) ?? params.fallbackConversationId;
8112
+ }
8019
8113
  function resolveChildRunSystemReminderPolicy(agentConfig) {
8020
8114
  const configured = agentConfig.systemReminderPolicy ?? agentConfig.contextPolicy?.systemReminder;
8021
8115
  const threshold = agentConfig.stepPolicy?.lastStepsHintThreshold;
@@ -8206,7 +8300,7 @@ function cloneRunRecord(record) {
8206
8300
  ...record,
8207
8301
  iterationBudget: record.iterationBudget ? { ...record.iterationBudget } : void 0,
8208
8302
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0,
8209
- metadata: record.metadata ? { ...record.metadata } : void 0
8303
+ metadata: record.metadata ? structuredClone(record.metadata) : void 0
8210
8304
  };
8211
8305
  }
8212
8306
  function matchesStatus(candidate, filter) {
@@ -8618,7 +8712,7 @@ function isTerminalStatus(status) {
8618
8712
  return status === "completed" || status === "failed" || status === "cancelled";
8619
8713
  }
8620
8714
  function cloneMetadata(metadata) {
8621
- return metadata ? { ...metadata } : void 0;
8715
+ return metadata ? structuredClone(metadata) : void 0;
8622
8716
  }
8623
8717
  function recordToSnapshot(record) {
8624
8718
  return {
@@ -8705,7 +8799,7 @@ var DefaultRunSupervisor = class {
8705
8799
  startedAt,
8706
8800
  updatedAt: startedAt,
8707
8801
  iterationBudget: spec.iterationBudget ? { ...spec.iterationBudget } : void 0,
8708
- metadata: spec.metadata ? { ...spec.metadata } : void 0
8802
+ metadata: cloneMetadata(spec.metadata)
8709
8803
  };
8710
8804
  await this.registryStore.save(record);
8711
8805
  const handle = new DefaultRunHandle({
@@ -8879,12 +8973,13 @@ var DefaultRunSupervisor = class {
8879
8973
  }
8880
8974
  try {
8881
8975
  await handle.markRunning({ currentNode: "detached" });
8976
+ const registeredRecord = await this.registryStore.load(handle.runId);
8882
8977
  const executorOutcome = await this.executor.execute({
8883
8978
  runId: handle.runId,
8884
- parentRunId: spec.parentRunId,
8885
- conversationId: spec.conversationId,
8886
- agentSpec: spec.agentSpec,
8887
- request: spec.request,
8979
+ parentRunId: handle.parentRunId,
8980
+ conversationId: registeredRecord?.conversationId ?? spec.conversationId,
8981
+ agentSpec: await handle.spec(),
8982
+ request: await handle.request(),
8888
8983
  signal: handle.signal,
8889
8984
  eventBus: spec.eventBus,
8890
8985
  eventStore: spec.eventStore,
@@ -8893,7 +8988,7 @@ var DefaultRunSupervisor = class {
8893
8988
  contextFences: spec.contextFences,
8894
8989
  wakeSource: spec.wakeSource,
8895
8990
  ephemeral: spec.ephemeral,
8896
- metadata: spec.metadata
8991
+ metadata: cloneMetadata(registeredRecord?.metadata ?? spec.metadata)
8897
8992
  });
8898
8993
  const outcome = await this.persistExecutorOutcome(handle, executorOutcome);
8899
8994
  this.notifyTerminalWaiters(outcome);
@@ -8957,10 +9052,14 @@ var DefaultRunSupervisor = class {
8957
9052
  await this.registryStore.save(record);
8958
9053
  }
8959
9054
  const completedAt = executorOutcome?.completedAt ?? this.now();
9055
+ const fallbackMeta = record ? void 0 : await handle.meta();
8960
9056
  const outcome = recordToTerminalOutcome(record ?? {
8961
9057
  runId: handle.runId,
8962
9058
  parentRunId: handle.parentRunId,
8963
- status: executorOutcome?.status ?? "completed"}, completedAt);
9059
+ conversationId: fallbackMeta?.conversationId ?? "",
9060
+ agentSpecId: fallbackMeta?.agentSpecId,
9061
+ status: executorOutcome?.status ?? "completed",
9062
+ startedAt: fallbackMeta?.startedAt ?? completedAt}, completedAt);
8964
9063
  const nextOutcome = {
8965
9064
  ...outcome,
8966
9065
  metadata: {
@@ -9188,6 +9287,7 @@ function createGraphLoopHarness(options) {
9188
9287
  };
9189
9288
  return {
9190
9289
  async run() {
9290
+ const checkpointKey = options.conversationId;
9191
9291
  const executor = createDefaultGraphExecutor({
9192
9292
  llmNode: options.createLlmNode({
9193
9293
  llmCaller: options.llmCaller,
@@ -9216,8 +9316,8 @@ function createGraphLoopHarness(options) {
9216
9316
  signal: options.signal ?? options.toolContext.abortSignal,
9217
9317
  executorLocal
9218
9318
  };
9219
- await executor.prime(options.conversationId, local, "user");
9220
- const result = await executor.runUntilYield(options.conversationId);
9319
+ await executor.prime(checkpointKey, local, "user");
9320
+ const result = await executor.runUntilYield(checkpointKey);
9221
9321
  return {
9222
9322
  checkpointNodeId: result.checkpoint.nodeId,
9223
9323
  stepCount: result.stepCount
@@ -9560,6 +9660,7 @@ async function emitRunEvent(event, sink) {
9560
9660
  async function runAgent(agent, options) {
9561
9661
  const modelId = resolveModelId(agent, options);
9562
9662
  const conversationId = options.conversationId ?? `conv_${Date.now()}`;
9663
+ const checkpointKey = conversationId;
9563
9664
  const runId = options.runId ?? generateRunId();
9564
9665
  const turnId = runId;
9565
9666
  const costCollector = new QuickstartRunCostCollector();
@@ -9614,7 +9715,7 @@ async function runAgent(agent, options) {
9614
9715
  };
9615
9716
  await handle.markRunning({ currentNode: "user" });
9616
9717
  try {
9617
- await executor.prime(conversationId, {
9718
+ await executor.prime(checkpointKey, {
9618
9719
  conversationId,
9619
9720
  turnId,
9620
9721
  request: {
@@ -9639,7 +9740,7 @@ async function runAgent(agent, options) {
9639
9740
  return void 0;
9640
9741
  }
9641
9742
  });
9642
- const result = await executor.runUntilYield(conversationId);
9743
+ const result = await executor.runUntilYield(checkpointKey);
9643
9744
  runtimeEvents.push(...result.events);
9644
9745
  for (const event of result.events) {
9645
9746
  if (event.type === "final_answer_chunk") continue;