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