@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.js CHANGED
@@ -1594,6 +1594,44 @@ var init_plugin_guards = __esm({
1594
1594
  }
1595
1595
  });
1596
1596
 
1597
+ // src/compaction.ts
1598
+ function resolveEffectiveContextWindow(input) {
1599
+ if (!(input.margin > 0) || input.margin > 1) {
1600
+ throw new ContextWindowMarginError(input.margin);
1601
+ }
1602
+ const withMargin = (raw) => Math.floor(raw * input.margin);
1603
+ if (input.override !== void 0) {
1604
+ const clamped = input.catalog !== void 0 && input.override > input.catalog;
1605
+ const raw = clamped ? input.catalog : input.override;
1606
+ return { window: withMargin(raw), source: "override", clamped };
1607
+ }
1608
+ if (input.catalog !== void 0) {
1609
+ return { window: withMargin(input.catalog), source: "catalog", clamped: false };
1610
+ }
1611
+ return { window: withMargin(input.floor ?? 0), source: "fallback", clamped: false };
1612
+ }
1613
+ function estimateTokens(text) {
1614
+ return Math.ceil(text.length / 4);
1615
+ }
1616
+ var ContextWindowMarginError, CONTEXT_WINDOW_MARGIN, CONTEXT_WINDOW_FLOOR;
1617
+ var init_compaction = __esm({
1618
+ "src/compaction.ts"() {
1619
+ init_errors();
1620
+ ContextWindowMarginError = class extends TheokitAgentError {
1621
+ constructor(margin) {
1622
+ super(
1623
+ `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.`,
1624
+ { code: "invalid_context_window_margin" }
1625
+ );
1626
+ this.margin = margin;
1627
+ }
1628
+ margin;
1629
+ };
1630
+ CONTEXT_WINDOW_MARGIN = 0.95;
1631
+ CONTEXT_WINDOW_FLOOR = 128e3;
1632
+ }
1633
+ });
1634
+
1597
1635
  // src/types/run-events.ts
1598
1636
  function emitRunEvent(sink, event) {
1599
1637
  if (sink === void 0) return;
@@ -1606,6 +1644,18 @@ var init_run_events = __esm({
1606
1644
  "src/types/run-events.ts"() {
1607
1645
  }
1608
1646
  });
1647
+
1648
+ // src/internal/global-singleton.ts
1649
+ function globalSingleton(key, create) {
1650
+ const g = globalThis;
1651
+ const sym = Symbol.for(key);
1652
+ if (g[sym] === void 0) g[sym] = create();
1653
+ return g[sym];
1654
+ }
1655
+ var init_global_singleton = __esm({
1656
+ "src/internal/global-singleton.ts"() {
1657
+ }
1658
+ });
1609
1659
  var MODALITIES, costSchema, limitSchema, modalitiesSchema, catalogModelSchema;
1610
1660
  var init_catalog_schema = __esm({
1611
1661
  "src/internal/providers/catalog-schema.ts"() {
@@ -1646,12 +1696,6 @@ var init_catalog_schema = __esm({
1646
1696
  });
1647
1697
 
1648
1698
  // src/internal/providers/registry.ts
1649
- function globalSingleton(key, create) {
1650
- const g = globalThis;
1651
- const sym = Symbol.for(key);
1652
- if (g[sym] === void 0) g[sym] = create();
1653
- return g[sym];
1654
- }
1655
1699
  function registerProvider(profile) {
1656
1700
  if (REGISTRY.has(profile.name)) {
1657
1701
  process.stderr.write(`[theokit-sdk] Provider "${profile.name}" overridden by user plugin.
@@ -1676,6 +1720,7 @@ function getProviderProfile(name) {
1676
1720
  var REGISTRY, ALIASES;
1677
1721
  var init_registry = __esm({
1678
1722
  "src/internal/providers/registry.ts"() {
1723
+ init_global_singleton();
1679
1724
  REGISTRY = globalSingleton(
1680
1725
  "theokit-sdk.providers.registry",
1681
1726
  () => /* @__PURE__ */ new Map()
@@ -1683,12 +1728,6 @@ var init_registry = __esm({
1683
1728
  ALIASES = globalSingleton("theokit-sdk.providers.aliases", () => /* @__PURE__ */ new Map());
1684
1729
  }
1685
1730
  });
1686
- function globalSingleton2(key, create) {
1687
- const g = globalThis;
1688
- const sym = Symbol.for(key);
1689
- if (g[sym] === void 0) g[sym] = create();
1690
- return g[sym];
1691
- }
1692
1731
  function getCatalogModelInfo(key) {
1693
1732
  ensureModelIndexLoaded();
1694
1733
  return modelInfoIndex.get(key);
@@ -1777,32 +1816,24 @@ function registerCatalogProviders(opts) {
1777
1816
  var __dirname_resolved, modelInfoIndex, patchedModelKeys, indexState;
1778
1817
  var init_catalog_loader = __esm({
1779
1818
  "src/internal/providers/catalog-loader.ts"() {
1819
+ init_global_singleton();
1780
1820
  init_catalog_schema();
1781
1821
  init_registry();
1782
1822
  __dirname_resolved = dirname(fileURLToPath(import.meta.url));
1783
- modelInfoIndex = globalSingleton2(
1823
+ modelInfoIndex = globalSingleton(
1784
1824
  "theokit-sdk.providers.model-info-index",
1785
1825
  () => /* @__PURE__ */ new Map()
1786
1826
  );
1787
- patchedModelKeys = globalSingleton2(
1827
+ patchedModelKeys = globalSingleton(
1788
1828
  "theokit-sdk.providers.model-info-patched",
1789
1829
  () => /* @__PURE__ */ new Set()
1790
1830
  );
1791
- indexState = globalSingleton2("theokit-sdk.providers.model-info-loaded", () => ({
1831
+ indexState = globalSingleton("theokit-sdk.providers.model-info-loaded", () => ({
1792
1832
  loaded: false
1793
1833
  }));
1794
1834
  }
1795
1835
  });
1796
1836
 
1797
- // src/compaction.ts
1798
- function estimateTokens(text) {
1799
- return Math.ceil(text.length / 4);
1800
- }
1801
- var init_compaction = __esm({
1802
- "src/compaction.ts"() {
1803
- }
1804
- });
1805
-
1806
1837
  // src/internal/providers/builtin/anthropic.ts
1807
1838
  var ANTHROPIC;
1808
1839
  var init_anthropic = __esm({
@@ -2172,11 +2203,12 @@ function writeCredential(cred, config, env = {}) {
2172
2203
  var CredentialError, apiFileSchema, oauthFileSchema, fileSchema;
2173
2204
  var init_credential_store = __esm({
2174
2205
  "src/internal/auth/credential-store.ts"() {
2175
- CredentialError = class extends Error {
2176
- constructor(message) {
2177
- super(message);
2178
- this.name = "CredentialError";
2179
- }
2206
+ init_errors();
2207
+ CredentialError = class extends AuthenticationError {
2208
+ // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`
2209
+ // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the
2210
+ // suite was green with the broken assignment because the transpiler strips the type.
2211
+ name = "CredentialError";
2180
2212
  };
2181
2213
  apiFileSchema = z.object({
2182
2214
  type: z.literal("api").optional(),
@@ -2598,12 +2630,6 @@ var init_builtin = __esm({
2598
2630
  })();
2599
2631
  }
2600
2632
  });
2601
- function globalSingleton3(key, create) {
2602
- const g = globalThis;
2603
- const sym = Symbol.for(key);
2604
- if (g[sym] === void 0) g[sym] = create();
2605
- return g[sym];
2606
- }
2607
2633
  function pluginsRoot() {
2608
2634
  return join(homedir(), ".theokit", "plugins", "model-providers");
2609
2635
  }
@@ -2695,8 +2721,9 @@ async function loadOne(dir, entryName) {
2695
2721
  var discoveryState;
2696
2722
  var init_discovery = __esm({
2697
2723
  "src/internal/providers/discovery.ts"() {
2724
+ init_global_singleton();
2698
2725
  init_registry();
2699
- discoveryState = globalSingleton3("theokit-sdk.providers.discovered", () => ({
2726
+ discoveryState = globalSingleton("theokit-sdk.providers.discovered", () => ({
2700
2727
  done: false
2701
2728
  }));
2702
2729
  }
@@ -4372,6 +4399,68 @@ var init_hermes_tool_extract = __esm({
4372
4399
  }
4373
4400
  });
4374
4401
 
4402
+ // src/internal/llm/openai-messages.ts
4403
+ function toOpenAIMessages(message) {
4404
+ if (message.role === "system") return [systemMessage(message)];
4405
+ if (message.role === "user") return userOrToolMessages(message);
4406
+ return [assistantMessage(message)];
4407
+ }
4408
+ function systemMessage(message) {
4409
+ return { role: "system", content: joinTextParts2(message) };
4410
+ }
4411
+ function joinTextParts2(message) {
4412
+ return message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
4413
+ }
4414
+ function userOrToolMessages(message) {
4415
+ const out = [];
4416
+ for (const part of message.content) {
4417
+ if (part.type === "tool_result") {
4418
+ out.push({
4419
+ role: "tool",
4420
+ tool_call_id: part.toolUseId,
4421
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
4422
+ // image block fails fast (ConfigurationError).
4423
+ content: toStringToolResultContent(part.content, "openai")
4424
+ });
4425
+ }
4426
+ }
4427
+ const userText = joinTextParts2(message);
4428
+ const imageParts = message.content.filter(
4429
+ (p) => p.type === "image"
4430
+ );
4431
+ if (imageParts.length > 0) {
4432
+ const content = [];
4433
+ if (userText.length > 0) content.push({ type: "text", text: userText });
4434
+ for (const img of imageParts) {
4435
+ const url = img.source.type === "base64" ? `data:${img.source.media_type};base64,${img.source.data}` : img.source.url;
4436
+ content.push({ type: "image_url", image_url: { url } });
4437
+ }
4438
+ out.push({ role: "user", content });
4439
+ } else if (userText.length > 0) {
4440
+ out.push({ role: "user", content: userText });
4441
+ }
4442
+ return out;
4443
+ }
4444
+ function assistantMessage(message) {
4445
+ const text = joinTextParts2(message);
4446
+ const toolCalls = message.content.filter((part) => part.type === "tool_use").map((part) => {
4447
+ const tc = part;
4448
+ return {
4449
+ id: tc.id,
4450
+ type: "function",
4451
+ function: { name: tc.name, arguments: JSON.stringify(tc.input) }
4452
+ };
4453
+ });
4454
+ const result = { role: "assistant", content: text };
4455
+ if (toolCalls.length > 0) result.tool_calls = toolCalls;
4456
+ return result;
4457
+ }
4458
+ var init_openai_messages = __esm({
4459
+ "src/internal/llm/openai-messages.ts"() {
4460
+ init_tool_result_content();
4461
+ }
4462
+ });
4463
+
4375
4464
  // src/internal/llm/openai.ts
4376
4465
  function deriveChatPath(baseUrl) {
4377
4466
  try {
@@ -4433,61 +4522,6 @@ function encodeOpenAIResponseFormat(rf) {
4433
4522
  }
4434
4523
  };
4435
4524
  }
4436
- function toOpenAIMessages(message) {
4437
- if (message.role === "system") return [systemMessage(message)];
4438
- if (message.role === "user") return userOrToolMessages(message);
4439
- return [assistantMessage(message)];
4440
- }
4441
- function systemMessage(message) {
4442
- return { role: "system", content: joinTextParts2(message) };
4443
- }
4444
- function joinTextParts2(message) {
4445
- return message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
4446
- }
4447
- function userOrToolMessages(message) {
4448
- const out = [];
4449
- for (const part of message.content) {
4450
- if (part.type === "tool_result") {
4451
- out.push({
4452
- role: "tool",
4453
- tool_call_id: part.toolUseId,
4454
- // SE7 — this wire's tool role is string-only: text blocks flatten; an
4455
- // image block fails fast (ConfigurationError).
4456
- content: toStringToolResultContent(part.content, "openai")
4457
- });
4458
- }
4459
- }
4460
- const userText = joinTextParts2(message);
4461
- const imageParts = message.content.filter(
4462
- (p) => p.type === "image"
4463
- );
4464
- if (imageParts.length > 0) {
4465
- const content = [];
4466
- if (userText.length > 0) content.push({ type: "text", text: userText });
4467
- for (const img of imageParts) {
4468
- const url = img.source.type === "base64" ? `data:${img.source.media_type};base64,${img.source.data}` : img.source.url;
4469
- content.push({ type: "image_url", image_url: { url } });
4470
- }
4471
- out.push({ role: "user", content });
4472
- } else if (userText.length > 0) {
4473
- out.push({ role: "user", content: userText });
4474
- }
4475
- return out;
4476
- }
4477
- function assistantMessage(message) {
4478
- const text = joinTextParts2(message);
4479
- const toolCalls = message.content.filter((part) => part.type === "tool_use").map((part) => {
4480
- const tc = part;
4481
- return {
4482
- id: tc.id,
4483
- type: "function",
4484
- function: { name: tc.name, arguments: JSON.stringify(tc.input) }
4485
- };
4486
- });
4487
- const result = { role: "assistant", content: text };
4488
- if (toolCalls.length > 0) result.tool_calls = toolCalls;
4489
- return result;
4490
- }
4491
4525
  var OpenAIClient, OpenAIStreamAccumulator, openAISystemText;
4492
4526
  var init_openai2 = __esm({
4493
4527
  "src/internal/llm/openai.ts"() {
@@ -4496,8 +4530,8 @@ var init_openai2 = __esm({
4496
4530
  init_openai_compatible2();
4497
4531
  init_finish();
4498
4532
  init_hermes_tool_extract();
4533
+ init_openai_messages();
4499
4534
  init_sse();
4500
- init_tool_result_content();
4501
4535
  OpenAIClient = class {
4502
4536
  constructor(options) {
4503
4537
  this.options = options;
@@ -5586,6 +5620,14 @@ function selectTransport(profile, apiKey) {
5586
5620
  const ctx = { apiKey };
5587
5621
  return { fetch: profile.transform.fetch?.(ctx), headers: profile.transform.headers?.(ctx) };
5588
5622
  };
5623
+ const comTransform = (opts, criar) => {
5624
+ const t = applyTransform();
5625
+ assertOAuthResolved(t);
5626
+ if (t.fetch !== void 0) opts.fetch = t.fetch;
5627
+ const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5628
+ if (merged !== void 0) opts.extraHeaders = merged;
5629
+ return criar(opts);
5630
+ };
5589
5631
  const assertOAuthResolved = (t) => {
5590
5632
  if (apiKey !== "__oauth_lazy_token__") return;
5591
5633
  const auth = t.headers?.authorization ?? t.headers?.Authorization;
@@ -5614,12 +5656,7 @@ function selectTransport(profile, apiKey) {
5614
5656
  }
5615
5657
  const envOverride = resolveBaseUrlEnvOverride(profile.name);
5616
5658
  if (envOverride !== void 0) opts.baseUrl = envOverride;
5617
- const t = applyTransform();
5618
- assertOAuthResolved(t);
5619
- if (t.fetch !== void 0) opts.fetch = t.fetch;
5620
- const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5621
- if (merged !== void 0) opts.extraHeaders = merged;
5622
- return new OpenAIClient(opts);
5659
+ return comTransform(opts, (o) => new OpenAIClient(o));
5623
5660
  }
5624
5661
  if (profile.apiMode === "anthropic_messages") {
5625
5662
  if (profile.name === "vertex") {
@@ -5628,12 +5665,7 @@ function selectTransport(profile, apiKey) {
5628
5665
  }
5629
5666
  const opts = { apiKey };
5630
5667
  opts.baseUrl = process.env.ANTHROPIC_API_BASE_URL ?? profile.baseUrl;
5631
- const t = applyTransform();
5632
- assertOAuthResolved(t);
5633
- if (t.fetch !== void 0) opts.fetch = t.fetch;
5634
- const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
5635
- if (merged !== void 0) opts.extraHeaders = merged;
5636
- return new AnthropicClient(opts);
5668
+ return comTransform(opts, (o) => new AnthropicClient(o));
5637
5669
  }
5638
5670
  if (profile.apiMode === "bedrock_anthropic") {
5639
5671
  const realKey = apiKey === "__bedrock_lazy_token__" ? void 0 : apiKey;
@@ -5790,202 +5822,52 @@ function buildCompressionPrompt(messages) {
5790
5822
 
5791
5823
  --- CONVERSATION TO SUMMARIZE ---
5792
5824
  ${formatted}
5793
- --- END ---`;
5794
- }
5795
- async function compressConversationWindow(opts) {
5796
- const userPrompt = buildCompressionPrompt(opts.messages);
5797
- let summary;
5798
- try {
5799
- summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
5800
- } catch (cause) {
5801
- throw new CompressionFailedError(
5802
- `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
5803
- { cause: cause instanceof Error ? cause : void 0 }
5804
- );
5805
- }
5806
- if (!summary || summary.trim().length === 0) {
5807
- throw new CompressionFailedError(
5808
- "Compression LLM returned empty summary \u2014 reduction ineffective."
5809
- );
5810
- }
5811
- return {
5812
- role: "system",
5813
- content: `[Compressed conversation summary]: ${summary.trim()}`
5814
- };
5815
- }
5816
- var CompressionFailedError, COMPRESSION_SYSTEM;
5817
- var init_compression_summarizer = __esm({
5818
- "src/internal/runtime/compression/compression-summarizer.ts"() {
5819
- CompressionFailedError = class extends Error {
5820
- name = "CompressionFailedError";
5821
- };
5822
- 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.";
5823
- }
5824
- });
5825
-
5826
- // src/internal/session/agent-session-store.ts
5827
- function seedTranscript(prior, opts) {
5828
- return SessionTranscript.fromRecords(prior, opts);
5829
- }
5830
- function mapAgentTurn(steps) {
5831
- const assistant = {};
5832
- const toolResults = [];
5833
- const toolCalls = [];
5834
- for (const step of steps) {
5835
- if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
5836
- else if (step.type === "assistantMessage") assistant.text = step.message.text;
5837
- else if (step.type === "toolCall")
5838
- toolCalls.push({
5839
- id: step.message.callId,
5840
- name: step.message.name,
5841
- input: step.message.args ?? {}
5842
- });
5843
- else
5844
- toolResults.push({
5845
- toolUseId: step.message.callId,
5846
- content: step.message.result,
5847
- isError: step.message.isError
5848
- });
5849
- }
5850
- if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
5851
- return { assistant, toolResults };
5852
- }
5853
- function hasAssistantContent(a) {
5854
- return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
5855
- }
5856
- function appendConversation(transcript, conversation) {
5857
- for (const ct of conversation) {
5858
- if (ct.type !== "agentConversationTurn") continue;
5859
- const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
5860
- if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
5861
- if (toolResults.length > 0) transcript.appendToolResults(toolResults);
5862
- }
5863
- }
5864
- async function readSessionMessages(store, agentId) {
5865
- const records = await store.readRecords(agentId);
5866
- return reconstructMessages(records).map(narrowToSessionMessage);
5867
- }
5868
- function partToText(p) {
5869
- if (p.type === "text") return p.text ?? "";
5870
- if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
5871
- if (p.type === "tool_result") {
5872
- const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
5873
- return `[tool result] ${body}`;
5874
- }
5875
- return "";
5876
- }
5877
- function narrowToSessionMessage(m) {
5878
- const role = m.role === "user" ? "user" : "assistant";
5879
- const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
5880
- return { role, text };
5881
- }
5882
- function deltaRecords(transcript, priorLength) {
5883
- return transcript.records().slice(priorLength);
5884
- }
5885
- async function persistTurn(store, loc, sessionId, turn) {
5886
- const prior = await store.readRecords(loc.agentId);
5887
- const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
5888
- transcript.appendUserTurn(turn.userText);
5889
- appendConversation(transcript, turn.conversation);
5890
- await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
5891
- }
5892
- var init_agent_session_store = __esm({
5893
- "src/internal/session/agent-session-store.ts"() {
5894
- init_session_transcript();
5895
- }
5896
- });
5897
-
5898
- // src/internal/session/agent-session.ts
5899
- function transcriptKey(cwd, agentId) {
5900
- return `${cwd}::${agentId}`;
5901
- }
5902
- function appendSessionMessage(agentId, message) {
5903
- const existing = sessions.get(agentId) ?? [];
5904
- existing.push(message);
5905
- sessions.set(agentId, existing);
5906
- }
5907
- function getSessionMessages(agentId) {
5908
- return sessions.get(agentId) ?? [];
5909
- }
5910
- function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
5911
- const key = transcriptKey(loc.cwd, loc.agentId);
5912
- const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
5913
- try {
5914
- await persistTurn(store, loc, sessionId, turn);
5915
- const count = (recordCounts.get(key) ?? 0) + 1;
5916
- recordCounts.set(key, count);
5917
- if (turn.autoCompact !== void 0) {
5918
- const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
5919
- const fired = await autoCompactIfNeeded2({
5920
- store,
5921
- loc,
5922
- sessionId,
5923
- usageTotal: turn.autoCompact.usageTotal,
5924
- contextWindow: turn.autoCompact.contextWindow,
5925
- turnCount: count,
5926
- summarize: turn.autoCompact.summarize
5927
- });
5928
- if (fired) onCompact?.();
5929
- }
5930
- } catch (cause) {
5931
- const msg = cause instanceof Error ? cause.message : String(cause);
5932
- process.stderr.write(
5933
- `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
5934
- `
5935
- );
5936
- }
5937
- });
5938
- pendingWrites.set(
5939
- key,
5940
- chained.then(
5941
- () => void 0,
5942
- () => void 0
5943
- )
5944
- );
5945
- }
5946
- async function hydrateSession(agentId, loc) {
5947
- const key = transcriptKey(loc.cwd, agentId);
5948
- if (hydratedKeys.has(key)) return;
5949
- hydratedKeys.add(key);
5950
- const persisted = await readSessionMessages(loc.store, agentId);
5951
- if (persisted.length === 0) return;
5952
- sessions.set(agentId, persisted);
5953
- }
5954
- async function flushSessionWrites() {
5955
- while (pendingWrites.size > 0) {
5956
- const all = Array.from(pendingWrites.values());
5957
- pendingWrites.clear();
5958
- await Promise.all(all);
5825
+ --- END ---`;
5826
+ }
5827
+ async function compressConversationWindow(opts) {
5828
+ const userPrompt = buildCompressionPrompt(opts.messages);
5829
+ let summary;
5830
+ try {
5831
+ summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
5832
+ } catch (cause) {
5833
+ throw new CompressionFailedError(
5834
+ `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
5835
+ { cause: cause instanceof Error ? cause : void 0 }
5836
+ );
5837
+ }
5838
+ if (!summary || summary.trim().length === 0) {
5839
+ throw new CompressionFailedError(
5840
+ "Compression LLM returned empty summary \u2014 reduction ineffective."
5841
+ );
5959
5842
  }
5843
+ return {
5844
+ role: "system",
5845
+ content: `[Compressed conversation summary]: ${summary.trim()}`
5846
+ };
5960
5847
  }
5961
- function clearSession(agentId) {
5962
- sessions.delete(agentId);
5848
+ var CompressionFailedError, COMPRESSION_SYSTEM;
5849
+ var init_compression_summarizer = __esm({
5850
+ "src/internal/runtime/compression/compression-summarizer.ts"() {
5851
+ CompressionFailedError = class extends Error {
5852
+ name = "CompressionFailedError";
5853
+ };
5854
+ 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.";
5855
+ }
5856
+ });
5857
+
5858
+ // src/internal/session/session-cache.ts
5859
+ function transcriptKey(cwd, agentId) {
5860
+ return `${cwd}::${agentId}`;
5963
5861
  }
5964
5862
  function invalidateSessionCache(cwd, agentId) {
5965
5863
  sessions.delete(agentId);
5966
5864
  hydratedKeys.delete(transcriptKey(cwd, agentId));
5967
5865
  }
5968
- function enqueueSessionWrite(cwd, agentId, fn) {
5969
- const key = transcriptKey(cwd, agentId);
5970
- const prior = pendingWrites.get(key) ?? Promise.resolve();
5971
- const result = prior.then(fn);
5972
- pendingWrites.set(
5973
- key,
5974
- result.then(
5975
- () => void 0,
5976
- () => void 0
5977
- )
5978
- );
5979
- return result;
5980
- }
5981
- var sessions, hydratedKeys, pendingWrites, recordCounts;
5982
- var init_agent_session = __esm({
5983
- "src/internal/session/agent-session.ts"() {
5984
- init_agent_session_store();
5866
+ var sessions, hydratedKeys;
5867
+ var init_session_cache = __esm({
5868
+ "src/internal/session/session-cache.ts"() {
5985
5869
  sessions = /* @__PURE__ */ new Map();
5986
5870
  hydratedKeys = /* @__PURE__ */ new Set();
5987
- pendingWrites = /* @__PURE__ */ new Map();
5988
- recordCounts = /* @__PURE__ */ new Map();
5989
5871
  }
5990
5872
  });
5991
5873
 
@@ -6147,7 +6029,7 @@ var init_compact_session = __esm({
6147
6029
  init_providers();
6148
6030
  init_compression_model_registry();
6149
6031
  init_compression_summarizer();
6150
- init_agent_session();
6032
+ init_session_cache();
6151
6033
  COMPACT_SUMMARY_MARKER = "[[theokit:compact-summary]]";
6152
6034
  COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
6153
6035
  autoCompactAttempts = (() => {
@@ -6158,6 +6040,165 @@ var init_compact_session = __esm({
6158
6040
  })();
6159
6041
  }
6160
6042
  });
6043
+
6044
+ // src/internal/session/agent-session-store.ts
6045
+ function seedTranscript(prior, opts) {
6046
+ return SessionTranscript.fromRecords(prior, opts);
6047
+ }
6048
+ function mapAgentTurn(steps) {
6049
+ const assistant = {};
6050
+ const toolResults = [];
6051
+ const toolCalls = [];
6052
+ for (const step of steps) {
6053
+ if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
6054
+ else if (step.type === "assistantMessage") assistant.text = step.message.text;
6055
+ else if (step.type === "toolCall")
6056
+ toolCalls.push({
6057
+ id: step.message.callId,
6058
+ name: step.message.name,
6059
+ input: step.message.args ?? {}
6060
+ });
6061
+ else
6062
+ toolResults.push({
6063
+ toolUseId: step.message.callId,
6064
+ content: step.message.result,
6065
+ isError: step.message.isError
6066
+ });
6067
+ }
6068
+ if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
6069
+ return { assistant, toolResults };
6070
+ }
6071
+ function hasAssistantContent(a) {
6072
+ return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
6073
+ }
6074
+ function appendConversation(transcript, conversation) {
6075
+ for (const ct of conversation) {
6076
+ if (ct.type !== "agentConversationTurn") continue;
6077
+ const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
6078
+ if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
6079
+ if (toolResults.length > 0) transcript.appendToolResults(toolResults);
6080
+ }
6081
+ }
6082
+ async function readSessionMessages(store, agentId) {
6083
+ const records = await store.readRecords(agentId);
6084
+ return reconstructMessages(records).map(narrowToSessionMessage);
6085
+ }
6086
+ function partToText(p) {
6087
+ if (p.type === "text") return p.text ?? "";
6088
+ if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
6089
+ if (p.type === "tool_result") {
6090
+ const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
6091
+ return `[tool result] ${body}`;
6092
+ }
6093
+ return "";
6094
+ }
6095
+ function narrowToSessionMessage(m) {
6096
+ const role = m.role === "user" ? "user" : "assistant";
6097
+ const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
6098
+ return { role, text };
6099
+ }
6100
+ function deltaRecords(transcript, priorLength) {
6101
+ return transcript.records().slice(priorLength);
6102
+ }
6103
+ async function persistTurn(store, loc, sessionId, turn) {
6104
+ const prior = await store.readRecords(loc.agentId);
6105
+ const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
6106
+ transcript.appendUserTurn(turn.userText);
6107
+ appendConversation(transcript, turn.conversation);
6108
+ await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
6109
+ }
6110
+ var init_agent_session_store = __esm({
6111
+ "src/internal/session/agent-session-store.ts"() {
6112
+ init_session_transcript();
6113
+ }
6114
+ });
6115
+
6116
+ // src/internal/session/agent-session.ts
6117
+ function appendSessionMessage(agentId, message) {
6118
+ const existing = sessions.get(agentId) ?? [];
6119
+ existing.push(message);
6120
+ sessions.set(agentId, existing);
6121
+ }
6122
+ function getSessionMessages(agentId) {
6123
+ return sessions.get(agentId) ?? [];
6124
+ }
6125
+ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
6126
+ const key = transcriptKey(loc.cwd, loc.agentId);
6127
+ const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
6128
+ try {
6129
+ await persistTurn(store, loc, sessionId, turn);
6130
+ const count = (recordCounts.get(key) ?? 0) + 1;
6131
+ recordCounts.set(key, count);
6132
+ if (turn.autoCompact !== void 0) {
6133
+ const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
6134
+ const fired = await autoCompactIfNeeded2({
6135
+ store,
6136
+ loc,
6137
+ sessionId,
6138
+ usageTotal: turn.autoCompact.usageTotal,
6139
+ contextWindow: turn.autoCompact.contextWindow,
6140
+ turnCount: count,
6141
+ summarize: turn.autoCompact.summarize
6142
+ });
6143
+ if (fired) onCompact?.();
6144
+ }
6145
+ } catch (cause) {
6146
+ const msg = cause instanceof Error ? cause.message : String(cause);
6147
+ process.stderr.write(
6148
+ `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
6149
+ `
6150
+ );
6151
+ }
6152
+ });
6153
+ pendingWrites.set(
6154
+ key,
6155
+ chained.then(
6156
+ () => void 0,
6157
+ () => void 0
6158
+ )
6159
+ );
6160
+ }
6161
+ async function hydrateSession(agentId, loc) {
6162
+ const key = transcriptKey(loc.cwd, agentId);
6163
+ if (hydratedKeys.has(key)) return;
6164
+ hydratedKeys.add(key);
6165
+ const persisted = await readSessionMessages(loc.store, agentId);
6166
+ if (persisted.length === 0) return;
6167
+ sessions.set(agentId, persisted);
6168
+ }
6169
+ async function flushSessionWrites() {
6170
+ while (pendingWrites.size > 0) {
6171
+ const all = Array.from(pendingWrites.values());
6172
+ pendingWrites.clear();
6173
+ await Promise.all(all);
6174
+ }
6175
+ }
6176
+ function clearSession(agentId) {
6177
+ sessions.delete(agentId);
6178
+ }
6179
+ function enqueueSessionWrite(cwd, agentId, fn) {
6180
+ const key = transcriptKey(cwd, agentId);
6181
+ const prior = pendingWrites.get(key) ?? Promise.resolve();
6182
+ const result = prior.then(fn);
6183
+ pendingWrites.set(
6184
+ key,
6185
+ result.then(
6186
+ () => void 0,
6187
+ () => void 0
6188
+ )
6189
+ );
6190
+ return result;
6191
+ }
6192
+ var pendingWrites, recordCounts;
6193
+ var init_agent_session = __esm({
6194
+ "src/internal/session/agent-session.ts"() {
6195
+ init_agent_session_store();
6196
+ init_session_cache();
6197
+ init_session_cache();
6198
+ pendingWrites = /* @__PURE__ */ new Map();
6199
+ recordCounts = /* @__PURE__ */ new Map();
6200
+ }
6201
+ });
6161
6202
  async function withToolWhitelist(whitelist, fn) {
6162
6203
  return toolWhitelistStore.run(whitelist, fn);
6163
6204
  }
@@ -6252,10 +6293,10 @@ var init_context = __esm({
6252
6293
  }
6253
6294
  });
6254
6295
 
6255
- // src/goal-loop.ts
6296
+ // src/internal/runtime/lifecycle/goal-marker.ts
6256
6297
  var GOAL_CONTINUATION_MARKER;
6257
- var init_goal_loop = __esm({
6258
- "src/goal-loop.ts"() {
6298
+ var init_goal_marker = __esm({
6299
+ "src/internal/runtime/lifecycle/goal-marker.ts"() {
6259
6300
  GOAL_CONTINUATION_MARKER = "[[theokit:goal-continuation]]";
6260
6301
  }
6261
6302
  });
@@ -6429,7 +6470,7 @@ ${lastResponse.slice(-1e3)}`
6429
6470
  }
6430
6471
  var init_run_until = __esm({
6431
6472
  "src/internal/runtime/lifecycle/run-until.ts"() {
6432
- init_goal_loop();
6473
+ init_goal_marker();
6433
6474
  }
6434
6475
  });
6435
6476
 
@@ -10600,6 +10641,7 @@ function parseDecisionFromStdout(stdout) {
10600
10641
  }
10601
10642
 
10602
10643
  // src/internal/runtime/lifecycle/post-run-lifecycle.ts
10644
+ init_compaction();
10603
10645
  init_run_events();
10604
10646
 
10605
10647
  // src/internal/memory/storage/session-summary-writer.ts
@@ -10669,6 +10711,12 @@ function resolveActiveMemorySummaryForSend(legacySummary, portPathEnabled) {
10669
10711
  return legacySummary;
10670
10712
  }
10671
10713
 
10714
+ // src/internal/runtime/lifecycle/context-budget-event.ts
10715
+ function buildContextBudgetEvent(model, resolved) {
10716
+ if (resolved.source !== "fallback") return void 0;
10717
+ return { type: "compaction_fallback", model, window: resolved.window };
10718
+ }
10719
+
10672
10720
  // src/internal/runtime/lifecycle/post-run-lifecycle.ts
10673
10721
  async function runPostRunLifecycle(inputs) {
10674
10722
  const {
@@ -10694,18 +10742,15 @@ async function runPostRunLifecycle(inputs) {
10694
10742
  appendSessionMessage(agentId, { role: "assistant", text: result.result });
10695
10743
  }
10696
10744
  const conversation = await safeConversation(run);
10697
- const contextWindow = getCatalogModelInfo(model)?.limit?.context;
10698
- if (contextWindow === void 0) {
10699
- const g = globalThis;
10700
- const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.compact.no-cw-warned");
10701
- const warned3 = g[sym] ??= /* @__PURE__ */ new Set();
10702
- if (!warned3.has(model)) {
10703
- warned3.add(model);
10704
- process.stderr.write(
10705
- `[theokit-sdk] auto-compaction disabled: model "${model}" has no context-window entry in the catalog
10706
- `
10707
- );
10708
- }
10745
+ const resolvedWindow = resolveEffectiveContextWindow({
10746
+ catalog: getCatalogModelInfo(model)?.limit?.context,
10747
+ margin: CONTEXT_WINDOW_MARGIN,
10748
+ floor: CONTEXT_WINDOW_FLOOR
10749
+ });
10750
+ const contextWindow = resolvedWindow.window;
10751
+ const budgetEvent = buildContextBudgetEvent(model, resolvedWindow);
10752
+ if (budgetEvent !== void 0 && onRunEvent !== void 0) {
10753
+ emitRunEvent(onRunEvent, budgetEvent);
10709
10754
  }
10710
10755
  const lastRequestUsage = result.usage?.requests?.at(-1)?.totalTokens;
10711
10756
  const usageForTrigger = lastRequestUsage ?? result.usage?.totalTokens;
@@ -15677,6 +15722,71 @@ function registerPluginProviderProfiles(entries) {
15677
15722
 
15678
15723
  // src/internal/local-agent/real-local-run.ts
15679
15724
  init_async_local_storage();
15725
+
15726
+ // src/internal/local-agent/mcp-pool.ts
15727
+ var DEFAULT_IDLE_TTL_MS = 6e5;
15728
+ function configKey(config) {
15729
+ return JSON.stringify(
15730
+ config,
15731
+ (_k, v) => v !== null && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(
15732
+ Object.entries(v).sort(([a], [b]) => a < b ? -1 : 1)
15733
+ ) : v
15734
+ );
15735
+ }
15736
+ var McpClientPool = class {
15737
+ entries = /* @__PURE__ */ new Map();
15738
+ idleTtlMs;
15739
+ now;
15740
+ constructor(options = {}) {
15741
+ this.idleTtlMs = options.idleTtlMs ?? DEFAULT_IDLE_TTL_MS;
15742
+ this.now = options.now ?? Date.now;
15743
+ }
15744
+ /**
15745
+ * Return the pooled client for `(sessionId, serverName, config)`, creating it via `factory` on
15746
+ * first use. Every call refreshes idleness — the TTL measures time SINCE LAST USE, not age.
15747
+ *
15748
+ * Synchronous by design: `createMcpClient` is itself synchronous (the handshake happens later, on
15749
+ * `initialize`), so there is no `await` between the lookup and the insert and two concurrent runs
15750
+ * in the same session cannot both miss the cache.
15751
+ */
15752
+ acquire(sessionId, serverName, config, factory) {
15753
+ const key = `${sessionId}\0${serverName}\0${configKey(config)}`;
15754
+ const existing = this.entries.get(key);
15755
+ if (existing !== void 0) {
15756
+ existing.lastUsedAt = this.now();
15757
+ return existing.client;
15758
+ }
15759
+ const client = factory();
15760
+ this.entries.set(key, { client, sessionId, lastUsedAt: this.now() });
15761
+ return client;
15762
+ }
15763
+ /**
15764
+ * Close and forget every client of ONE session. Scoped deliberately: clearing the whole map would
15765
+ * tear down the servers of every concurrent conversation.
15766
+ */
15767
+ disposeSession(sessionId, close) {
15768
+ for (const [key, entry] of this.entries) {
15769
+ if (entry.sessionId !== sessionId) continue;
15770
+ close(entry.client);
15771
+ this.entries.delete(key);
15772
+ }
15773
+ }
15774
+ /** Close and forget every client idle for longer than the TTL. */
15775
+ reapIdle(close) {
15776
+ const cutoff = this.now() - this.idleTtlMs;
15777
+ for (const [key, entry] of this.entries) {
15778
+ if (entry.lastUsedAt > cutoff) continue;
15779
+ close(entry.client);
15780
+ this.entries.delete(key);
15781
+ }
15782
+ }
15783
+ /** Live pooled-client count — for observability and tests. */
15784
+ size() {
15785
+ return this.entries.size;
15786
+ }
15787
+ };
15788
+
15789
+ // src/internal/local-agent/real-local-run.ts
15680
15790
  init_real_local_run_provider();
15681
15791
 
15682
15792
  // src/a2a/subagent.ts
@@ -16095,12 +16205,23 @@ function buildLoopInputs(options, runId, userText, userImages) {
16095
16205
  ...options.agentOptions.memoryProvider !== void 0 ? { memoryProvider: options.agentOptions.memoryProvider } : {}
16096
16206
  };
16097
16207
  }
16208
+ var sessionMcpPool = new McpClientPool();
16209
+ function disposeSessionMcpClients(agentId) {
16210
+ sessionMcpPool.disposeSession(agentId, (client) => {
16211
+ void client.close();
16212
+ });
16213
+ }
16098
16214
  function buildMcpMap(options) {
16099
16215
  const map = /* @__PURE__ */ new Map();
16100
16216
  const inline = options.sendOptions.mcpServers ?? options.agentOptions.mcpServers;
16101
16217
  if (inline === void 0) return map;
16218
+ const pooled = options.agentOptions.mcpLifecycle === "session";
16219
+ if (pooled) sessionMcpPool.reapIdle((c) => void c.close());
16102
16220
  for (const [name, config] of Object.entries(inline)) {
16103
- map.set(name, createMcpClient(name, config));
16221
+ map.set(
16222
+ name,
16223
+ pooled ? sessionMcpPool.acquire(options.agentId, name, config, () => createMcpClient(name, config)) : createMcpClient(name, config)
16224
+ );
16104
16225
  }
16105
16226
  return map;
16106
16227
  }
@@ -17165,7 +17286,9 @@ async function loadDriver(filePath) {
17165
17286
  }
17166
17287
  try {
17167
17288
  const mod = await (driverLoaderOverrides?.nodeSqlite?.() ?? Promise.resolve(
17168
- process.getBuiltinModule?.("node:sqlite") ?? (() => {
17289
+ process.getBuiltinModule?.(
17290
+ "node:sqlite"
17291
+ ) ?? (() => {
17169
17292
  throw new Error("node:sqlite built-in unavailable (Node < 22.3)");
17170
17293
  })()
17171
17294
  ));
@@ -18215,7 +18338,8 @@ var LocalAgentMemory = class {
18215
18338
  const message = cause instanceof Error ? cause.message : String(cause);
18216
18339
  const g = globalThis;
18217
18340
  const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.memory.warned");
18218
- const warned3 = g[sym] ??= /* @__PURE__ */ new Set();
18341
+ g[sym] ??= /* @__PURE__ */ new Set();
18342
+ const warned3 = g[sym];
18219
18343
  if (!warned3.has(message)) {
18220
18344
  warned3.add(message);
18221
18345
  process.stderr.write(`[theokit-sdk] memory tools unavailable: ${message}
@@ -19399,6 +19523,7 @@ var LocalAgent = class {
19399
19523
  liveAgentRegistry.forget(this.agentId);
19400
19524
  this.lifecycleAbortController.abort();
19401
19525
  await withCwdMutex(`agent-send:${this.agentId}`, () => Promise.resolve());
19526
+ disposeSessionMcpClients(this.agentId);
19402
19527
  await flushSessionWrites();
19403
19528
  await flushRegistrySaves(this.workspaceCwd);
19404
19529
  }
@@ -19699,8 +19824,8 @@ async function getRegisteredAgentOrThrow(agentId) {
19699
19824
  // src/agent.ts
19700
19825
  init_errors();
19701
19826
  init_discovery();
19702
- init_agent_session();
19703
19827
  init_agent_factory_registry();
19828
+ init_agent_session();
19704
19829
  var streamObjectImport;
19705
19830
  var Agent = class _Agent {
19706
19831
  constructor() {
@@ -19992,26 +20117,26 @@ var Agent = class _Agent {
19992
20117
  reg = getRegisteredAgent(agentId);
19993
20118
  }
19994
20119
  if (reg === void 0 || reg.runtime !== "local") {
19995
- throw new UnknownAgentError(`No local agent "${agentId}" registered \u2014 compact targets local sessions.`);
20120
+ throw new UnknownAgentError(
20121
+ `No local agent "${agentId}" registered \u2014 compact targets local sessions.`
20122
+ );
19996
20123
  }
19997
- const cwd = reg.cwd ?? process.cwd();
19998
- const optModel = reg.options.model;
19999
- const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20000
20124
  const { compactSessionTranscript: compactSessionTranscript2, buildDefaultSummarizer: buildDefaultSummarizer2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
20001
- const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20002
- const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20003
- const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20004
- const store = new FsSessionStore2({ baseDir, cwd });
20005
- return enqueueSessionWrite(cwd, agentId, () => compactSessionTranscript2({
20006
- store,
20007
- loc: { cwd, agentId, model },
20008
- sessionId: agentId,
20009
- trigger: options.trigger ?? "manual",
20010
- summarize: options.summarize ?? buildDefaultSummarizer2({
20011
- agentModel: model,
20012
- ...reg.options.apiKey !== void 0 ? { apiKey: reg.options.apiKey } : {}
20125
+ const { cwd, model, store } = await abrirStoreLocal(reg);
20126
+ return enqueueSessionWrite(
20127
+ cwd,
20128
+ agentId,
20129
+ () => compactSessionTranscript2({
20130
+ store,
20131
+ loc: { cwd, agentId, model },
20132
+ sessionId: agentId,
20133
+ trigger: options.trigger ?? "manual",
20134
+ summarize: options.summarize ?? buildDefaultSummarizer2({
20135
+ agentModel: model,
20136
+ ...reg.options.apiKey !== void 0 ? { apiKey: reg.options.apiKey } : {}
20137
+ })
20013
20138
  })
20014
- }));
20139
+ );
20015
20140
  }
20016
20141
  /**
20017
20142
  * M51 — inject a SYNTHETIC user+assistant pair into a LOCAL session's persisted transcript WITHOUT
@@ -20028,16 +20153,12 @@ var Agent = class _Agent {
20028
20153
  reg = getRegisteredAgent(agentId);
20029
20154
  }
20030
20155
  if (reg === void 0 || reg.runtime !== "local") {
20031
- throw new UnknownAgentError(`No local agent "${agentId}" registered \u2014 injectSessionTurn targets local sessions.`);
20156
+ throw new UnknownAgentError(
20157
+ `No local agent "${agentId}" registered \u2014 injectSessionTurn targets local sessions.`
20158
+ );
20032
20159
  }
20033
- const cwd = reg.cwd ?? process.cwd();
20034
- const optModel = reg.options.model;
20035
- const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20036
20160
  const { injectSessionTurn: injectSessionTurn2 } = await Promise.resolve().then(() => (init_inject_session(), inject_session_exports));
20037
- const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20038
- const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20039
- const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20040
- const store = new FsSessionStore2({ baseDir, cwd });
20161
+ const { cwd, model, store } = await abrirStoreLocal(reg);
20041
20162
  await injectSessionTurn2({
20042
20163
  store,
20043
20164
  loc: { cwd, agentId, model },
@@ -20079,6 +20200,15 @@ setAgentFacade({
20079
20200
  resume: (agentId, options) => Agent.resume(agentId, options),
20080
20201
  batch: (prompts, options) => Agent.batch(prompts, options)
20081
20202
  });
20203
+ async function abrirStoreLocal(reg) {
20204
+ const cwd = reg.cwd ?? process.cwd();
20205
+ const optModel = reg.options.model;
20206
+ const model = reg.model?.id ?? (typeof optModel === "string" ? optModel : optModel?.id) ?? "unknown";
20207
+ const { FsSessionStore: FsSessionStore2 } = await Promise.resolve().then(() => (init_fs_session_store(), fs_session_store_exports));
20208
+ const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
20209
+ const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
20210
+ return { cwd, model, store: new FsSessionStore2({ baseDir, cwd }) };
20211
+ }
20082
20212
  var JsonlParseError = class extends Error {
20083
20213
  constructor(message, line) {
20084
20214
  super(message);