@linnlabs/linnkit 0.8.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 (83) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/bin/linnkit.cjs +7 -0
  5. package/dist/{agentSpec-EkmviZjy.d.cts → agentSpec-Du4Iye0q.d.cts} +16 -1
  6. package/dist/{agentSpec-EkmviZjy.d.ts → agentSpec-Du4Iye0q.d.ts} +16 -1
  7. package/dist/cli.cjs +234 -91
  8. package/dist/cli.cjs.map +1 -1
  9. package/dist/cli.js +234 -91
  10. package/dist/cli.js.map +1 -1
  11. package/dist/context-manager.cjs +230 -32
  12. package/dist/context-manager.cjs.map +1 -1
  13. package/dist/context-manager.d.cts +52 -15
  14. package/dist/context-manager.d.ts +52 -15
  15. package/dist/context-manager.js +230 -33
  16. package/dist/context-manager.js.map +1 -1
  17. package/dist/{context-trace-HE2qY5Q-.d.cts → context-trace-BHKDS-eq.d.cts} +2 -2
  18. package/dist/{context-trace-DRi5M4lX.d.ts → context-trace-CHbqHmyE.d.ts} +2 -2
  19. package/dist/contracts.cjs +3 -1
  20. package/dist/contracts.cjs.map +1 -1
  21. package/dist/contracts.d.cts +3 -3
  22. package/dist/contracts.d.ts +3 -3
  23. package/dist/contracts.js +3 -1
  24. package/dist/contracts.js.map +1 -1
  25. package/dist/{defaultGraphExecutor-BBswR8wn.d.ts → defaultGraphExecutor-B29_qTHy.d.ts} +16 -15
  26. package/dist/{defaultGraphExecutor-BIjJj7WF.d.cts → defaultGraphExecutor-C2E59v_R.d.cts} +16 -15
  27. package/dist/{index-Cm-JbzTH.d.cts → index-BAaUP9yU.d.cts} +38 -15
  28. package/dist/{index-DRBWi1fy.d.ts → index-BaVpVNi2.d.ts} +38 -15
  29. package/dist/{index-DO4dQgf2.d.cts → index-BnYCS8Zg.d.cts} +2 -2
  30. package/dist/{index-CJeWHopy.d.ts → index-C0DAjsdX.d.ts} +2 -2
  31. package/dist/{index-Dl5PLgAv.d.cts → index-CKQzzZ5Y.d.cts} +2 -2
  32. package/dist/{index-CHqwkvGp.d.ts → index-D0mKxTR5.d.ts} +2 -2
  33. package/dist/index.cjs +327 -110
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +10 -10
  36. package/dist/index.d.ts +10 -10
  37. package/dist/index.js +327 -110
  38. package/dist/index.js.map +1 -1
  39. package/dist/{ports-DnLuKfpE.d.ts → ports-DpPTFhSd.d.ts} +2 -2
  40. package/dist/{ports-DaatKJXp.d.cts → ports-s-tSp3sB.d.cts} +2 -2
  41. package/dist/quickstart.cjs +232 -88
  42. package/dist/quickstart.cjs.map +1 -1
  43. package/dist/quickstart.d.cts +7 -7
  44. package/dist/quickstart.d.ts +7 -7
  45. package/dist/quickstart.js +232 -88
  46. package/dist/quickstart.js.map +1 -1
  47. package/dist/{runAgent-CPj_9e58.d.ts → runAgent-C6F-399C.d.ts} +5 -5
  48. package/dist/{runAgent-HYKlXbVr.d.cts → runAgent-ilEj66Ik.d.cts} +5 -5
  49. package/dist/{runHandle-D3gPsD7B.d.cts → runHandle-BNOqS-Bl.d.cts} +3 -3
  50. package/dist/{runHandle-CyXvzgzk.d.ts → runHandle-BdLXOFqF.d.ts} +3 -3
  51. package/dist/runtime-kernel/events.cjs +1 -0
  52. package/dist/runtime-kernel/events.cjs.map +1 -1
  53. package/dist/runtime-kernel/events.d.cts +4 -4
  54. package/dist/runtime-kernel/events.d.ts +4 -4
  55. package/dist/runtime-kernel/events.js +1 -0
  56. package/dist/runtime-kernel/events.js.map +1 -1
  57. package/dist/runtime-kernel.cjs +318 -103
  58. package/dist/runtime-kernel.cjs.map +1 -1
  59. package/dist/runtime-kernel.d.cts +8 -8
  60. package/dist/runtime-kernel.d.ts +8 -8
  61. package/dist/runtime-kernel.js +315 -104
  62. package/dist/runtime-kernel.js.map +1 -1
  63. package/dist/testkit.cjs +331 -116
  64. package/dist/testkit.cjs.map +1 -1
  65. package/dist/testkit.d.cts +8 -8
  66. package/dist/testkit.d.ts +8 -8
  67. package/dist/testkit.js +331 -116
  68. package/dist/testkit.js.map +1 -1
  69. package/dist/{todo-B1PmDlp3.d.cts → todo-Ca8llpRQ.d.cts} +1 -1
  70. package/dist/{todo-B1PmDlp3.d.ts → todo-Ca8llpRQ.d.ts} +1 -1
  71. package/dist/{toolContracts-CLkQmhTG.d.cts → toolContracts-Bm3EZ1UM.d.cts} +13 -2
  72. package/dist/{toolContracts-Blll0241.d.ts → toolContracts-f8lzZBNa.d.ts} +13 -2
  73. package/docs/integration/README.md +1 -1
  74. package/docs/integration/agent-registration-guide.md +1 -1
  75. package/docs/integration/child-runs.md +4 -1
  76. package/docs/integration/context-engineering.md +30 -15
  77. package/docs/integration/context-fences.md +32 -3
  78. package/docs/integration/llm-provider.md +1 -1
  79. package/docs/integration/persistence.md +1 -0
  80. package/docs/integration/run-supervisor.md +3 -0
  81. package/docs/integration/tool-development-guide.md +7 -5
  82. package/docs/integration/tool-history.md +43 -17
  83. package/package.json +5 -4
package/dist/index.cjs CHANGED
@@ -48,14 +48,18 @@ __export(runtime_kernel_exports, {
48
48
  UserNode: () => UserNode,
49
49
  WaitUserNode: () => WaitUserNode,
50
50
  agentHasToolTrigger: () => agentHasToolTrigger,
51
+ appendStreamingProviderReasoningDetails: () => appendStreamingProviderReasoningDetails,
51
52
  applySystemReminders: () => applySystemReminders,
52
53
  audit: () => audit_exports,
53
54
  budgetWarningTrigger: () => budgetWarningTrigger,
54
55
  childRunTrace: () => child_run_trace_exports,
55
56
  childRuns: () => child_runs_exports,
57
+ compactProviderReasoningDetails: () => compactProviderReasoningDetails,
58
+ compactReasoningDetailsInValue: () => compactReasoningDetailsInValue,
56
59
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
57
60
  consoleAudit: () => consoleAudit,
58
61
  contextBudgetWarningTemplate: () => contextBudgetWarningTemplate,
62
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
59
63
  countToolCallsInCurrentRequest: () => countToolCallsInCurrentRequest,
60
64
  createCompositeAudit: () => createCompositeAudit,
61
65
  createConsoleAudit: () => createConsoleAudit,
@@ -561,6 +565,7 @@ var AgentSpecBudgetPolicy = zod.z.object({
561
565
  });
562
566
  var AgentSpecToolHistoryPolicy = zod.z.object({
563
567
  strategy: zod.z.enum(["per-pair", "per-run", "none"]).optional(),
568
+ retentionMode: zod.z.enum(["drop", "compress"]).optional(),
564
569
  keepLatestToolPairs: zod.z.number().int().nonnegative().optional(),
565
570
  keepLatestRuns: zod.z.number().int().nonnegative().optional(),
566
571
  maxInteractionGroups: zod.z.number().int().nonnegative().optional(),
@@ -683,12 +688,13 @@ var AgentSpecContextPolicy = zod.z.object({
683
688
  var DEFAULT_CONTEXT_POLICY = {
684
689
  profileId: "agent",
685
690
  budget: {
686
- maxTokens: 12e4,
691
+ maxTokens: 232e3,
687
692
  reservedForResponse: 2400,
688
693
  workingMemoryBudgetPercentage: 0.7
689
694
  },
690
695
  toolHistory: {
691
696
  strategy: "per-run",
697
+ retentionMode: "drop",
692
698
  keepLatestToolPairs: 2,
693
699
  keepLatestRuns: 1,
694
700
  maxInteractionGroups: 12,
@@ -1540,6 +1546,17 @@ var logger = new Logger("GraphExecutor");
1540
1546
  function asLocalRecord(local) {
1541
1547
  return local && typeof local === "object" ? { ...local } : {};
1542
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
+ }
1543
1560
  var GraphExecutor = class {
1544
1561
  constructor(checkpointer, config = {}) {
1545
1562
  this.checkpointer = checkpointer;
@@ -1557,8 +1574,8 @@ var GraphExecutor = class {
1557
1574
  registerNode(node) {
1558
1575
  this.nodes.set(node.id, node);
1559
1576
  }
1560
- async peekCheckpoint(conversationId) {
1561
- return await this.checkpointer.load(conversationId);
1577
+ async peekCheckpoint(checkpointKey) {
1578
+ return await this.checkpointer.load(checkpointKey);
1562
1579
  }
1563
1580
  sanitize(state) {
1564
1581
  const local = asLocalRecord(state.local);
@@ -1570,8 +1587,8 @@ var GraphExecutor = class {
1570
1587
  local
1571
1588
  };
1572
1589
  }
1573
- async prime(conversationId, local, nodeId = "user") {
1574
- this.ephemeralLocals.set(conversationId, { ...local || {} });
1590
+ async prime(checkpointKey, local, nodeId = "user") {
1591
+ this.ephemeralLocals.set(checkpointKey, { ...local || {} });
1575
1592
  const localSansMemory = { ...local || {} };
1576
1593
  if ("memory" in localSansMemory) delete localSansMemory.memory;
1577
1594
  const state = {
@@ -1579,10 +1596,10 @@ var GraphExecutor = class {
1579
1596
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1580
1597
  local: localSansMemory
1581
1598
  };
1582
- await this.checkpointer.save(conversationId, state);
1599
+ await this.checkpointer.save(checkpointKey, state);
1583
1600
  }
1584
- async setNode(conversationId, nodeId, localPatch) {
1585
- const current = await this.checkpointer.load(conversationId) || {
1601
+ async setNode(checkpointKey, nodeId, localPatch) {
1602
+ const current = await this.checkpointer.load(checkpointKey) || {
1586
1603
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1587
1604
  local: {}
1588
1605
  };
@@ -1593,19 +1610,46 @@ var GraphExecutor = class {
1593
1610
  schemaVersion: current.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
1594
1611
  local: mergedLocal
1595
1612
  };
1596
- await this.checkpointer.save(conversationId, next);
1613
+ await this.checkpointer.save(checkpointKey, next);
1597
1614
  }
1598
- async runUntilYield(conversationId) {
1615
+ async runUntilYield(checkpointKey) {
1599
1616
  const runId = `run_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1600
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);
1601
1639
  this.telemetryPort.emit({
1602
1640
  kind: "run_lifecycle",
1603
1641
  runId,
1604
1642
  phase: "spawned",
1605
- scope: { conversationId: conversationId || void 0 }
1643
+ scope: {
1644
+ conversationId: lifecycleConversationId,
1645
+ turnId: lifecycleTurnId
1646
+ }
1606
1647
  });
1607
1648
  try {
1608
- 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;
1609
1653
  } catch (err) {
1610
1654
  lifecyclePhase = err?.name === "AbortError" ? "cancelled" : "failed";
1611
1655
  throw err;
@@ -1614,17 +1658,23 @@ var GraphExecutor = class {
1614
1658
  kind: "run_lifecycle",
1615
1659
  runId,
1616
1660
  phase: lifecyclePhase,
1617
- scope: { conversationId: conversationId || void 0 }
1661
+ scope: {
1662
+ conversationId: lifecycleConversationId,
1663
+ turnId: lifecycleTurnId
1664
+ }
1618
1665
  });
1619
1666
  }
1620
1667
  }
1621
- async runUntilYieldInternal(conversationId) {
1622
- let state = await this.checkpointer.load(conversationId) || {
1668
+ async loadInitialState(checkpointKey) {
1669
+ return await this.checkpointer.load(checkpointKey) || {
1623
1670
  nodeId: "user",
1624
1671
  schemaVersion: ENGINE_STATE_SCHEMA_VERSION,
1625
1672
  local: {}
1626
1673
  };
1627
- const ephemeral = this.ephemeralLocals.get(conversationId) || {};
1674
+ }
1675
+ async runUntilYieldInternal(checkpointKey, initialState) {
1676
+ let state = initialState;
1677
+ const ephemeral = this.ephemeralLocals.get(checkpointKey) || {};
1628
1678
  state = {
1629
1679
  ...state,
1630
1680
  schemaVersion: state.schemaVersion ?? ENGINE_STATE_SCHEMA_VERSION,
@@ -1653,7 +1703,7 @@ var GraphExecutor = class {
1653
1703
  const signalRaw = state.local?.signal;
1654
1704
  if (isAbortSignal2(signalRaw) && signalRaw.aborted) {
1655
1705
  logger.warn("[GraphExecutor] \u6536\u5230 AbortSignal\uFF0C\u7ACB\u5373\u505C\u6B62\u63A8\u7406\u5FAA\u73AF");
1656
- this.ephemeralLocals.delete(conversationId);
1706
+ this.ephemeralLocals.delete(checkpointKey);
1657
1707
  throwAbortError();
1658
1708
  }
1659
1709
  const isLastStep = cycleStepCount >= this.config.maxSteps;
@@ -1701,8 +1751,8 @@ var GraphExecutor = class {
1701
1751
  checkpointCount
1702
1752
  });
1703
1753
  const cp2 = this.sanitize(state);
1704
- await this.checkpointer.save(conversationId, cp2);
1705
- this.ephemeralLocals.delete(conversationId);
1754
+ await this.checkpointer.save(checkpointKey, cp2);
1755
+ this.ephemeralLocals.delete(checkpointKey);
1706
1756
  return { events: allEvents, checkpoint: cp2, stepCount };
1707
1757
  }
1708
1758
  logger.info("[GraphExecutor] \u8282\u70B9\u5207\u6362", {
@@ -1713,18 +1763,18 @@ var GraphExecutor = class {
1713
1763
  });
1714
1764
  const nodeRunStartedAt = Date.now();
1715
1765
  const nodeIdForTelemetry = state.nodeId;
1766
+ const conversationIdForTelemetry = readRuntimeConversationId(state);
1716
1767
  let result;
1717
1768
  try {
1718
1769
  result = await node.run(state);
1719
1770
  } finally {
1720
- const turnIdForTelemetry = typeof state.local?.turnId === "string" ? state.local.turnId : void 0;
1721
1771
  this.telemetryPort.emit({
1722
1772
  kind: "graph_node",
1723
1773
  nodeId: nodeIdForTelemetry,
1724
1774
  durationMs: Date.now() - nodeRunStartedAt,
1725
1775
  scope: {
1726
- conversationId: conversationId || void 0,
1727
- turnId: turnIdForTelemetry
1776
+ conversationId: conversationIdForTelemetry,
1777
+ turnId: readRuntimeTurnId(state)
1728
1778
  }
1729
1779
  });
1730
1780
  }
@@ -1763,7 +1813,7 @@ var GraphExecutor = class {
1763
1813
  });
1764
1814
  state = { ...state, nodeId: nextNodeId };
1765
1815
  const cp2 = this.sanitize(state);
1766
- await this.checkpointer.save(conversationId, cp2);
1816
+ await this.checkpointer.save(checkpointKey, cp2);
1767
1817
  continue;
1768
1818
  }
1769
1819
  if (result.kind === "yield") {
@@ -1774,7 +1824,7 @@ var GraphExecutor = class {
1774
1824
  checkpointCount
1775
1825
  });
1776
1826
  const cp2 = this.sanitize(state);
1777
- await this.checkpointer.save(conversationId, cp2);
1827
+ await this.checkpointer.save(checkpointKey, cp2);
1778
1828
  return { events: allEvents, checkpoint: cp2, stepCount };
1779
1829
  }
1780
1830
  if (result.kind === "pause") {
@@ -1785,7 +1835,7 @@ var GraphExecutor = class {
1785
1835
  checkpointCount
1786
1836
  });
1787
1837
  const cp2 = this.sanitize(state);
1788
- await this.checkpointer.save(conversationId, cp2);
1838
+ await this.checkpointer.save(checkpointKey, cp2);
1789
1839
  return { events: allEvents, checkpoint: cp2, stepCount };
1790
1840
  }
1791
1841
  }
@@ -1796,8 +1846,8 @@ var GraphExecutor = class {
1796
1846
  checkpointCount
1797
1847
  });
1798
1848
  const cp = this.sanitize(state);
1799
- await this.checkpointer.save(conversationId, cp);
1800
- this.ephemeralLocals.delete(conversationId);
1849
+ await this.checkpointer.save(checkpointKey, cp);
1850
+ this.ephemeralLocals.delete(checkpointKey);
1801
1851
  return { events: allEvents, checkpoint: cp, stepCount };
1802
1852
  }
1803
1853
  };
@@ -1994,15 +2044,15 @@ function splitConcatenatedJsonObjects(input) {
1994
2044
  }
1995
2045
 
1996
2046
  // src/runtime-kernel/graph-engine/tick-pipeline/helpers.ts
1997
- function readNonEmptyString(value) {
2047
+ function readNonEmptyString2(value) {
1998
2048
  if (typeof value !== "string") return void 0;
1999
2049
  const trimmed = value.trim();
2000
2050
  return trimmed.length > 0 ? trimmed : void 0;
2001
2051
  }
2002
2052
  function resolveConversationIdForRuntimeEvents(toolContext) {
2003
- const fromCamel = readNonEmptyString(toolContext?.conversationId);
2053
+ const fromCamel = readNonEmptyString2(toolContext?.conversationId);
2004
2054
  if (fromCamel) return fromCamel;
2005
- const fromSnake = toolContext ? readNonEmptyString(toolContext["conversation_id"]) : void 0;
2055
+ const fromSnake = toolContext ? readNonEmptyString2(toolContext["conversation_id"]) : void 0;
2006
2056
  if (fromSnake) return fromSnake;
2007
2057
  return generateMessageId();
2008
2058
  }
@@ -2384,7 +2434,7 @@ var runModelLockMiddleware = async (ctx, stage, next) => {
2384
2434
  if (stage.id !== "execute_llm") {
2385
2435
  return;
2386
2436
  }
2387
- const normalized = readNonEmptyString(ctx.cloudQuotaFallbackAppliedModelId);
2437
+ const normalized = readNonEmptyString2(ctx.cloudQuotaFallbackAppliedModelId);
2388
2438
  if (!normalized) {
2389
2439
  return;
2390
2440
  }
@@ -2985,7 +3035,7 @@ function createExecuteLlmStage(dependencies) {
2985
3035
  streamEventHandler,
2986
3036
  ctx.signal,
2987
3037
  (fallbackModelId) => {
2988
- ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString(fallbackModelId);
3038
+ ctx.cloudQuotaFallbackAppliedModelId = readNonEmptyString2(fallbackModelId);
2989
3039
  },
2990
3040
  (info) => {
2991
3041
  ctx.modelFallbackAudit = info;
@@ -3029,7 +3079,7 @@ function createPrepareCallStage(dependencies) {
3029
3079
  return {
3030
3080
  id: "prepare_call",
3031
3081
  async run(ctx) {
3032
- const lockedRunModelId = readNonEmptyString(ctx.executorLocal?.runLockedModelId);
3082
+ const lockedRunModelId = readNonEmptyString2(ctx.executorLocal?.runLockedModelId);
3033
3083
  const requestedModelId = lockedRunModelId ?? ctx.request.model_id;
3034
3084
  ctx.modelId = dependencies.modelResolver.resolveModelId(requestedModelId);
3035
3085
  await emitAuditEnvelope(ctx.audit, {
@@ -3101,7 +3151,7 @@ var GraphAgentExecutor = class {
3101
3151
  this.llmCaller = dependencies.llmCaller;
3102
3152
  this.toolRuntime = dependencies.toolRuntime;
3103
3153
  this.contextBuilder = dependencies.contextBuilder;
3104
- this.cloudQuotaFallbackModelId = readNonEmptyString(dependencies.cloudQuotaFallbackModelId);
3154
+ this.cloudQuotaFallbackModelId = readNonEmptyString2(dependencies.cloudQuotaFallbackModelId);
3105
3155
  this.modelCatalog = dependencies.modelCatalog ?? createEmptyModelCatalog();
3106
3156
  this.modelResolver = dependencies.modelResolver ?? new ModelResolver({
3107
3157
  modelCatalog: this.modelCatalog
@@ -3149,7 +3199,7 @@ var GraphAgentExecutor = class {
3149
3199
  llmMessages: [],
3150
3200
  mode: input.request.mode === "chat" ? "chat" : "agent",
3151
3201
  conversationId: resolveConversationIdForRuntimeEvents(input.toolContext),
3152
- turnId: readNonEmptyString(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3202
+ turnId: readNonEmptyString2(input.toolContext?.turnId) ?? `turn_${Date.now()}`,
3153
3203
  telemetry: this.telemetryPort,
3154
3204
  audit: this.auditPort
3155
3205
  };
@@ -3199,18 +3249,18 @@ function isSummarizationCallbacks(value) {
3199
3249
  function isGraphSseSink(value) {
3200
3250
  return typeof value === "function";
3201
3251
  }
3202
- function readNonEmptyString2(value) {
3252
+ function readNonEmptyString3(value) {
3203
3253
  if (typeof value !== "string") return void 0;
3204
3254
  const trimmed = value.trim();
3205
3255
  return trimmed.length > 0 ? trimmed : void 0;
3206
3256
  }
3207
3257
  function readGraphAgentLocal(local) {
3208
3258
  const source = local ?? {};
3209
- const answerId = readNonEmptyString2(source.answerId);
3259
+ const answerId = readNonEmptyString3(source.answerId);
3210
3260
  const chunkSeq = Number.isInteger(source.chunkSeq) ? Number(source.chunkSeq) : 0;
3211
3261
  return {
3212
- conversationId: readNonEmptyString2(source.conversationId) ?? "",
3213
- turnId: readNonEmptyString2(source.turnId),
3262
+ conversationId: readNonEmptyString3(source.conversationId) ?? "",
3263
+ turnId: readNonEmptyString3(source.turnId),
3214
3264
  request: isAgentInvocationRequest(source.request) ? source.request : void 0,
3215
3265
  toolContext: isToolExecutionContext(source.toolContext) ? source.toolContext : void 0,
3216
3266
  history: isRuntimeEventArray(source.history) ? source.history : [],
@@ -3975,7 +4025,7 @@ var LlmNode = class {
3975
4025
  function isRecord8(value) {
3976
4026
  return typeof value === "object" && value !== null && !Array.isArray(value);
3977
4027
  }
3978
- function readNonEmptyString3(value) {
4028
+ function readNonEmptyString4(value) {
3979
4029
  if (typeof value !== "string") {
3980
4030
  return void 0;
3981
4031
  }
@@ -3997,7 +4047,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
3997
4047
  return void 0;
3998
4048
  }
3999
4049
  if (toolName === "write_report") {
4000
- const report = readNonEmptyString3(data.report);
4050
+ const report = readNonEmptyString4(data.report);
4001
4051
  if (!report) {
4002
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");
4003
4053
  }
@@ -4007,7 +4057,7 @@ function resolveFinalAnswerFromToolResult(toolName, parsedResult) {
4007
4057
  if (data.success !== true) {
4008
4058
  return void 0;
4009
4059
  }
4010
- const finalAnswer = readNonEmptyString3(data.final_answer);
4060
+ const finalAnswer = readNonEmptyString4(data.final_answer);
4011
4061
  if (!finalAnswer) {
4012
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");
4013
4063
  }
@@ -4557,6 +4607,31 @@ function ensureToolContextRuntimeCapability(params) {
4557
4607
  function getToolContextRuntimeBinding(context) {
4558
4608
  return readBinding(context);
4559
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
+ }
4560
4635
  function readToolContextWorkingHistory(context) {
4561
4636
  if (context.conversationView) {
4562
4637
  return context.conversationView.getWorkingHistoryEvents();
@@ -4970,6 +5045,22 @@ var ToolNode = class {
4970
5045
  });
4971
5046
  }
4972
5047
  async run(state) {
5048
+ const events = [];
5049
+ while (true) {
5050
+ const result = await this.runNextPendingToolCall(state);
5051
+ if (Array.isArray(result.events) && result.events.length > 0) {
5052
+ events.push(...result.events);
5053
+ }
5054
+ if (result.kind === "route" && result.nextNodeId === "tool") {
5055
+ continue;
5056
+ }
5057
+ return {
5058
+ ...result,
5059
+ events
5060
+ };
5061
+ }
5062
+ }
5063
+ async runNextPendingToolCall(state) {
4973
5064
  const calls = state.local?.pendingToolCalls ?? [];
4974
5065
  const signalRaw = state.local?.signal;
4975
5066
  if (isAbortSignal(signalRaw) && signalRaw.aborted) {
@@ -5177,18 +5268,25 @@ var ToolNode = class {
5177
5268
  rawArguments: context.call.function?.arguments,
5178
5269
  parsedArguments: context.toolArgs
5179
5270
  });
5271
+ const remainingCalls = context.calls.slice(1);
5180
5272
  context.state.local = buildErrorLocalState({
5181
5273
  local: context.local,
5182
- remainingCalls: context.calls.slice(1),
5274
+ remainingCalls,
5183
5275
  conversationId: context.conversationId,
5184
5276
  turnId: context.turnId,
5185
5277
  runtimeEvents: context.bridge.getRuntimeEvents(),
5186
5278
  nextProtocolErrorCount: fuse.nextCount
5187
5279
  });
5188
- if (fuse.shouldFuse) {
5280
+ if (fuse.shouldFuse && remainingCalls.length === 0) {
5189
5281
  throw createToolProtocolFuseError(fuse.nextCount, context.exec.error);
5190
5282
  }
5191
- return { kind: "route", nextNodeId: "llm", events: context.bridge.getRuntimeEvents() };
5283
+ return {
5284
+ kind: "route",
5285
+ // 同一个 assistant.tool_calls batch 必须为每个 call 产出 tool_output。
5286
+ // 出错时也继续消费剩余 call,ToolNode.run 会在本节点内 drain 完 batch 再回 LLM。
5287
+ nextNodeId: remainingCalls.length > 0 ? "tool" : "llm",
5288
+ events: context.bridge.getRuntimeEvents()
5289
+ };
5192
5290
  }
5193
5291
  };
5194
5292
 
@@ -5385,12 +5483,12 @@ function asRecord(value) {
5385
5483
  }
5386
5484
  return value;
5387
5485
  }
5388
- function summarizeCheckpoint(conversationId, state, savedAt) {
5486
+ function summarizeCheckpoint(checkpointKey, state, savedAt) {
5389
5487
  const local = asRecord(state.local);
5390
5488
  const executorLocal = asRecord(local?.executorLocal);
5391
5489
  const pendingToolCalls = local?.pendingToolCalls;
5392
5490
  return {
5393
- conversationId,
5491
+ checkpointKey,
5394
5492
  schemaVersion: state.schemaVersion ?? 1,
5395
5493
  savedAt,
5396
5494
  currentNode: state.nodeId,
@@ -5409,25 +5507,25 @@ var MemoryCheckpointer = class {
5409
5507
  local: state.local && typeof state.local === "object" && !Array.isArray(state.local) ? { ...state.local } : state.local
5410
5508
  };
5411
5509
  }
5412
- async load(conversationId) {
5413
- const entry = this.store.get(conversationId);
5510
+ async load(checkpointKey) {
5511
+ const entry = this.store.get(checkpointKey);
5414
5512
  return entry ? this.cloneState(entry.state) : null;
5415
5513
  }
5416
- async save(conversationId, state) {
5417
- this.store.set(conversationId, {
5514
+ async save(checkpointKey, state) {
5515
+ this.store.set(checkpointKey, {
5418
5516
  state: this.cloneState(state),
5419
5517
  savedAt: Date.now()
5420
5518
  });
5421
5519
  }
5422
- async clear(conversationId) {
5423
- this.store.delete(conversationId);
5520
+ async clear(checkpointKey) {
5521
+ this.store.delete(checkpointKey);
5424
5522
  }
5425
- async peekMeta(conversationId) {
5426
- const entry = this.store.get(conversationId);
5427
- 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;
5428
5526
  }
5429
5527
  async list(filter = {}) {
5430
- 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);
5431
5529
  if (filter.limit === void 0) {
5432
5530
  return summaries;
5433
5531
  }
@@ -5499,6 +5597,7 @@ __export(tools_exports, {
5499
5597
  CommonParameterTypes: () => CommonParameterTypes,
5500
5598
  ContextCheckpointTool: () => ContextCheckpointTool,
5501
5599
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
5600
+ copyToolContextRuntimeCapability: () => copyToolContextRuntimeCapability,
5502
5601
  createContextCheckpointTool: () => createContextCheckpointTool,
5503
5602
  ensureToolContextRuntimeCapability: () => ensureToolContextRuntimeCapability,
5504
5603
  findCachedToolOutputByIdempotencyKey: () => findCachedToolOutputByIdempotencyKey,
@@ -5692,7 +5791,7 @@ function createContextCheckpointTool(options) {
5692
5791
  function isRecord15(value) {
5693
5792
  return !!value && typeof value === "object" && !Array.isArray(value);
5694
5793
  }
5695
- function readNonEmptyString4(value) {
5794
+ function readNonEmptyString5(value) {
5696
5795
  if (typeof value !== "string") {
5697
5796
  return void 0;
5698
5797
  }
@@ -5712,13 +5811,13 @@ function readToolContextUserQuery(context) {
5712
5811
  if (!context) {
5713
5812
  return void 0;
5714
5813
  }
5715
- return readNonEmptyString4(context["user_query"]);
5814
+ return readNonEmptyString5(context["user_query"]);
5716
5815
  }
5717
5816
  function readToolContextModelId(context) {
5718
5817
  if (!context) {
5719
5818
  return void 0;
5720
5819
  }
5721
- return readNonEmptyString4(context["modelId"]);
5820
+ return readNonEmptyString5(context["modelId"]);
5722
5821
  }
5723
5822
  function readToolContextRunContext(context) {
5724
5823
  if (!context) {
@@ -5925,18 +6024,18 @@ function createClassification(category, reason, suggestedDelay, extras) {
5925
6024
  }
5926
6025
  var ErrorClassifier = class {
5927
6026
  static classify(error, context) {
5928
- const isRecord24 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6027
+ const isRecord25 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
5929
6028
  const baseMsg = (error.message || "").toLowerCase();
5930
6029
  const causeMsg = (() => {
5931
6030
  const cause = error.cause;
5932
6031
  if (typeof cause === "string") return cause.toLowerCase();
5933
6032
  if (cause instanceof Error) return (cause.message || "").toLowerCase();
5934
- if (isRecord24(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
6033
+ if (isRecord25(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
5935
6034
  return "";
5936
6035
  })();
5937
6036
  const causeCode = (() => {
5938
6037
  const cause = error.cause;
5939
- if (isRecord24(cause) && typeof cause["code"] === "string") return String(cause["code"]);
6038
+ if (isRecord25(cause) && typeof cause["code"] === "string") return String(cause["code"]);
5940
6039
  return "";
5941
6040
  })();
5942
6041
  const errorMessage = `${baseMsg} ${causeMsg}`.trim();
@@ -6428,6 +6527,9 @@ __export(llm_exports, {
6428
6527
  LLMPolicyEngine: () => LLMPolicyEngine,
6429
6528
  LlmCaller: () => LlmCaller,
6430
6529
  ModelResolver: () => ModelResolver,
6530
+ appendStreamingProviderReasoningDetails: () => appendStreamingProviderReasoningDetails,
6531
+ compactProviderReasoningDetails: () => compactProviderReasoningDetails,
6532
+ compactReasoningDetailsInValue: () => compactReasoningDetailsInValue,
6431
6533
  createDefaultTokenizerPort: () => createDefaultTokenizerPort,
6432
6534
  defaultPolicyEngine: () => defaultPolicyEngine
6433
6535
  });
@@ -6817,6 +6919,90 @@ function assertToolCallsHaveValidJsonArguments(toolCalls) {
6817
6919
  }
6818
6920
  }
6819
6921
 
6922
+ // src/runtime-kernel/llm/reasoning-details.ts
6923
+ var mergeableTextFields = ["reasoning_content"];
6924
+ function isRecord20(value) {
6925
+ return !!value && typeof value === "object" && !Array.isArray(value);
6926
+ }
6927
+ function findMergeableTextField(detail) {
6928
+ if (!isRecord20(detail)) return void 0;
6929
+ if (typeof detail.provider !== "string") return void 0;
6930
+ if (typeof detail.type !== "string") return void 0;
6931
+ for (const field of mergeableTextFields) {
6932
+ if (typeof detail[field] === "string") {
6933
+ return field;
6934
+ }
6935
+ }
6936
+ return void 0;
6937
+ }
6938
+ function hasOnlyStableTextDetailFields(detail, textField) {
6939
+ const allowedKeys = /* @__PURE__ */ new Set(["provider", "type", textField]);
6940
+ return Object.keys(detail).every((key) => allowedKeys.has(key));
6941
+ }
6942
+ function canMergeTextDetails(previous, incoming) {
6943
+ if (!isRecord20(previous) || !isRecord20(incoming)) return false;
6944
+ const previousField = findMergeableTextField(previous);
6945
+ const incomingField = findMergeableTextField(incoming);
6946
+ if (!previousField || previousField !== incomingField) return false;
6947
+ return previous.provider === incoming.provider && previous.type === incoming.type && hasOnlyStableTextDetailFields(previous, previousField) && hasOnlyStableTextDetailFields(incoming, incomingField);
6948
+ }
6949
+ function mergeStreamingText(previous, incoming) {
6950
+ if (!previous) return incoming;
6951
+ if (!incoming) return previous;
6952
+ if (incoming.startsWith(previous)) {
6953
+ return incoming;
6954
+ }
6955
+ if (previous.endsWith(incoming)) {
6956
+ return previous;
6957
+ }
6958
+ return `${previous}${incoming}`;
6959
+ }
6960
+ function appendStreamingProviderReasoningDetails(existing, incoming) {
6961
+ const next = [...existing];
6962
+ for (const detail of incoming) {
6963
+ const previous = next[next.length - 1];
6964
+ if (canMergeTextDetails(previous, detail)) {
6965
+ const textField = findMergeableTextField(previous);
6966
+ if (textField && isRecord20(detail)) {
6967
+ const mergedText = mergeStreamingText(String(previous[textField]), String(detail[textField]));
6968
+ if (mergedText === previous[textField]) {
6969
+ continue;
6970
+ }
6971
+ next[next.length - 1] = {
6972
+ ...previous,
6973
+ [textField]: mergedText
6974
+ };
6975
+ continue;
6976
+ }
6977
+ }
6978
+ next.push(detail);
6979
+ }
6980
+ return next;
6981
+ }
6982
+ function compactProviderReasoningDetails(reasoningDetails) {
6983
+ return appendStreamingProviderReasoningDetails([], reasoningDetails);
6984
+ }
6985
+ function compactReasoningDetailsInValue(value) {
6986
+ return compactValue(value);
6987
+ }
6988
+ function compactValue(value) {
6989
+ if (Array.isArray(value)) {
6990
+ return value.map((item) => compactValue(item));
6991
+ }
6992
+ if (!isRecord20(value)) {
6993
+ return value;
6994
+ }
6995
+ const compacted = {};
6996
+ for (const [key, childValue] of Object.entries(value)) {
6997
+ if (key === "reasoning_details" && Array.isArray(childValue)) {
6998
+ compacted[key] = compactProviderReasoningDetails(childValue);
6999
+ continue;
7000
+ }
7001
+ compacted[key] = compactValue(childValue);
7002
+ }
7003
+ return compacted;
7004
+ }
7005
+
6820
7006
  // src/runtime-kernel/llm/streaming-adapter.ts
6821
7007
  async function callLlmStream(params) {
6822
7008
  const {
@@ -6829,7 +7015,7 @@ async function callLlmStream(params) {
6829
7015
  } = params;
6830
7016
  let fullResponse = "";
6831
7017
  let streamError = null;
6832
- const reasoningDetails = [];
7018
+ let reasoningDetails = [];
6833
7019
  const streamAnswerId = generateMessageId();
6834
7020
  let streamChunkSeq = 0;
6835
7021
  let capturedUsage = void 0;
@@ -6899,13 +7085,21 @@ async function callLlmStream(params) {
6899
7085
  const reasoning = isRecord19(chunk) ? chunk["reasoning_details"] : void 0;
6900
7086
  if (reasoning !== void 0) {
6901
7087
  const newReasoningDetails = Array.isArray(reasoning) ? reasoning : [reasoning];
6902
- reasoningDetails.push(...newReasoningDetails);
6903
- eventHandler({
6904
- type: "provider_sidecar",
6905
- id: generateMessageId(),
6906
- timestamp: Date.now(),
6907
- reasoning_details: newReasoningDetails
6908
- });
7088
+ const previousReasoningDetails = reasoningDetails;
7089
+ const previousLength = previousReasoningDetails.length;
7090
+ const compactedReasoningDetails = appendStreamingProviderReasoningDetails(reasoningDetails, newReasoningDetails);
7091
+ reasoningDetails = compactedReasoningDetails;
7092
+ const previousLastChanged = previousLength > 0 && compactedReasoningDetails[previousLength - 1] !== previousReasoningDetails[previousLength - 1];
7093
+ const emitFromIndex = previousLastChanged ? previousLength - 1 : previousLength;
7094
+ const emittedReasoningDetails = compactedReasoningDetails.slice(Math.max(0, emitFromIndex));
7095
+ if (emittedReasoningDetails.length > 0) {
7096
+ eventHandler({
7097
+ type: "provider_sidecar",
7098
+ id: generateMessageId(),
7099
+ timestamp: Date.now(),
7100
+ reasoning_details: emittedReasoningDetails
7101
+ });
7102
+ }
6909
7103
  }
6910
7104
  if (chunk.tool_calls) {
6911
7105
  emitThoughtComplete(thoughtSegmenter.onBoundary());
@@ -7359,7 +7553,6 @@ __export(child_runs_exports, {
7359
7553
 
7360
7554
  // src/runtime-kernel/child-runs/childToolContext.ts
7361
7555
  function createChildRunToolContext(params) {
7362
- const inheritedConversationId = typeof params.parentToolContext.conversationId === "string" && params.parentToolContext.conversationId.trim().length > 0 ? params.parentToolContext.conversationId.trim() : void 0;
7363
7556
  const inheritedContext = stripRuntimeReservedToolContextPatch(params.parentToolContext);
7364
7557
  const childToolContext = {
7365
7558
  ...inheritedContext,
@@ -7371,7 +7564,7 @@ function createChildRunToolContext(params) {
7371
7564
  persistedHistory: params.seedHistory,
7372
7565
  workingHistory: params.seedHistory,
7373
7566
  executionMeta: {
7374
- conversationId: inheritedConversationId ?? params.internalConversationId,
7567
+ conversationId: params.conversationId,
7375
7568
  turnId: params.turnId,
7376
7569
  runId: params.runId,
7377
7570
  parentRunId: params.parentRunId
@@ -7522,7 +7715,7 @@ var FinalAnswerCollector = class {
7522
7715
  };
7523
7716
 
7524
7717
  // src/runtime-kernel/child-runs/childRunTraceSink.ts
7525
- function isRecord20(v) {
7718
+ function isRecord21(v) {
7526
7719
  return !!v && typeof v === "object" && !Array.isArray(v);
7527
7720
  }
7528
7721
  function getString2(obj, key) {
@@ -7555,7 +7748,7 @@ function createChildRunTraceSink(params) {
7555
7748
  const { publisher, conversationId, turnId } = params;
7556
7749
  const finalAnswerCollector = new FinalAnswerCollector(conversationId, turnId);
7557
7750
  const sink = (evt) => {
7558
- if (!isRecord20(evt)) {
7751
+ if (!isRecord21(evt)) {
7559
7752
  return [];
7560
7753
  }
7561
7754
  const type = getString2(evt, "type");
@@ -7691,7 +7884,7 @@ function readCheckpointHistory(checkpoint) {
7691
7884
  });
7692
7885
  }
7693
7886
  async function recoverChildRunEventsFromCheckpoint(params) {
7694
- const checkpoint = await params.checkpointer.load(params.conversationId);
7887
+ const checkpoint = await params.checkpointer.load(params.checkpointKey);
7695
7888
  const history = readCheckpointHistory(checkpoint);
7696
7889
  if (history.length === 0) {
7697
7890
  return [];
@@ -7699,7 +7892,7 @@ async function recoverChildRunEventsFromCheckpoint(params) {
7699
7892
  if (hasSeedHistoryPrefix(history, params.seedHistory)) {
7700
7893
  return history.slice(params.seedHistory.length);
7701
7894
  }
7702
- return history.filter((event) => event.conversation_id === params.internalConversationId);
7895
+ return history.filter((event) => event.conversation_id === params.childConversationId);
7703
7896
  }
7704
7897
 
7705
7898
  // src/runtime-kernel/child-runs/childRunInvoker.ts
@@ -7728,6 +7921,7 @@ var ChildRunInvoker = class {
7728
7921
  agentConfig,
7729
7922
  userMessage,
7730
7923
  parentToolContext,
7924
+ conversationId,
7731
7925
  runId,
7732
7926
  parentRunId,
7733
7927
  subrunTracePublisher,
@@ -7736,12 +7930,18 @@ var ChildRunInvoker = class {
7736
7930
  modelId,
7737
7931
  abortSignal
7738
7932
  } = config;
7739
- const internalConversationId = `internal_${generateMessageId()}`;
7933
+ const internalCheckpointKey = `internal_${generateMessageId()}`;
7934
+ const runtimeConversationId = resolveChildRunConversationId({
7935
+ explicitConversationId: conversationId,
7936
+ parentToolContext,
7937
+ fallbackConversationId: internalCheckpointKey
7938
+ });
7740
7939
  const turnId = `turn_${Date.now()}`;
7741
- 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;
7742
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;
7743
7942
  logger13.info(`\u542F\u52A8 child-run: ${agentConfig.id}`, {
7744
- conversationId: internalConversationId,
7943
+ conversationId: runtimeConversationId,
7944
+ checkpointKey: internalCheckpointKey,
7745
7945
  maxSteps,
7746
7946
  userMessage: userMessage.slice(0, 100) + (userMessage.length > 100 ? "..." : "")
7747
7947
  });
@@ -7802,7 +8002,7 @@ var ChildRunInvoker = class {
7802
8002
  const seedHistory = Array.isArray(seedHistoryEvents) ? seedHistoryEvents : [];
7803
8003
  const childToolContext = createChildRunToolContext({
7804
8004
  parentToolContext,
7805
- internalConversationId,
8005
+ conversationId: runtimeConversationId,
7806
8006
  turnId,
7807
8007
  runId: childRunId,
7808
8008
  parentRunId: resolvedParentRunId,
@@ -7811,13 +8011,13 @@ var ChildRunInvoker = class {
7811
8011
  });
7812
8012
  const subrunSseSink = subrunTracePublisher ? createChildRunTraceSink({
7813
8013
  publisher: subrunTracePublisher,
7814
- conversationId: internalConversationId,
8014
+ conversationId: runtimeConversationId,
7815
8015
  turnId
7816
8016
  }) : void 0;
7817
8017
  const initialLocal = {
7818
8018
  request,
7819
8019
  history: seedHistory,
7820
- conversationId: internalConversationId,
8020
+ conversationId: runtimeConversationId,
7821
8021
  turnId,
7822
8022
  toolContext: childToolContext,
7823
8023
  ...abortSignal ? { signal: abortSignal } : {},
@@ -7825,7 +8025,7 @@ var ChildRunInvoker = class {
7825
8025
  ...subrunSseSink ? { sseSink: subrunSseSink } : {},
7826
8026
  systemPrompt
7827
8027
  };
7828
- await graphExecutor.prime(internalConversationId, initialLocal, "llm");
8028
+ await graphExecutor.prime(internalCheckpointKey, initialLocal, "llm");
7829
8029
  const allEvents = [];
7830
8030
  let stepCount = 0;
7831
8031
  let finalAnswer;
@@ -7837,7 +8037,7 @@ var ChildRunInvoker = class {
7837
8037
  err.name = "AbortError";
7838
8038
  throw err;
7839
8039
  }
7840
- const result = await graphExecutor.runUntilYield(internalConversationId);
8040
+ const result = await graphExecutor.runUntilYield(internalCheckpointKey);
7841
8041
  appendUniqueEvents(allEvents, result.events);
7842
8042
  stepCount = result.stepCount;
7843
8043
  if (subrunSseSink && typeof subrunSseSink.finalize === "function") {
@@ -7871,8 +8071,8 @@ var ChildRunInvoker = class {
7871
8071
  }
7872
8072
  const recoveredEvents = await recoverChildRunEventsFromCheckpoint({
7873
8073
  checkpointer,
7874
- conversationId: internalConversationId,
7875
- internalConversationId,
8074
+ checkpointKey: internalCheckpointKey,
8075
+ childConversationId: runtimeConversationId,
7876
8076
  seedHistory
7877
8077
  });
7878
8078
  appendUniqueEvents(allEvents, recoveredEvents);
@@ -7889,7 +8089,7 @@ var ChildRunInvoker = class {
7889
8089
  stack: err.stack
7890
8090
  } : { error: String(err) });
7891
8091
  }
7892
- await checkpointer.clear(internalConversationId);
8092
+ await checkpointer.clear(internalCheckpointKey);
7893
8093
  return {
7894
8094
  success: !error,
7895
8095
  runId: childRunId,
@@ -7902,6 +8102,16 @@ var ChildRunInvoker = class {
7902
8102
  };
7903
8103
  }
7904
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
+ }
7905
8115
  function resolveChildRunSystemReminderPolicy(agentConfig) {
7906
8116
  const configured = agentConfig.systemReminderPolicy ?? agentConfig.contextPolicy?.systemReminder;
7907
8117
  const threshold = agentConfig.stepPolicy?.lastStepsHintThreshold;
@@ -8092,7 +8302,7 @@ function cloneRunRecord(record) {
8092
8302
  ...record,
8093
8303
  iterationBudget: record.iterationBudget ? { ...record.iterationBudget } : void 0,
8094
8304
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0,
8095
- metadata: record.metadata ? { ...record.metadata } : void 0
8305
+ metadata: record.metadata ? structuredClone(record.metadata) : void 0
8096
8306
  };
8097
8307
  }
8098
8308
  function matchesStatus(candidate, filter) {
@@ -8224,7 +8434,7 @@ function runRecordToMeta(record) {
8224
8434
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0
8225
8435
  };
8226
8436
  }
8227
- function isRecord21(value) {
8437
+ function isRecord22(value) {
8228
8438
  return typeof value === "object" && value !== null && !Array.isArray(value);
8229
8439
  }
8230
8440
  function readStringField(record, key) {
@@ -8245,7 +8455,7 @@ function getRunIdFromMetadata(event) {
8245
8455
  return snakeCaseRunId;
8246
8456
  }
8247
8457
  const runContext = metadata["run_context"];
8248
- if (isRecord21(runContext)) {
8458
+ if (isRecord22(runContext)) {
8249
8459
  return readStringField(runContext, "runId") ?? readStringField(runContext, "run_id");
8250
8460
  }
8251
8461
  return void 0;
@@ -8463,7 +8673,7 @@ function runMetaFromRecord(record) {
8463
8673
  }
8464
8674
 
8465
8675
  // src/runtime-kernel/run-supervisor/runSupervisor.ts
8466
- function isRecord22(value) {
8676
+ function isRecord23(value) {
8467
8677
  return typeof value === "object" && value !== null && !Array.isArray(value);
8468
8678
  }
8469
8679
  function readStringField2(record, key) {
@@ -8480,7 +8690,7 @@ function readRunIdFromRuntimeEvent(event) {
8480
8690
  return directRunId;
8481
8691
  }
8482
8692
  const runContext = metadata["run_context"];
8483
- if (!isRecord22(runContext)) {
8693
+ if (!isRecord23(runContext)) {
8484
8694
  return void 0;
8485
8695
  }
8486
8696
  return readStringField2(runContext, "runId") ?? readStringField2(runContext, "run_id");
@@ -8492,7 +8702,7 @@ function readAwaitingUserReason(event) {
8492
8702
  if (typeof event.prompt === "string" && event.prompt.trim().length > 0) {
8493
8703
  return event.prompt;
8494
8704
  }
8495
- if (isRecord22(event.form)) {
8705
+ if (isRecord23(event.form)) {
8496
8706
  const prompt = readStringField2(event.form, "prompt");
8497
8707
  if (prompt && prompt.trim().length > 0) {
8498
8708
  return prompt;
@@ -8504,7 +8714,7 @@ function isTerminalStatus(status) {
8504
8714
  return status === "completed" || status === "failed" || status === "cancelled";
8505
8715
  }
8506
8716
  function cloneMetadata(metadata) {
8507
- return metadata ? { ...metadata } : void 0;
8717
+ return metadata ? structuredClone(metadata) : void 0;
8508
8718
  }
8509
8719
  function recordToSnapshot(record) {
8510
8720
  return {
@@ -8591,7 +8801,7 @@ var DefaultRunSupervisor = class {
8591
8801
  startedAt,
8592
8802
  updatedAt: startedAt,
8593
8803
  iterationBudget: spec.iterationBudget ? { ...spec.iterationBudget } : void 0,
8594
- metadata: spec.metadata ? { ...spec.metadata } : void 0
8804
+ metadata: cloneMetadata(spec.metadata)
8595
8805
  };
8596
8806
  await this.registryStore.save(record);
8597
8807
  const handle = new DefaultRunHandle({
@@ -8765,12 +8975,13 @@ var DefaultRunSupervisor = class {
8765
8975
  }
8766
8976
  try {
8767
8977
  await handle.markRunning({ currentNode: "detached" });
8978
+ const registeredRecord = await this.registryStore.load(handle.runId);
8768
8979
  const executorOutcome = await this.executor.execute({
8769
8980
  runId: handle.runId,
8770
- parentRunId: spec.parentRunId,
8771
- conversationId: spec.conversationId,
8772
- agentSpec: spec.agentSpec,
8773
- request: spec.request,
8981
+ parentRunId: handle.parentRunId,
8982
+ conversationId: registeredRecord?.conversationId ?? spec.conversationId,
8983
+ agentSpec: await handle.spec(),
8984
+ request: await handle.request(),
8774
8985
  signal: handle.signal,
8775
8986
  eventBus: spec.eventBus,
8776
8987
  eventStore: spec.eventStore,
@@ -8779,7 +8990,7 @@ var DefaultRunSupervisor = class {
8779
8990
  contextFences: spec.contextFences,
8780
8991
  wakeSource: spec.wakeSource,
8781
8992
  ephemeral: spec.ephemeral,
8782
- metadata: spec.metadata
8993
+ metadata: cloneMetadata(registeredRecord?.metadata ?? spec.metadata)
8783
8994
  });
8784
8995
  const outcome = await this.persistExecutorOutcome(handle, executorOutcome);
8785
8996
  this.notifyTerminalWaiters(outcome);
@@ -8843,10 +9054,14 @@ var DefaultRunSupervisor = class {
8843
9054
  await this.registryStore.save(record);
8844
9055
  }
8845
9056
  const completedAt = executorOutcome?.completedAt ?? this.now();
9057
+ const fallbackMeta = record ? void 0 : await handle.meta();
8846
9058
  const outcome = recordToTerminalOutcome(record ?? {
8847
9059
  runId: handle.runId,
8848
9060
  parentRunId: handle.parentRunId,
8849
- status: executorOutcome?.status ?? "completed"}, completedAt);
9061
+ conversationId: fallbackMeta?.conversationId ?? "",
9062
+ agentSpecId: fallbackMeta?.agentSpecId,
9063
+ status: executorOutcome?.status ?? "completed",
9064
+ startedAt: fallbackMeta?.startedAt ?? completedAt}, completedAt);
8850
9065
  const nextOutcome = {
8851
9066
  ...outcome,
8852
9067
  metadata: {
@@ -9074,6 +9289,7 @@ function createGraphLoopHarness(options) {
9074
9289
  };
9075
9290
  return {
9076
9291
  async run() {
9292
+ const checkpointKey = options.conversationId;
9077
9293
  const executor = createDefaultGraphExecutor({
9078
9294
  llmNode: options.createLlmNode({
9079
9295
  llmCaller: options.llmCaller,
@@ -9102,8 +9318,8 @@ function createGraphLoopHarness(options) {
9102
9318
  signal: options.signal ?? options.toolContext.abortSignal,
9103
9319
  executorLocal
9104
9320
  };
9105
- await executor.prime(options.conversationId, local, "user");
9106
- const result = await executor.runUntilYield(options.conversationId);
9321
+ await executor.prime(checkpointKey, local, "user");
9322
+ const result = await executor.runUntilYield(checkpointKey);
9107
9323
  return {
9108
9324
  checkpointNodeId: result.checkpoint.nodeId,
9109
9325
  stepCount: result.stepCount
@@ -9374,7 +9590,7 @@ function createQuickstartTelemetryPort(collector) {
9374
9590
  }
9375
9591
 
9376
9592
  // src/quickstart/runAgent.ts
9377
- function isRecord23(value) {
9593
+ function isRecord24(value) {
9378
9594
  return typeof value === "object" && value !== null && !Array.isArray(value);
9379
9595
  }
9380
9596
  function readString4(value) {
@@ -9388,7 +9604,7 @@ function resolveModelId(agent, options) {
9388
9604
  return modelId;
9389
9605
  }
9390
9606
  function isQuickstartStreamChunkEvent(value) {
9391
- return isRecord23(value) && value.type === "stream_chunk" && typeof value.content === "string";
9607
+ return isRecord24(value) && value.type === "stream_chunk" && typeof value.content === "string";
9392
9608
  }
9393
9609
  function createNoopObservationPreview() {
9394
9610
  return {
@@ -9428,7 +9644,7 @@ function readFinalAnswer(events, checkpointLocal) {
9428
9644
  if (chunks.length > 0) {
9429
9645
  return chunks.join("");
9430
9646
  }
9431
- if (isRecord23(checkpointLocal)) {
9647
+ if (isRecord24(checkpointLocal)) {
9432
9648
  const finalAnswer = checkpointLocal["finalAnswer"];
9433
9649
  if (typeof finalAnswer === "string") {
9434
9650
  return finalAnswer;
@@ -9437,7 +9653,7 @@ function readFinalAnswer(events, checkpointLocal) {
9437
9653
  return "";
9438
9654
  }
9439
9655
  function readContextTrace(checkpointLocal) {
9440
- if (!isRecord23(checkpointLocal)) return void 0;
9656
+ if (!isRecord24(checkpointLocal)) return void 0;
9441
9657
  return checkpointLocal["contextTrace"];
9442
9658
  }
9443
9659
  async function emitRunEvent(event, sink) {
@@ -9446,6 +9662,7 @@ async function emitRunEvent(event, sink) {
9446
9662
  async function runAgent(agent, options) {
9447
9663
  const modelId = resolveModelId(agent, options);
9448
9664
  const conversationId = options.conversationId ?? `conv_${Date.now()}`;
9665
+ const checkpointKey = conversationId;
9449
9666
  const runId = options.runId ?? generateRunId();
9450
9667
  const turnId = runId;
9451
9668
  const costCollector = new QuickstartRunCostCollector();
@@ -9500,7 +9717,7 @@ async function runAgent(agent, options) {
9500
9717
  };
9501
9718
  await handle.markRunning({ currentNode: "user" });
9502
9719
  try {
9503
- await executor.prime(conversationId, {
9720
+ await executor.prime(checkpointKey, {
9504
9721
  conversationId,
9505
9722
  turnId,
9506
9723
  request: {
@@ -9525,7 +9742,7 @@ async function runAgent(agent, options) {
9525
9742
  return void 0;
9526
9743
  }
9527
9744
  });
9528
- const result = await executor.runUntilYield(conversationId);
9745
+ const result = await executor.runUntilYield(checkpointKey);
9529
9746
  runtimeEvents.push(...result.events);
9530
9747
  for (const event of result.events) {
9531
9748
  if (event.type === "final_answer_chunk") continue;