@theokit/sdk 4.22.0 → 4.24.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 (63) hide show
  1. package/dist/auth/index.cjs +29 -5
  2. package/dist/auth/index.cjs.map +1 -1
  3. package/dist/auth/index.js +29 -5
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/compaction.cjs +31 -0
  6. package/dist/compaction.cjs.map +1 -1
  7. package/dist/compaction.d.cts +79 -0
  8. package/dist/compaction.d.ts +79 -0
  9. package/dist/compaction.js +28 -1
  10. package/dist/compaction.js.map +1 -1
  11. package/dist/{cron-Bhdyjl0B.d.ts → cron-B_NkE_VM.d.ts} +15 -1
  12. package/dist/{cron-M2Xz7lq2.d.cts → cron-x3muPNgg.d.cts} +15 -1
  13. package/dist/cron.cjs +467 -337
  14. package/dist/cron.cjs.map +1 -1
  15. package/dist/cron.d.cts +2 -2
  16. package/dist/cron.d.ts +2 -2
  17. package/dist/cron.js +467 -337
  18. package/dist/cron.js.map +1 -1
  19. package/dist/{errors-gE8612p9.d.cts → errors-BdL-buYn.d.cts} +1 -1
  20. package/dist/{errors-CG2RpeW-.d.ts → errors-DHZtSNnj.d.ts} +1 -1
  21. package/dist/errors.d.cts +2 -2
  22. package/dist/eval.cjs +467 -337
  23. package/dist/eval.cjs.map +1 -1
  24. package/dist/eval.js +467 -337
  25. package/dist/eval.js.map +1 -1
  26. package/dist/index.cjs +640 -508
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +21 -12
  29. package/dist/index.d.ts +21 -12
  30. package/dist/index.js +640 -508
  31. package/dist/index.js.map +1 -1
  32. package/dist/internal/auth/credential-store.d.ts +20 -3
  33. package/dist/internal/global-singleton.d.ts +13 -0
  34. package/dist/internal/llm/openai-messages.d.ts +2 -0
  35. package/dist/internal/local-agent/mcp-pool.d.ts +41 -0
  36. package/dist/internal/local-agent/real-local-run.d.ts +2 -0
  37. package/dist/internal/persistence/index.cjs +3 -1
  38. package/dist/internal/persistence/index.cjs.map +1 -1
  39. package/dist/internal/persistence/index.js +3 -1
  40. package/dist/internal/persistence/index.js.map +1 -1
  41. package/dist/internal/providers/registry.d.ts +1 -0
  42. package/dist/internal/runtime/lifecycle/context-budget-event.d.ts +25 -0
  43. package/dist/internal/runtime/lifecycle/goal-marker.d.ts +13 -0
  44. package/dist/internal/runtime/lifecycle/run-until.d.ts +0 -1
  45. package/dist/internal/session/agent-session.d.ts +1 -1
  46. package/dist/internal/session/session-cache.d.ts +20 -0
  47. package/dist/models.cjs +22 -20
  48. package/dist/models.cjs.map +1 -1
  49. package/dist/models.js +22 -20
  50. package/dist/models.js.map +1 -1
  51. package/dist/persistence.cjs +3 -1
  52. package/dist/persistence.cjs.map +1 -1
  53. package/dist/persistence.js +3 -1
  54. package/dist/persistence.js.map +1 -1
  55. package/dist/provider-catalog.json +144 -469
  56. package/dist/{run-DFM1H2jW.d.cts → run-OJbGyweZ.d.cts} +20 -1
  57. package/dist/{run-DFM1H2jW.d.ts → run-OJbGyweZ.d.ts} +20 -1
  58. package/dist/types/agent.d.ts +14 -0
  59. package/dist/types/run-events.d.ts +20 -1
  60. package/dist/workflow.cjs.map +1 -1
  61. package/dist/workflow.js.map +1 -1
  62. package/package.json +2 -2
  63. package/dist/goal-loop.d.ts +0 -35
package/dist/eval.cjs CHANGED
@@ -1597,6 +1597,44 @@ var init_plugin_guards = __esm({
1597
1597
  }
1598
1598
  });
1599
1599
 
1600
+ // src/compaction.ts
1601
+ function resolveEffectiveContextWindow(input) {
1602
+ if (!(input.margin > 0) || input.margin > 1) {
1603
+ throw new ContextWindowMarginError(input.margin);
1604
+ }
1605
+ const withMargin = (raw) => Math.floor(raw * input.margin);
1606
+ if (input.override !== void 0) {
1607
+ const clamped = input.catalog !== void 0 && input.override > input.catalog;
1608
+ const raw = clamped ? input.catalog : input.override;
1609
+ return { window: withMargin(raw), source: "override", clamped };
1610
+ }
1611
+ if (input.catalog !== void 0) {
1612
+ return { window: withMargin(input.catalog), source: "catalog", clamped: false };
1613
+ }
1614
+ return { window: withMargin(input.floor ?? 0), source: "fallback", clamped: false };
1615
+ }
1616
+ function estimateTokens(text) {
1617
+ return Math.ceil(text.length / 4);
1618
+ }
1619
+ var ContextWindowMarginError, CONTEXT_WINDOW_MARGIN, CONTEXT_WINDOW_FLOOR;
1620
+ var init_compaction = __esm({
1621
+ "src/compaction.ts"() {
1622
+ init_errors();
1623
+ ContextWindowMarginError = class extends TheokitAgentError {
1624
+ constructor(margin) {
1625
+ super(
1626
+ `context-window margin must be in (0, 1], got ${String(margin)}. A margin above 1 grows the assumed window and delays compaction past the real limit.`,
1627
+ { code: "invalid_context_window_margin" }
1628
+ );
1629
+ this.margin = margin;
1630
+ }
1631
+ margin;
1632
+ };
1633
+ CONTEXT_WINDOW_MARGIN = 0.95;
1634
+ CONTEXT_WINDOW_FLOOR = 128e3;
1635
+ }
1636
+ });
1637
+
1600
1638
  // src/types/run-events.ts
1601
1639
  function emitRunEvent(sink, event) {
1602
1640
  if (sink === void 0) return;
@@ -1609,6 +1647,18 @@ var init_run_events = __esm({
1609
1647
  "src/types/run-events.ts"() {
1610
1648
  }
1611
1649
  });
1650
+
1651
+ // src/internal/global-singleton.ts
1652
+ function globalSingleton(key, create) {
1653
+ const g = globalThis;
1654
+ const sym = Symbol.for(key);
1655
+ if (g[sym] === void 0) g[sym] = create();
1656
+ return g[sym];
1657
+ }
1658
+ var init_global_singleton = __esm({
1659
+ "src/internal/global-singleton.ts"() {
1660
+ }
1661
+ });
1612
1662
  var MODALITIES, costSchema, limitSchema, modalitiesSchema, catalogModelSchema;
1613
1663
  var init_catalog_schema = __esm({
1614
1664
  "src/internal/providers/catalog-schema.ts"() {
@@ -1649,12 +1699,6 @@ var init_catalog_schema = __esm({
1649
1699
  });
1650
1700
 
1651
1701
  // src/internal/providers/registry.ts
1652
- function globalSingleton(key, create) {
1653
- const g = globalThis;
1654
- const sym = Symbol.for(key);
1655
- if (g[sym] === void 0) g[sym] = create();
1656
- return g[sym];
1657
- }
1658
1702
  function registerProvider(profile) {
1659
1703
  if (REGISTRY.has(profile.name)) {
1660
1704
  process.stderr.write(`[theokit-sdk] Provider "${profile.name}" overridden by user plugin.
@@ -1679,6 +1723,7 @@ function getProviderProfile(name) {
1679
1723
  var REGISTRY, ALIASES;
1680
1724
  var init_registry = __esm({
1681
1725
  "src/internal/providers/registry.ts"() {
1726
+ init_global_singleton();
1682
1727
  REGISTRY = globalSingleton(
1683
1728
  "theokit-sdk.providers.registry",
1684
1729
  () => /* @__PURE__ */ new Map()
@@ -1686,12 +1731,6 @@ var init_registry = __esm({
1686
1731
  ALIASES = globalSingleton("theokit-sdk.providers.aliases", () => /* @__PURE__ */ new Map());
1687
1732
  }
1688
1733
  });
1689
- function globalSingleton2(key, create) {
1690
- const g = globalThis;
1691
- const sym = Symbol.for(key);
1692
- if (g[sym] === void 0) g[sym] = create();
1693
- return g[sym];
1694
- }
1695
1734
  function getCatalogModelInfo(key) {
1696
1735
  ensureModelIndexLoaded();
1697
1736
  return modelInfoIndex.get(key);
@@ -1780,32 +1819,24 @@ function registerCatalogProviders(opts) {
1780
1819
  var __dirname_resolved, modelInfoIndex, patchedModelKeys, indexState;
1781
1820
  var init_catalog_loader = __esm({
1782
1821
  "src/internal/providers/catalog-loader.ts"() {
1822
+ init_global_singleton();
1783
1823
  init_catalog_schema();
1784
1824
  init_registry();
1785
1825
  __dirname_resolved = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('eval.cjs', document.baseURI).href))));
1786
- modelInfoIndex = globalSingleton2(
1826
+ modelInfoIndex = globalSingleton(
1787
1827
  "theokit-sdk.providers.model-info-index",
1788
1828
  () => /* @__PURE__ */ new Map()
1789
1829
  );
1790
- patchedModelKeys = globalSingleton2(
1830
+ patchedModelKeys = globalSingleton(
1791
1831
  "theokit-sdk.providers.model-info-patched",
1792
1832
  () => /* @__PURE__ */ new Set()
1793
1833
  );
1794
- indexState = globalSingleton2("theokit-sdk.providers.model-info-loaded", () => ({
1834
+ indexState = globalSingleton("theokit-sdk.providers.model-info-loaded", () => ({
1795
1835
  loaded: false
1796
1836
  }));
1797
1837
  }
1798
1838
  });
1799
1839
 
1800
- // src/compaction.ts
1801
- function estimateTokens(text) {
1802
- return Math.ceil(text.length / 4);
1803
- }
1804
- var init_compaction = __esm({
1805
- "src/compaction.ts"() {
1806
- }
1807
- });
1808
-
1809
1840
  // src/internal/providers/builtin/anthropic.ts
1810
1841
  var ANTHROPIC;
1811
1842
  var init_anthropic = __esm({
@@ -2175,11 +2206,12 @@ function writeCredential(cred, config, env = {}) {
2175
2206
  var CredentialError, apiFileSchema, oauthFileSchema, fileSchema;
2176
2207
  var init_credential_store = __esm({
2177
2208
  "src/internal/auth/credential-store.ts"() {
2178
- CredentialError = class extends Error {
2179
- constructor(message) {
2180
- super(message);
2181
- this.name = "CredentialError";
2182
- }
2209
+ init_errors();
2210
+ CredentialError = class extends AuthenticationError {
2211
+ // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`
2212
+ // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the
2213
+ // suite was green with the broken assignment because the transpiler strips the type.
2214
+ name = "CredentialError";
2183
2215
  };
2184
2216
  apiFileSchema = zod.z.object({
2185
2217
  type: zod.z.literal("api").optional(),
@@ -2601,12 +2633,6 @@ var init_builtin = __esm({
2601
2633
  })();
2602
2634
  }
2603
2635
  });
2604
- function globalSingleton3(key, create) {
2605
- const g = globalThis;
2606
- const sym = Symbol.for(key);
2607
- if (g[sym] === void 0) g[sym] = create();
2608
- return g[sym];
2609
- }
2610
2636
  function pluginsRoot() {
2611
2637
  return path.join(os.homedir(), ".theokit", "plugins", "model-providers");
2612
2638
  }
@@ -2698,8 +2724,9 @@ async function loadOne(dir, entryName) {
2698
2724
  var discoveryState;
2699
2725
  var init_discovery = __esm({
2700
2726
  "src/internal/providers/discovery.ts"() {
2727
+ init_global_singleton();
2701
2728
  init_registry();
2702
- discoveryState = globalSingleton3("theokit-sdk.providers.discovered", () => ({
2729
+ discoveryState = globalSingleton("theokit-sdk.providers.discovered", () => ({
2703
2730
  done: false
2704
2731
  }));
2705
2732
  }
@@ -4375,6 +4402,68 @@ var init_hermes_tool_extract = __esm({
4375
4402
  }
4376
4403
  });
4377
4404
 
4405
+ // src/internal/llm/openai-messages.ts
4406
+ function toOpenAIMessages(message) {
4407
+ if (message.role === "system") return [systemMessage(message)];
4408
+ if (message.role === "user") return userOrToolMessages(message);
4409
+ return [assistantMessage(message)];
4410
+ }
4411
+ function systemMessage(message) {
4412
+ return { role: "system", content: joinTextParts2(message) };
4413
+ }
4414
+ function joinTextParts2(message) {
4415
+ return message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
4416
+ }
4417
+ function userOrToolMessages(message) {
4418
+ const out = [];
4419
+ for (const part of message.content) {
4420
+ if (part.type === "tool_result") {
4421
+ out.push({
4422
+ role: "tool",
4423
+ tool_call_id: part.toolUseId,
4424
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
4425
+ // image block fails fast (ConfigurationError).
4426
+ content: toStringToolResultContent(part.content, "openai")
4427
+ });
4428
+ }
4429
+ }
4430
+ const userText = joinTextParts2(message);
4431
+ const imageParts = message.content.filter(
4432
+ (p) => p.type === "image"
4433
+ );
4434
+ if (imageParts.length > 0) {
4435
+ const content = [];
4436
+ if (userText.length > 0) content.push({ type: "text", text: userText });
4437
+ for (const img of imageParts) {
4438
+ const url = img.source.type === "base64" ? `data:${img.source.media_type};base64,${img.source.data}` : img.source.url;
4439
+ content.push({ type: "image_url", image_url: { url } });
4440
+ }
4441
+ out.push({ role: "user", content });
4442
+ } else if (userText.length > 0) {
4443
+ out.push({ role: "user", content: userText });
4444
+ }
4445
+ return out;
4446
+ }
4447
+ function assistantMessage(message) {
4448
+ const text = joinTextParts2(message);
4449
+ const toolCalls = message.content.filter((part) => part.type === "tool_use").map((part) => {
4450
+ const tc = part;
4451
+ return {
4452
+ id: tc.id,
4453
+ type: "function",
4454
+ function: { name: tc.name, arguments: JSON.stringify(tc.input) }
4455
+ };
4456
+ });
4457
+ const result = { role: "assistant", content: text };
4458
+ if (toolCalls.length > 0) result.tool_calls = toolCalls;
4459
+ return result;
4460
+ }
4461
+ var init_openai_messages = __esm({
4462
+ "src/internal/llm/openai-messages.ts"() {
4463
+ init_tool_result_content();
4464
+ }
4465
+ });
4466
+
4378
4467
  // src/internal/llm/openai.ts
4379
4468
  function deriveChatPath(baseUrl) {
4380
4469
  try {
@@ -4436,61 +4525,6 @@ function encodeOpenAIResponseFormat(rf) {
4436
4525
  }
4437
4526
  };
4438
4527
  }
4439
- function toOpenAIMessages(message) {
4440
- if (message.role === "system") return [systemMessage(message)];
4441
- if (message.role === "user") return userOrToolMessages(message);
4442
- return [assistantMessage(message)];
4443
- }
4444
- function systemMessage(message) {
4445
- return { role: "system", content: joinTextParts2(message) };
4446
- }
4447
- function joinTextParts2(message) {
4448
- return message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
4449
- }
4450
- function userOrToolMessages(message) {
4451
- const out = [];
4452
- for (const part of message.content) {
4453
- if (part.type === "tool_result") {
4454
- out.push({
4455
- role: "tool",
4456
- tool_call_id: part.toolUseId,
4457
- // SE7 — this wire's tool role is string-only: text blocks flatten; an
4458
- // image block fails fast (ConfigurationError).
4459
- content: toStringToolResultContent(part.content, "openai")
4460
- });
4461
- }
4462
- }
4463
- const userText = joinTextParts2(message);
4464
- const imageParts = message.content.filter(
4465
- (p) => p.type === "image"
4466
- );
4467
- if (imageParts.length > 0) {
4468
- const content = [];
4469
- if (userText.length > 0) content.push({ type: "text", text: userText });
4470
- for (const img of imageParts) {
4471
- const url = img.source.type === "base64" ? `data:${img.source.media_type};base64,${img.source.data}` : img.source.url;
4472
- content.push({ type: "image_url", image_url: { url } });
4473
- }
4474
- out.push({ role: "user", content });
4475
- } else if (userText.length > 0) {
4476
- out.push({ role: "user", content: userText });
4477
- }
4478
- return out;
4479
- }
4480
- function assistantMessage(message) {
4481
- const text = joinTextParts2(message);
4482
- const toolCalls = message.content.filter((part) => part.type === "tool_use").map((part) => {
4483
- const tc = part;
4484
- return {
4485
- id: tc.id,
4486
- type: "function",
4487
- function: { name: tc.name, arguments: JSON.stringify(tc.input) }
4488
- };
4489
- });
4490
- const result = { role: "assistant", content: text };
4491
- if (toolCalls.length > 0) result.tool_calls = toolCalls;
4492
- return result;
4493
- }
4494
4528
  var OpenAIClient, OpenAIStreamAccumulator, openAISystemText;
4495
4529
  var init_openai2 = __esm({
4496
4530
  "src/internal/llm/openai.ts"() {
@@ -4499,8 +4533,8 @@ var init_openai2 = __esm({
4499
4533
  init_openai_compatible2();
4500
4534
  init_finish();
4501
4535
  init_hermes_tool_extract();
4536
+ init_openai_messages();
4502
4537
  init_sse();
4503
- init_tool_result_content();
4504
4538
  OpenAIClient = class {
4505
4539
  constructor(options) {
4506
4540
  this.options = options;
@@ -5589,6 +5623,14 @@ function selectTransport(profile, apiKey) {
5589
5623
  const ctx = { apiKey };
5590
5624
  return { fetch: profile.transform.fetch?.(ctx), headers: profile.transform.headers?.(ctx) };
5591
5625
  };
5626
+ const comTransform = (opts, criar) => {
5627
+ const t = applyTransform();
5628
+ assertOAuthResolved(t);
5629
+ if (t.fetch !== void 0) opts.fetch = t.fetch;
5630
+ const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5631
+ if (merged !== void 0) opts.extraHeaders = merged;
5632
+ return criar(opts);
5633
+ };
5592
5634
  const assertOAuthResolved = (t) => {
5593
5635
  if (apiKey !== "__oauth_lazy_token__") return;
5594
5636
  const auth = t.headers?.authorization ?? t.headers?.Authorization;
@@ -5617,12 +5659,7 @@ function selectTransport(profile, apiKey) {
5617
5659
  }
5618
5660
  const envOverride = resolveBaseUrlEnvOverride(profile.name);
5619
5661
  if (envOverride !== void 0) opts.baseUrl = envOverride;
5620
- const t = applyTransform();
5621
- assertOAuthResolved(t);
5622
- if (t.fetch !== void 0) opts.fetch = t.fetch;
5623
- const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5624
- if (merged !== void 0) opts.extraHeaders = merged;
5625
- return new OpenAIClient(opts);
5662
+ return comTransform(opts, (o) => new OpenAIClient(o));
5626
5663
  }
5627
5664
  if (profile.apiMode === "anthropic_messages") {
5628
5665
  if (profile.name === "vertex") {
@@ -5631,12 +5668,7 @@ function selectTransport(profile, apiKey) {
5631
5668
  }
5632
5669
  const opts = { apiKey };
5633
5670
  opts.baseUrl = process.env.ANTHROPIC_API_BASE_URL ?? profile.baseUrl;
5634
- const t = applyTransform();
5635
- assertOAuthResolved(t);
5636
- if (t.fetch !== void 0) opts.fetch = t.fetch;
5637
- const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5638
- if (merged !== void 0) opts.extraHeaders = merged;
5639
- return new AnthropicClient(opts);
5671
+ return comTransform(opts, (o) => new AnthropicClient(o));
5640
5672
  }
5641
5673
  if (profile.apiMode === "bedrock_anthropic") {
5642
5674
  const realKey = apiKey === "__bedrock_lazy_token__" ? void 0 : apiKey;
@@ -5793,202 +5825,52 @@ function buildCompressionPrompt(messages) {
5793
5825
 
5794
5826
  --- CONVERSATION TO SUMMARIZE ---
5795
5827
  ${formatted}
5796
- --- END ---`;
5797
- }
5798
- async function compressConversationWindow(opts) {
5799
- const userPrompt = buildCompressionPrompt(opts.messages);
5800
- let summary;
5801
- try {
5802
- summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
5803
- } catch (cause) {
5804
- throw new CompressionFailedError(
5805
- `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
5806
- { cause: cause instanceof Error ? cause : void 0 }
5807
- );
5808
- }
5809
- if (!summary || summary.trim().length === 0) {
5810
- throw new CompressionFailedError(
5811
- "Compression LLM returned empty summary \u2014 reduction ineffective."
5812
- );
5813
- }
5814
- return {
5815
- role: "system",
5816
- content: `[Compressed conversation summary]: ${summary.trim()}`
5817
- };
5818
- }
5819
- var CompressionFailedError, COMPRESSION_SYSTEM;
5820
- var init_compression_summarizer = __esm({
5821
- "src/internal/runtime/compression/compression-summarizer.ts"() {
5822
- CompressionFailedError = class extends Error {
5823
- name = "CompressionFailedError";
5824
- };
5825
- COMPRESSION_SYSTEM = "You are a conversation summarizer. Produce a concise factual summary. Preserve all decisions, preferences, code snippets, and action items. Do not add commentary or opinions. Output ONLY the summary text.";
5826
- }
5827
- });
5828
-
5829
- // src/internal/session/agent-session-store.ts
5830
- function seedTranscript(prior, opts) {
5831
- return SessionTranscript.fromRecords(prior, opts);
5832
- }
5833
- function mapAgentTurn(steps) {
5834
- const assistant = {};
5835
- const toolResults = [];
5836
- const toolCalls = [];
5837
- for (const step of steps) {
5838
- if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
5839
- else if (step.type === "assistantMessage") assistant.text = step.message.text;
5840
- else if (step.type === "toolCall")
5841
- toolCalls.push({
5842
- id: step.message.callId,
5843
- name: step.message.name,
5844
- input: step.message.args ?? {}
5845
- });
5846
- else
5847
- toolResults.push({
5848
- toolUseId: step.message.callId,
5849
- content: step.message.result,
5850
- isError: step.message.isError
5851
- });
5852
- }
5853
- if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
5854
- return { assistant, toolResults };
5855
- }
5856
- function hasAssistantContent(a) {
5857
- return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
5858
- }
5859
- function appendConversation(transcript, conversation) {
5860
- for (const ct of conversation) {
5861
- if (ct.type !== "agentConversationTurn") continue;
5862
- const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
5863
- if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
5864
- if (toolResults.length > 0) transcript.appendToolResults(toolResults);
5865
- }
5866
- }
5867
- async function readSessionMessages(store, agentId) {
5868
- const records = await store.readRecords(agentId);
5869
- return reconstructMessages(records).map(narrowToSessionMessage);
5870
- }
5871
- function partToText(p) {
5872
- if (p.type === "text") return p.text ?? "";
5873
- if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
5874
- if (p.type === "tool_result") {
5875
- const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
5876
- return `[tool result] ${body}`;
5877
- }
5878
- return "";
5879
- }
5880
- function narrowToSessionMessage(m) {
5881
- const role = m.role === "user" ? "user" : "assistant";
5882
- const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
5883
- return { role, text };
5884
- }
5885
- function deltaRecords(transcript, priorLength) {
5886
- return transcript.records().slice(priorLength);
5887
- }
5888
- async function persistTurn(store, loc, sessionId, turn) {
5889
- const prior = await store.readRecords(loc.agentId);
5890
- const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
5891
- transcript.appendUserTurn(turn.userText);
5892
- appendConversation(transcript, turn.conversation);
5893
- await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
5894
- }
5895
- var init_agent_session_store = __esm({
5896
- "src/internal/session/agent-session-store.ts"() {
5897
- init_session_transcript();
5898
- }
5899
- });
5900
-
5901
- // src/internal/session/agent-session.ts
5902
- function transcriptKey(cwd, agentId) {
5903
- return `${cwd}::${agentId}`;
5904
- }
5905
- function appendSessionMessage(agentId, message) {
5906
- const existing = sessions.get(agentId) ?? [];
5907
- existing.push(message);
5908
- sessions.set(agentId, existing);
5909
- }
5910
- function getSessionMessages(agentId) {
5911
- return sessions.get(agentId) ?? [];
5912
- }
5913
- function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
5914
- const key = transcriptKey(loc.cwd, loc.agentId);
5915
- const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
5916
- try {
5917
- await persistTurn(store, loc, sessionId, turn);
5918
- const count = (recordCounts.get(key) ?? 0) + 1;
5919
- recordCounts.set(key, count);
5920
- if (turn.autoCompact !== void 0) {
5921
- const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
5922
- const fired = await autoCompactIfNeeded2({
5923
- store,
5924
- loc,
5925
- sessionId,
5926
- usageTotal: turn.autoCompact.usageTotal,
5927
- contextWindow: turn.autoCompact.contextWindow,
5928
- turnCount: count,
5929
- summarize: turn.autoCompact.summarize
5930
- });
5931
- if (fired) onCompact?.();
5932
- }
5933
- } catch (cause) {
5934
- const msg = cause instanceof Error ? cause.message : String(cause);
5935
- process.stderr.write(
5936
- `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
5937
- `
5938
- );
5939
- }
5940
- });
5941
- pendingWrites.set(
5942
- key,
5943
- chained.then(
5944
- () => void 0,
5945
- () => void 0
5946
- )
5947
- );
5948
- }
5949
- async function hydrateSession(agentId, loc) {
5950
- const key = transcriptKey(loc.cwd, agentId);
5951
- if (hydratedKeys.has(key)) return;
5952
- hydratedKeys.add(key);
5953
- const persisted = await readSessionMessages(loc.store, agentId);
5954
- if (persisted.length === 0) return;
5955
- sessions.set(agentId, persisted);
5956
- }
5957
- async function flushSessionWrites() {
5958
- while (pendingWrites.size > 0) {
5959
- const all = Array.from(pendingWrites.values());
5960
- pendingWrites.clear();
5961
- await Promise.all(all);
5828
+ --- END ---`;
5829
+ }
5830
+ async function compressConversationWindow(opts) {
5831
+ const userPrompt = buildCompressionPrompt(opts.messages);
5832
+ let summary;
5833
+ try {
5834
+ summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
5835
+ } catch (cause) {
5836
+ throw new CompressionFailedError(
5837
+ `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
5838
+ { cause: cause instanceof Error ? cause : void 0 }
5839
+ );
5840
+ }
5841
+ if (!summary || summary.trim().length === 0) {
5842
+ throw new CompressionFailedError(
5843
+ "Compression LLM returned empty summary \u2014 reduction ineffective."
5844
+ );
5962
5845
  }
5846
+ return {
5847
+ role: "system",
5848
+ content: `[Compressed conversation summary]: ${summary.trim()}`
5849
+ };
5963
5850
  }
5964
- function clearSession(agentId) {
5965
- sessions.delete(agentId);
5851
+ var CompressionFailedError, COMPRESSION_SYSTEM;
5852
+ var init_compression_summarizer = __esm({
5853
+ "src/internal/runtime/compression/compression-summarizer.ts"() {
5854
+ CompressionFailedError = class extends Error {
5855
+ name = "CompressionFailedError";
5856
+ };
5857
+ COMPRESSION_SYSTEM = "You are a conversation summarizer. Produce a concise factual summary. Preserve all decisions, preferences, code snippets, and action items. Do not add commentary or opinions. Output ONLY the summary text.";
5858
+ }
5859
+ });
5860
+
5861
+ // src/internal/session/session-cache.ts
5862
+ function transcriptKey(cwd, agentId) {
5863
+ return `${cwd}::${agentId}`;
5966
5864
  }
5967
5865
  function invalidateSessionCache(cwd, agentId) {
5968
5866
  sessions.delete(agentId);
5969
5867
  hydratedKeys.delete(transcriptKey(cwd, agentId));
5970
5868
  }
5971
- function enqueueSessionWrite(cwd, agentId, fn) {
5972
- const key = transcriptKey(cwd, agentId);
5973
- const prior = pendingWrites.get(key) ?? Promise.resolve();
5974
- const result = prior.then(fn);
5975
- pendingWrites.set(
5976
- key,
5977
- result.then(
5978
- () => void 0,
5979
- () => void 0
5980
- )
5981
- );
5982
- return result;
5983
- }
5984
- var sessions, hydratedKeys, pendingWrites, recordCounts;
5985
- var init_agent_session = __esm({
5986
- "src/internal/session/agent-session.ts"() {
5987
- init_agent_session_store();
5869
+ var sessions, hydratedKeys;
5870
+ var init_session_cache = __esm({
5871
+ "src/internal/session/session-cache.ts"() {
5988
5872
  sessions = /* @__PURE__ */ new Map();
5989
5873
  hydratedKeys = /* @__PURE__ */ new Set();
5990
- pendingWrites = /* @__PURE__ */ new Map();
5991
- recordCounts = /* @__PURE__ */ new Map();
5992
5874
  }
5993
5875
  });
5994
5876
 
@@ -6150,7 +6032,7 @@ var init_compact_session = __esm({
6150
6032
  init_providers();
6151
6033
  init_compression_model_registry();
6152
6034
  init_compression_summarizer();
6153
- init_agent_session();
6035
+ init_session_cache();
6154
6036
  COMPACT_SUMMARY_MARKER = "[[theokit:compact-summary]]";
6155
6037
  COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
6156
6038
  autoCompactAttempts = (() => {
@@ -6161,6 +6043,165 @@ var init_compact_session = __esm({
6161
6043
  })();
6162
6044
  }
6163
6045
  });
6046
+
6047
+ // src/internal/session/agent-session-store.ts
6048
+ function seedTranscript(prior, opts) {
6049
+ return SessionTranscript.fromRecords(prior, opts);
6050
+ }
6051
+ function mapAgentTurn(steps) {
6052
+ const assistant = {};
6053
+ const toolResults = [];
6054
+ const toolCalls = [];
6055
+ for (const step of steps) {
6056
+ if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
6057
+ else if (step.type === "assistantMessage") assistant.text = step.message.text;
6058
+ else if (step.type === "toolCall")
6059
+ toolCalls.push({
6060
+ id: step.message.callId,
6061
+ name: step.message.name,
6062
+ input: step.message.args ?? {}
6063
+ });
6064
+ else
6065
+ toolResults.push({
6066
+ toolUseId: step.message.callId,
6067
+ content: step.message.result,
6068
+ isError: step.message.isError
6069
+ });
6070
+ }
6071
+ if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
6072
+ return { assistant, toolResults };
6073
+ }
6074
+ function hasAssistantContent(a) {
6075
+ return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
6076
+ }
6077
+ function appendConversation(transcript, conversation) {
6078
+ for (const ct of conversation) {
6079
+ if (ct.type !== "agentConversationTurn") continue;
6080
+ const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
6081
+ if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
6082
+ if (toolResults.length > 0) transcript.appendToolResults(toolResults);
6083
+ }
6084
+ }
6085
+ async function readSessionMessages(store, agentId) {
6086
+ const records = await store.readRecords(agentId);
6087
+ return reconstructMessages(records).map(narrowToSessionMessage);
6088
+ }
6089
+ function partToText(p) {
6090
+ if (p.type === "text") return p.text ?? "";
6091
+ if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
6092
+ if (p.type === "tool_result") {
6093
+ const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
6094
+ return `[tool result] ${body}`;
6095
+ }
6096
+ return "";
6097
+ }
6098
+ function narrowToSessionMessage(m) {
6099
+ const role = m.role === "user" ? "user" : "assistant";
6100
+ const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
6101
+ return { role, text };
6102
+ }
6103
+ function deltaRecords(transcript, priorLength) {
6104
+ return transcript.records().slice(priorLength);
6105
+ }
6106
+ async function persistTurn(store, loc, sessionId, turn) {
6107
+ const prior = await store.readRecords(loc.agentId);
6108
+ const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
6109
+ transcript.appendUserTurn(turn.userText);
6110
+ appendConversation(transcript, turn.conversation);
6111
+ await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
6112
+ }
6113
+ var init_agent_session_store = __esm({
6114
+ "src/internal/session/agent-session-store.ts"() {
6115
+ init_session_transcript();
6116
+ }
6117
+ });
6118
+
6119
+ // src/internal/session/agent-session.ts
6120
+ function appendSessionMessage(agentId, message) {
6121
+ const existing = sessions.get(agentId) ?? [];
6122
+ existing.push(message);
6123
+ sessions.set(agentId, existing);
6124
+ }
6125
+ function getSessionMessages(agentId) {
6126
+ return sessions.get(agentId) ?? [];
6127
+ }
6128
+ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
6129
+ const key = transcriptKey(loc.cwd, loc.agentId);
6130
+ const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
6131
+ try {
6132
+ await persistTurn(store, loc, sessionId, turn);
6133
+ const count = (recordCounts.get(key) ?? 0) + 1;
6134
+ recordCounts.set(key, count);
6135
+ if (turn.autoCompact !== void 0) {
6136
+ const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
6137
+ const fired = await autoCompactIfNeeded2({
6138
+ store,
6139
+ loc,
6140
+ sessionId,
6141
+ usageTotal: turn.autoCompact.usageTotal,
6142
+ contextWindow: turn.autoCompact.contextWindow,
6143
+ turnCount: count,
6144
+ summarize: turn.autoCompact.summarize
6145
+ });
6146
+ if (fired) onCompact?.();
6147
+ }
6148
+ } catch (cause) {
6149
+ const msg = cause instanceof Error ? cause.message : String(cause);
6150
+ process.stderr.write(
6151
+ `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
6152
+ `
6153
+ );
6154
+ }
6155
+ });
6156
+ pendingWrites.set(
6157
+ key,
6158
+ chained.then(
6159
+ () => void 0,
6160
+ () => void 0
6161
+ )
6162
+ );
6163
+ }
6164
+ async function hydrateSession(agentId, loc) {
6165
+ const key = transcriptKey(loc.cwd, agentId);
6166
+ if (hydratedKeys.has(key)) return;
6167
+ hydratedKeys.add(key);
6168
+ const persisted = await readSessionMessages(loc.store, agentId);
6169
+ if (persisted.length === 0) return;
6170
+ sessions.set(agentId, persisted);
6171
+ }
6172
+ async function flushSessionWrites() {
6173
+ while (pendingWrites.size > 0) {
6174
+ const all = Array.from(pendingWrites.values());
6175
+ pendingWrites.clear();
6176
+ await Promise.all(all);
6177
+ }
6178
+ }
6179
+ function clearSession(agentId) {
6180
+ sessions.delete(agentId);
6181
+ }
6182
+ function enqueueSessionWrite(cwd, agentId, fn) {
6183
+ const key = transcriptKey(cwd, agentId);
6184
+ const prior = pendingWrites.get(key) ?? Promise.resolve();
6185
+ const result = prior.then(fn);
6186
+ pendingWrites.set(
6187
+ key,
6188
+ result.then(
6189
+ () => void 0,
6190
+ () => void 0
6191
+ )
6192
+ );
6193
+ return result;
6194
+ }
6195
+ var pendingWrites, recordCounts;
6196
+ var init_agent_session = __esm({
6197
+ "src/internal/session/agent-session.ts"() {
6198
+ init_agent_session_store();
6199
+ init_session_cache();
6200
+ init_session_cache();
6201
+ pendingWrites = /* @__PURE__ */ new Map();
6202
+ recordCounts = /* @__PURE__ */ new Map();
6203
+ }
6204
+ });
6164
6205
  async function withToolWhitelist(whitelist, fn) {
6165
6206
  return toolWhitelistStore.run(whitelist, fn);
6166
6207
  }
@@ -6255,10 +6296,10 @@ var init_context = __esm({
6255
6296
  }
6256
6297
  });
6257
6298
 
6258
- // src/goal-loop.ts
6299
+ // src/internal/runtime/lifecycle/goal-marker.ts
6259
6300
  var GOAL_CONTINUATION_MARKER;
6260
- var init_goal_loop = __esm({
6261
- "src/goal-loop.ts"() {
6301
+ var init_goal_marker = __esm({
6302
+ "src/internal/runtime/lifecycle/goal-marker.ts"() {
6262
6303
  GOAL_CONTINUATION_MARKER = "[[theokit:goal-continuation]]";
6263
6304
  }
6264
6305
  });
@@ -6432,7 +6473,7 @@ ${lastResponse.slice(-1e3)}`
6432
6473
  }
6433
6474
  var init_run_until = __esm({
6434
6475
  "src/internal/runtime/lifecycle/run-until.ts"() {
6435
- init_goal_loop();
6476
+ init_goal_marker();
6436
6477
  }
6437
6478
  });
6438
6479
 
@@ -10603,6 +10644,7 @@ function parseDecisionFromStdout(stdout) {
10603
10644
  }
10604
10645
 
10605
10646
  // src/internal/runtime/lifecycle/post-run-lifecycle.ts
10647
+ init_compaction();
10606
10648
  init_run_events();
10607
10649
 
10608
10650
  // src/internal/memory/storage/session-summary-writer.ts
@@ -10672,6 +10714,12 @@ function resolveActiveMemorySummaryForSend(legacySummary, portPathEnabled) {
10672
10714
  return legacySummary;
10673
10715
  }
10674
10716
 
10717
+ // src/internal/runtime/lifecycle/context-budget-event.ts
10718
+ function buildContextBudgetEvent(model, resolved) {
10719
+ if (resolved.source !== "fallback") return void 0;
10720
+ return { type: "compaction_fallback", model, window: resolved.window };
10721
+ }
10722
+
10675
10723
  // src/internal/runtime/lifecycle/post-run-lifecycle.ts
10676
10724
  async function runPostRunLifecycle(inputs) {
10677
10725
  const {
@@ -10697,18 +10745,15 @@ async function runPostRunLifecycle(inputs) {
10697
10745
  appendSessionMessage(agentId, { role: "assistant", text: result.result });
10698
10746
  }
10699
10747
  const conversation = await safeConversation(run);
10700
- const contextWindow = getCatalogModelInfo(model)?.limit?.context;
10701
- if (contextWindow === void 0) {
10702
- const g = globalThis;
10703
- const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.compact.no-cw-warned");
10704
- const warned3 = g[sym] ??= /* @__PURE__ */ new Set();
10705
- if (!warned3.has(model)) {
10706
- warned3.add(model);
10707
- process.stderr.write(
10708
- `[theokit-sdk] auto-compaction disabled: model "${model}" has no context-window entry in the catalog
10709
- `
10710
- );
10711
- }
10748
+ const resolvedWindow = resolveEffectiveContextWindow({
10749
+ catalog: getCatalogModelInfo(model)?.limit?.context,
10750
+ margin: CONTEXT_WINDOW_MARGIN,
10751
+ floor: CONTEXT_WINDOW_FLOOR
10752
+ });
10753
+ const contextWindow = resolvedWindow.window;
10754
+ const budgetEvent = buildContextBudgetEvent(model, resolvedWindow);
10755
+ if (budgetEvent !== void 0 && onRunEvent !== void 0) {
10756
+ emitRunEvent(onRunEvent, budgetEvent);
10712
10757
  }
10713
10758
  const lastRequestUsage = result.usage?.requests?.at(-1)?.totalTokens;
10714
10759
  const usageForTrigger = lastRequestUsage ?? result.usage?.totalTokens;
@@ -15680,6 +15725,71 @@ function registerPluginProviderProfiles(entries) {
15680
15725
 
15681
15726
  // src/internal/local-agent/real-local-run.ts
15682
15727
  init_async_local_storage();
15728
+
15729
+ // src/internal/local-agent/mcp-pool.ts
15730
+ var DEFAULT_IDLE_TTL_MS = 6e5;
15731
+ function configKey(config) {
15732
+ return JSON.stringify(
15733
+ config,
15734
+ (_k, v) => v !== null && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(
15735
+ Object.entries(v).sort(([a], [b]) => a < b ? -1 : 1)
15736
+ ) : v
15737
+ );
15738
+ }
15739
+ var McpClientPool = class {
15740
+ entries = /* @__PURE__ */ new Map();
15741
+ idleTtlMs;
15742
+ now;
15743
+ constructor(options = {}) {
15744
+ this.idleTtlMs = options.idleTtlMs ?? DEFAULT_IDLE_TTL_MS;
15745
+ this.now = options.now ?? Date.now;
15746
+ }
15747
+ /**
15748
+ * Return the pooled client for `(sessionId, serverName, config)`, creating it via `factory` on
15749
+ * first use. Every call refreshes idleness — the TTL measures time SINCE LAST USE, not age.
15750
+ *
15751
+ * Synchronous by design: `createMcpClient` is itself synchronous (the handshake happens later, on
15752
+ * `initialize`), so there is no `await` between the lookup and the insert and two concurrent runs
15753
+ * in the same session cannot both miss the cache.
15754
+ */
15755
+ acquire(sessionId, serverName, config, factory) {
15756
+ const key = `${sessionId}\0${serverName}\0${configKey(config)}`;
15757
+ const existing = this.entries.get(key);
15758
+ if (existing !== void 0) {
15759
+ existing.lastUsedAt = this.now();
15760
+ return existing.client;
15761
+ }
15762
+ const client = factory();
15763
+ this.entries.set(key, { client, sessionId, lastUsedAt: this.now() });
15764
+ return client;
15765
+ }
15766
+ /**
15767
+ * Close and forget every client of ONE session. Scoped deliberately: clearing the whole map would
15768
+ * tear down the servers of every concurrent conversation.
15769
+ */
15770
+ disposeSession(sessionId, close) {
15771
+ for (const [key, entry] of this.entries) {
15772
+ if (entry.sessionId !== sessionId) continue;
15773
+ close(entry.client);
15774
+ this.entries.delete(key);
15775
+ }
15776
+ }
15777
+ /** Close and forget every client idle for longer than the TTL. */
15778
+ reapIdle(close) {
15779
+ const cutoff = this.now() - this.idleTtlMs;
15780
+ for (const [key, entry] of this.entries) {
15781
+ if (entry.lastUsedAt > cutoff) continue;
15782
+ close(entry.client);
15783
+ this.entries.delete(key);
15784
+ }
15785
+ }
15786
+ /** Live pooled-client count — for observability and tests. */
15787
+ size() {
15788
+ return this.entries.size;
15789
+ }
15790
+ };
15791
+
15792
+ // src/internal/local-agent/real-local-run.ts
15683
15793
  init_real_local_run_provider();
15684
15794
 
15685
15795
  // src/a2a/subagent.ts
@@ -16098,12 +16208,23 @@ function buildLoopInputs(options, runId, userText, userImages) {
16098
16208
  ...options.agentOptions.memoryProvider !== void 0 ? { memoryProvider: options.agentOptions.memoryProvider } : {}
16099
16209
  };
16100
16210
  }
16211
+ var sessionMcpPool = new McpClientPool();
16212
+ function disposeSessionMcpClients(agentId) {
16213
+ sessionMcpPool.disposeSession(agentId, (client) => {
16214
+ void client.close();
16215
+ });
16216
+ }
16101
16217
  function buildMcpMap(options) {
16102
16218
  const map = /* @__PURE__ */ new Map();
16103
16219
  const inline = options.sendOptions.mcpServers ?? options.agentOptions.mcpServers;
16104
16220
  if (inline === void 0) return map;
16221
+ const pooled = options.agentOptions.mcpLifecycle === "session";
16222
+ if (pooled) sessionMcpPool.reapIdle((c) => void c.close());
16105
16223
  for (const [name, config] of Object.entries(inline)) {
16106
- map.set(name, createMcpClient(name, config));
16224
+ map.set(
16225
+ name,
16226
+ pooled ? sessionMcpPool.acquire(options.agentId, name, config, () => createMcpClient(name, config)) : createMcpClient(name, config)
16227
+ );
16107
16228
  }
16108
16229
  return map;
16109
16230
  }
@@ -17168,7 +17289,9 @@ async function loadDriver(filePath) {
17168
17289
  }
17169
17290
  try {
17170
17291
  const mod = await (driverLoaderOverrides?.nodeSqlite?.() ?? Promise.resolve(
17171
- process.getBuiltinModule?.("node:sqlite") ?? (() => {
17292
+ process.getBuiltinModule?.(
17293
+ "node:sqlite"
17294
+ ) ?? (() => {
17172
17295
  throw new Error("node:sqlite built-in unavailable (Node < 22.3)");
17173
17296
  })()
17174
17297
  ));
@@ -18218,7 +18341,8 @@ var LocalAgentMemory = class {
18218
18341
  const message = cause instanceof Error ? cause.message : String(cause);
18219
18342
  const g = globalThis;
18220
18343
  const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.memory.warned");
18221
- const warned3 = g[sym] ??= /* @__PURE__ */ new Set();
18344
+ g[sym] ??= /* @__PURE__ */ new Set();
18345
+ const warned3 = g[sym];
18222
18346
  if (!warned3.has(message)) {
18223
18347
  warned3.add(message);
18224
18348
  process.stderr.write(`[theokit-sdk] memory tools unavailable: ${message}
@@ -19402,6 +19526,7 @@ var LocalAgent = class {
19402
19526
  liveAgentRegistry.forget(this.agentId);
19403
19527
  this.lifecycleAbortController.abort();
19404
19528
  await withCwdMutex(`agent-send:${this.agentId}`, () => Promise.resolve());
19529
+ disposeSessionMcpClients(this.agentId);
19405
19530
  await flushSessionWrites();
19406
19531
  await flushRegistrySaves(this.workspaceCwd);
19407
19532
  }
@@ -19702,8 +19827,8 @@ async function getRegisteredAgentOrThrow(agentId) {
19702
19827
  // src/agent.ts
19703
19828
  init_errors();
19704
19829
  init_discovery();
19705
- init_agent_session();
19706
19830
  init_agent_factory_registry();
19831
+ init_agent_session();
19707
19832
  var streamObjectImport;
19708
19833
  var Agent = class _Agent {
19709
19834
  constructor() {
@@ -19995,26 +20120,26 @@ var Agent = class _Agent {
19995
20120
  reg = getRegisteredAgent(agentId);
19996
20121
  }
19997
20122
  if (reg === void 0 || reg.runtime !== "local") {
19998
- throw new UnknownAgentError(`No local agent "${agentId}" registered \u2014 compact targets local sessions.`);
20123
+ throw new UnknownAgentError(
20124
+ `No local agent "${agentId}" registered \u2014 compact targets local sessions.`
20125
+ );
19999
20126
  }
20000
- const cwd = reg.cwd ?? process.cwd();
20001
- const optModel = reg.options.model;
20002
- const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20003
20127
  const { compactSessionTranscript: compactSessionTranscript2, buildDefaultSummarizer: buildDefaultSummarizer2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
20004
- const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20005
- const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20006
- const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20007
- const store = new FsSessionStore2({ baseDir, cwd });
20008
- return enqueueSessionWrite(cwd, agentId, () => compactSessionTranscript2({
20009
- store,
20010
- loc: { cwd, agentId, model },
20011
- sessionId: agentId,
20012
- trigger: options.trigger ?? "manual",
20013
- summarize: options.summarize ?? buildDefaultSummarizer2({
20014
- agentModel: model,
20015
- ...reg.options.apiKey !== void 0 ? { apiKey: reg.options.apiKey } : {}
20128
+ const { cwd, model, store } = await abrirStoreLocal(reg);
20129
+ return enqueueSessionWrite(
20130
+ cwd,
20131
+ agentId,
20132
+ () => compactSessionTranscript2({
20133
+ store,
20134
+ loc: { cwd, agentId, model },
20135
+ sessionId: agentId,
20136
+ trigger: options.trigger ?? "manual",
20137
+ summarize: options.summarize ?? buildDefaultSummarizer2({
20138
+ agentModel: model,
20139
+ ...reg.options.apiKey !== void 0 ? { apiKey: reg.options.apiKey } : {}
20140
+ })
20016
20141
  })
20017
- }));
20142
+ );
20018
20143
  }
20019
20144
  /**
20020
20145
  * M51 — inject a SYNTHETIC user+assistant pair into a LOCAL session's persisted transcript WITHOUT
@@ -20031,16 +20156,12 @@ var Agent = class _Agent {
20031
20156
  reg = getRegisteredAgent(agentId);
20032
20157
  }
20033
20158
  if (reg === void 0 || reg.runtime !== "local") {
20034
- throw new UnknownAgentError(`No local agent "${agentId}" registered \u2014 injectSessionTurn targets local sessions.`);
20159
+ throw new UnknownAgentError(
20160
+ `No local agent "${agentId}" registered \u2014 injectSessionTurn targets local sessions.`
20161
+ );
20035
20162
  }
20036
- const cwd = reg.cwd ?? process.cwd();
20037
- const optModel = reg.options.model;
20038
- const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20039
20163
  const { injectSessionTurn: injectSessionTurn2 } = await Promise.resolve().then(() => (init_inject_session(), inject_session_exports));
20040
- const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20041
- const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20042
- const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20043
- const store = new FsSessionStore2({ baseDir, cwd });
20164
+ const { cwd, model, store } = await abrirStoreLocal(reg);
20044
20165
  await injectSessionTurn2({
20045
20166
  store,
20046
20167
  loc: { cwd, agentId, model },
@@ -20082,6 +20203,15 @@ setAgentFacade({
20082
20203
  resume: (agentId, options) => Agent.resume(agentId, options),
20083
20204
  batch: (prompts, options) => Agent.batch(prompts, options)
20084
20205
  });
20206
+ async function abrirStoreLocal(reg) {
20207
+ const cwd = reg.cwd ?? process.cwd();
20208
+ const optModel = reg.options.model;
20209
+ const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20210
+ const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20211
+ const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20212
+ const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20213
+ return { cwd, model, store: new FsSessionStore2({ baseDir, cwd }) };
20214
+ }
20085
20215
  var JsonlParseError = class extends Error {
20086
20216
  constructor(message, line) {
20087
20217
  super(message);