@theokit/sdk 4.16.3 → 4.16.5

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.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from 'module';
3
3
  import { randomUUID, createHash, randomBytes } from 'crypto';
4
4
  import { mkdir, readFile, stat, open, rename, unlink, readdir, statfs, access } from 'fs/promises';
5
5
  import { join, dirname, relative, resolve, sep, isAbsolute } from 'path';
6
- import { readFileSync, existsSync, rmSync, mkdirSync, renameSync, realpathSync, lstatSync, readlinkSync, readdirSync, statSync, chmodSync, openSync, writeFileSync, fsyncSync, closeSync, unlinkSync } from 'fs';
6
+ import { existsSync, rmSync, mkdirSync, renameSync, readFileSync, realpathSync, lstatSync, readlinkSync, readdirSync, statSync, chmodSync, openSync, writeFileSync, fsyncSync, closeSync, unlinkSync } from 'fs';
7
7
  import { homedir } from 'os';
8
8
  import { fileURLToPath, pathToFileURL } from 'url';
9
9
  import { AsyncLocalStorage } from 'async_hooks';
@@ -1757,140 +1757,6 @@ var init_session_summary_writer = __esm({
1757
1757
  MAX_TURN_CHARS = 2e3;
1758
1758
  }
1759
1759
  });
1760
-
1761
- // src/compaction.ts
1762
- function estimateTokens(text) {
1763
- return Math.ceil(text.length / 4);
1764
- }
1765
- var init_compaction = __esm({
1766
- "src/compaction.ts"() {
1767
- }
1768
- });
1769
-
1770
- // src/internal/runtime/compression/compression-summarizer.ts
1771
- var compression_summarizer_exports = {};
1772
- __export(compression_summarizer_exports, {
1773
- CompressionFailedError: () => CompressionFailedError,
1774
- buildCompressionPrompt: () => buildCompressionPrompt,
1775
- compressConversationWindow: () => compressConversationWindow
1776
- });
1777
- function buildCompressionPrompt(messages) {
1778
- const formatted = messages.map((m) => `[${m.role}]: ${m.content}`).join("\n\n");
1779
- return `Summarize the following ${messages.length} conversation messages into a concise summary that preserves ALL facts, decisions, user preferences, and context needed for the conversation to continue naturally. The summary will replace these messages in the context window. Be thorough but concise.
1780
-
1781
- --- CONVERSATION TO SUMMARIZE ---
1782
- ${formatted}
1783
- --- END ---`;
1784
- }
1785
- async function compressConversationWindow(opts) {
1786
- const userPrompt = buildCompressionPrompt(opts.messages);
1787
- let summary;
1788
- try {
1789
- summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
1790
- } catch (cause) {
1791
- throw new CompressionFailedError(
1792
- `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
1793
- { cause: cause instanceof Error ? cause : void 0 }
1794
- );
1795
- }
1796
- if (!summary || summary.trim().length === 0) {
1797
- throw new CompressionFailedError(
1798
- "Compression LLM returned empty summary \u2014 reduction ineffective."
1799
- );
1800
- }
1801
- return {
1802
- role: "system",
1803
- content: `[Compressed conversation summary]: ${summary.trim()}`
1804
- };
1805
- }
1806
- var CompressionFailedError, COMPRESSION_SYSTEM;
1807
- var init_compression_summarizer = __esm({
1808
- "src/internal/runtime/compression/compression-summarizer.ts"() {
1809
- CompressionFailedError = class extends Error {
1810
- name = "CompressionFailedError";
1811
- };
1812
- 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.";
1813
- }
1814
- });
1815
-
1816
- // src/internal/runtime/compression/compression-model-registry.ts
1817
- var compression_model_registry_exports = {};
1818
- __export(compression_model_registry_exports, {
1819
- CompressionModelUnresolvedError: () => CompressionModelUnresolvedError,
1820
- resolveCompressionModel: () => resolveCompressionModel
1821
- });
1822
- function resolveCompressionModel(agentModel) {
1823
- const exact = EXACT_REGISTRY.get(agentModel);
1824
- if (exact !== void 0) return exact;
1825
- const wildcard = matchWildcard(agentModel);
1826
- if (wildcard !== null) return wildcard;
1827
- if (isNoAuthProvider(agentModel)) return agentModel;
1828
- throw new CompressionModelUnresolvedError(agentModel);
1829
- }
1830
- function matchWildcard(agentModel) {
1831
- for (const [pattern, replacement] of WILDCARD_REGISTRY) {
1832
- const prefix = pattern.endsWith("*") ? pattern.slice(0, -1) : pattern;
1833
- if (!agentModel.startsWith(prefix)) continue;
1834
- const suffix = agentModel.slice(prefix.length);
1835
- const replPrefix = replacement.endsWith("*") ? replacement.slice(0, -1) : replacement;
1836
- return `${replPrefix}${suffix}`;
1837
- }
1838
- return null;
1839
- }
1840
- function isNoAuthProvider(agentModel) {
1841
- const slashIdx = agentModel.indexOf("/");
1842
- if (slashIdx <= 0) return false;
1843
- return NO_AUTH_PROVIDERS.has(agentModel.slice(0, slashIdx));
1844
- }
1845
- var EXACT_REGISTRY, WILDCARD_REGISTRY, NO_AUTH_PROVIDERS, CompressionModelUnresolvedError;
1846
- var init_compression_model_registry = __esm({
1847
- "src/internal/runtime/compression/compression-model-registry.ts"() {
1848
- EXACT_REGISTRY = /* @__PURE__ */ new Map([
1849
- // OpenAI family
1850
- ["openai/gpt-4o", "openai/gpt-4o-mini"],
1851
- ["openai/gpt-4-turbo", "openai/gpt-4o-mini"],
1852
- ["openai/gpt-4", "openai/gpt-4o-mini"],
1853
- ["openai/o1-preview", "openai/gpt-4o-mini"],
1854
- ["openai/o1", "openai/gpt-4o-mini"],
1855
- ["openai/o3", "openai/gpt-4o-mini"],
1856
- ["openai/o3-mini", "openai/gpt-4o-mini"],
1857
- // Anthropic family
1858
- ["anthropic/claude-opus-4", "anthropic/claude-3-5-haiku-latest"],
1859
- ["anthropic/claude-sonnet-4", "anthropic/claude-3-5-haiku-latest"],
1860
- ["anthropic/claude-3-5-sonnet", "anthropic/claude-3-5-haiku-latest"],
1861
- ["anthropic/claude-3-5-sonnet-latest", "anthropic/claude-3-5-haiku-latest"],
1862
- ["anthropic/claude-3-opus", "anthropic/claude-3-haiku"],
1863
- ["anthropic/claude-3-sonnet", "anthropic/claude-3-haiku"],
1864
- // Vertex (Gemini + Anthropic-on-Vertex)
1865
- ["vertex/gemini-1.5-pro", "vertex/gemini-1.5-flash"],
1866
- ["vertex/gemini-2.0-pro", "vertex/gemini-1.5-flash"],
1867
- ["vertex/claude-3-5-sonnet", "vertex/claude-3-5-haiku"],
1868
- ["vertex/claude-3-opus", "vertex/claude-3-haiku"],
1869
- // OpenRouter (preserve openrouter prefix, swap tier within same vendor)
1870
- ["openrouter/openai/gpt-4o", "openrouter/openai/gpt-4o-mini"],
1871
- ["openrouter/openai/gpt-4-turbo", "openrouter/openai/gpt-4o-mini"],
1872
- ["openrouter/anthropic/claude-3-5-sonnet", "openrouter/anthropic/claude-3-5-haiku"],
1873
- ["openrouter/anthropic/claude-opus-4", "openrouter/anthropic/claude-3-5-haiku"]
1874
- ]);
1875
- WILDCARD_REGISTRY = [
1876
- // Bedrock Anthropic: us.anthropic.claude-sonnet-* → us.anthropic.claude-3-haiku-*
1877
- ["bedrock/anthropic.claude-sonnet*", "bedrock/anthropic.claude-3-haiku*"],
1878
- ["bedrock/anthropic.claude-opus*", "bedrock/anthropic.claude-3-haiku*"],
1879
- ["bedrock/anthropic.claude-3-5-sonnet*", "bedrock/anthropic.claude-3-5-haiku*"]
1880
- ];
1881
- NO_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["ollama", "lmstudio", "llamacpp"]);
1882
- CompressionModelUnresolvedError = class extends Error {
1883
- name = "CompressionModelUnresolvedError";
1884
- agentModel;
1885
- constructor(agentModel) {
1886
- super(
1887
- `Could not resolve a same-family-cheaper-tier compression model for "${agentModel}". Provide Agent.create({compression: {model: "<your-cheaper-model>"}}) OR add "${agentModel}" to the compression-model-registry (see ADR D440).`
1888
- );
1889
- this.agentModel = agentModel;
1890
- }
1891
- };
1892
- }
1893
- });
1894
1760
  var MODALITIES, costSchema, limitSchema, modalitiesSchema, catalogModelSchema;
1895
1761
  var init_catalog_schema = __esm({
1896
1762
  "src/internal/providers/catalog-schema.ts"() {
@@ -1971,19 +1837,6 @@ var init_registry = __esm({
1971
1837
  ALIASES = globalSingleton("theokit-sdk.providers.aliases", () => /* @__PURE__ */ new Map());
1972
1838
  }
1973
1839
  });
1974
-
1975
- // src/internal/providers/catalog-loader.ts
1976
- var catalog_loader_exports = {};
1977
- __export(catalog_loader_exports, {
1978
- _resetModelInfoIndexForTests: () => _resetModelInfoIndexForTests,
1979
- getCatalogCapabilities: () => getCatalogCapabilities,
1980
- getCatalogModelInfo: () => getCatalogModelInfo,
1981
- isPatchedModelKey: () => isPatchedModelKey,
1982
- listModelInfoKeys: () => listModelInfoKeys,
1983
- loadProviderCatalog: () => loadProviderCatalog,
1984
- patchModelInfo: () => patchModelInfo,
1985
- registerCatalogProviders: () => registerCatalogProviders
1986
- });
1987
1840
  function globalSingleton2(key2, create) {
1988
1841
  const g = globalThis;
1989
1842
  const sym = Symbol.for(key2);
@@ -1997,16 +1850,6 @@ function getCatalogModelInfo(key2) {
1997
1850
  function isPatchedModelKey(key2) {
1998
1851
  return patchedModelKeys.has(key2);
1999
1852
  }
2000
- function patchModelInfo(key2, model) {
2001
- ensureModelIndexLoaded();
2002
- const existing = modelInfoIndex.get(key2);
2003
- modelInfoIndex.set(key2, existing === void 0 ? model : { ...existing, ...model });
2004
- patchedModelKeys.add(key2);
2005
- }
2006
- function listModelInfoKeys() {
2007
- ensureModelIndexLoaded();
2008
- return [...modelInfoIndex.keys()];
2009
- }
2010
1853
  function ensureModelIndexLoaded() {
2011
1854
  if (indexState.loaded) return;
2012
1855
  indexState.loaded = true;
@@ -2040,11 +1883,6 @@ function indexEntryModels(entry) {
2040
1883
  }
2041
1884
  }
2042
1885
  }
2043
- function _resetModelInfoIndexForTests() {
2044
- modelInfoIndex.clear();
2045
- patchedModelKeys.clear();
2046
- indexState.loaded = false;
2047
- }
2048
1886
  function validateEntry(raw) {
2049
1887
  if (typeof raw.id !== "string" || typeof raw.displayName !== "string" || typeof raw.apiMode !== "string" || typeof raw.authType !== "string" || typeof raw.baseUrl !== "string" || !Array.isArray(raw.envVars) || !Array.isArray(raw.fallbackModels) || raw.capabilities == null || typeof raw.capabilities !== "object") {
2050
1888
  return null;
@@ -2055,12 +1893,6 @@ function loadProviderCatalog(opts) {
2055
1893
  const catalogPath = join(__dirname_resolved, "provider-catalog.json");
2056
1894
  const rawText = readFileSync(catalogPath, "utf-8");
2057
1895
  let entries = JSON.parse(rawText);
2058
- if (opts?._testInjectMalformed) {
2059
- entries = [
2060
- ...entries,
2061
- { id: "malformed-provider", displayName: "Bad" }
2062
- ];
2063
- }
2064
1896
  const result = {};
2065
1897
  for (const raw of entries) {
2066
1898
  const validated = validateEntry(raw);
@@ -2089,7 +1921,7 @@ function getCatalogCapabilities(providerId) {
2089
1921
  return _capabilitiesCache[providerId];
2090
1922
  }
2091
1923
  function registerCatalogProviders(opts) {
2092
- const catalog = loadProviderCatalog(opts);
1924
+ const catalog = loadProviderCatalog();
2093
1925
  for (const entry of Object.values(catalog)) {
2094
1926
  if (getProviderProfile(entry.id) !== void 0) continue;
2095
1927
  if (entry.aliases?.some((a) => getProviderProfile(a) !== void 0)) continue;
@@ -2130,6 +1962,15 @@ var init_catalog_loader = __esm({
2130
1962
  }
2131
1963
  });
2132
1964
 
1965
+ // src/compaction.ts
1966
+ function estimateTokens(text) {
1967
+ return Math.ceil(text.length / 4);
1968
+ }
1969
+ var init_compaction = __esm({
1970
+ "src/compaction.ts"() {
1971
+ }
1972
+ });
1973
+
2133
1974
  // src/internal/providers/builtin/anthropic.ts
2134
1975
  var ANTHROPIC;
2135
1976
  var init_anthropic = __esm({
@@ -5774,12 +5615,6 @@ var init_vertex_router = __esm({
5774
5615
  });
5775
5616
 
5776
5617
  // src/internal/llm/router.ts
5777
- var router_exports = {};
5778
- __export(router_exports, {
5779
- _resetCredentialPoolWarnings: () => _resetCredentialPoolWarnings,
5780
- _resetNoAuthApiKeyWarnings: () => _resetNoAuthApiKeyWarnings,
5781
- resolveProviderChain: () => resolveProviderChain
5782
- });
5783
5618
  function resolveProviderChain(options) {
5784
5619
  registerBuiltins();
5785
5620
  return buildChain(options);
@@ -5877,9 +5712,6 @@ function warnNoAuthApiKeysIgnoredOnce(provider) {
5877
5712
  `
5878
5713
  );
5879
5714
  }
5880
- function _resetNoAuthApiKeyWarnings() {
5881
- warnedNoAuthApiKeys.clear();
5882
- }
5883
5715
  function sentinelForNoAuth(profile) {
5884
5716
  return profile.authType === "none" ? profile.name : void 0;
5885
5717
  }
@@ -5910,9 +5742,6 @@ function warnUnknownProvidersInApiKeys(apiKeys) {
5910
5742
  }
5911
5743
  }
5912
5744
  }
5913
- function _resetCredentialPoolWarnings() {
5914
- warnedProviders.clear();
5915
- }
5916
5745
  function resolveApiKey2(envVars) {
5917
5746
  for (const v of envVars) {
5918
5747
  const value = process.env[v];
@@ -6016,41 +5845,318 @@ var init_router = __esm({
6016
5845
  }
6017
5846
  });
6018
5847
 
6019
- // src/internal/local-agent/real-local-run-provider.ts
6020
- var real_local_run_provider_exports = {};
6021
- __export(real_local_run_provider_exports, {
6022
- detectPrimaryProvider: () => detectPrimaryProvider,
6023
- inferProviderFromApiKey: () => inferProviderFromApiKey
6024
- });
6025
- function inferProviderFromApiKey(apiKey) {
6026
- if (apiKey === void 0 || apiKey.length === 0) return void 0;
6027
- const byPrefix = [
6028
- { provider: "openrouter", prefix: "sk-or-" },
6029
- { provider: "anthropic", prefix: "sk-ant-" },
6030
- { provider: "openai", prefix: "sk-" }
6031
- ];
6032
- for (const { provider, prefix } of byPrefix) {
6033
- if (apiKey.startsWith(prefix) && getProviderProfile(provider) !== void 0) {
6034
- return provider;
5848
+ // src/internal/local-agent/real-local-run-provider.ts
5849
+ function inferProviderFromApiKey(apiKey) {
5850
+ if (apiKey === void 0 || apiKey.length === 0) return void 0;
5851
+ const byPrefix = [
5852
+ { provider: "openrouter", prefix: "sk-or-" },
5853
+ { provider: "anthropic", prefix: "sk-ant-" },
5854
+ { provider: "openai", prefix: "sk-" }
5855
+ ];
5856
+ for (const { provider, prefix } of byPrefix) {
5857
+ if (apiKey.startsWith(prefix) && getProviderProfile(provider) !== void 0) {
5858
+ return provider;
5859
+ }
5860
+ }
5861
+ return void 0;
5862
+ }
5863
+ function detectPrimaryProvider() {
5864
+ if (process.env.ANTHROPIC_API_KEY !== void 0 && process.env.ANTHROPIC_API_KEY.length > 0) {
5865
+ return "anthropic";
5866
+ }
5867
+ if (process.env.OPENAI_API_KEY !== void 0 && process.env.OPENAI_API_KEY.length > 0) {
5868
+ return "openai";
5869
+ }
5870
+ if (process.env.OPENROUTER_API_KEY !== void 0 && process.env.OPENROUTER_API_KEY.length > 0) {
5871
+ return "openrouter";
5872
+ }
5873
+ return "openai";
5874
+ }
5875
+ var init_real_local_run_provider = __esm({
5876
+ "src/internal/local-agent/real-local-run-provider.ts"() {
5877
+ init_providers();
5878
+ }
5879
+ });
5880
+
5881
+ // src/internal/runtime/compression/compression-model-registry.ts
5882
+ function resolveCompressionModel(agentModel) {
5883
+ const exact = EXACT_REGISTRY.get(agentModel);
5884
+ if (exact !== void 0) return exact;
5885
+ const wildcard = matchWildcard(agentModel);
5886
+ if (wildcard !== null) return wildcard;
5887
+ if (isNoAuthProvider(agentModel)) return agentModel;
5888
+ throw new CompressionModelUnresolvedError(agentModel);
5889
+ }
5890
+ function matchWildcard(agentModel) {
5891
+ for (const [pattern, replacement] of WILDCARD_REGISTRY) {
5892
+ const prefix = pattern.endsWith("*") ? pattern.slice(0, -1) : pattern;
5893
+ if (!agentModel.startsWith(prefix)) continue;
5894
+ const suffix = agentModel.slice(prefix.length);
5895
+ const replPrefix = replacement.endsWith("*") ? replacement.slice(0, -1) : replacement;
5896
+ return `${replPrefix}${suffix}`;
5897
+ }
5898
+ return null;
5899
+ }
5900
+ function isNoAuthProvider(agentModel) {
5901
+ const slashIdx = agentModel.indexOf("/");
5902
+ if (slashIdx <= 0) return false;
5903
+ return NO_AUTH_PROVIDERS.has(agentModel.slice(0, slashIdx));
5904
+ }
5905
+ var EXACT_REGISTRY, WILDCARD_REGISTRY, NO_AUTH_PROVIDERS, CompressionModelUnresolvedError;
5906
+ var init_compression_model_registry = __esm({
5907
+ "src/internal/runtime/compression/compression-model-registry.ts"() {
5908
+ EXACT_REGISTRY = /* @__PURE__ */ new Map([
5909
+ // OpenAI family
5910
+ ["openai/gpt-4o", "openai/gpt-4o-mini"],
5911
+ ["openai/gpt-4-turbo", "openai/gpt-4o-mini"],
5912
+ ["openai/gpt-4", "openai/gpt-4o-mini"],
5913
+ ["openai/o1-preview", "openai/gpt-4o-mini"],
5914
+ ["openai/o1", "openai/gpt-4o-mini"],
5915
+ ["openai/o3", "openai/gpt-4o-mini"],
5916
+ ["openai/o3-mini", "openai/gpt-4o-mini"],
5917
+ // Anthropic family
5918
+ ["anthropic/claude-opus-4", "anthropic/claude-3-5-haiku-latest"],
5919
+ ["anthropic/claude-sonnet-4", "anthropic/claude-3-5-haiku-latest"],
5920
+ ["anthropic/claude-3-5-sonnet", "anthropic/claude-3-5-haiku-latest"],
5921
+ ["anthropic/claude-3-5-sonnet-latest", "anthropic/claude-3-5-haiku-latest"],
5922
+ ["anthropic/claude-3-opus", "anthropic/claude-3-haiku"],
5923
+ ["anthropic/claude-3-sonnet", "anthropic/claude-3-haiku"],
5924
+ // Vertex (Gemini + Anthropic-on-Vertex)
5925
+ ["vertex/gemini-1.5-pro", "vertex/gemini-1.5-flash"],
5926
+ ["vertex/gemini-2.0-pro", "vertex/gemini-1.5-flash"],
5927
+ ["vertex/claude-3-5-sonnet", "vertex/claude-3-5-haiku"],
5928
+ ["vertex/claude-3-opus", "vertex/claude-3-haiku"],
5929
+ // OpenRouter (preserve openrouter prefix, swap tier within same vendor)
5930
+ ["openrouter/openai/gpt-4o", "openrouter/openai/gpt-4o-mini"],
5931
+ ["openrouter/openai/gpt-4-turbo", "openrouter/openai/gpt-4o-mini"],
5932
+ ["openrouter/anthropic/claude-3-5-sonnet", "openrouter/anthropic/claude-3-5-haiku"],
5933
+ ["openrouter/anthropic/claude-opus-4", "openrouter/anthropic/claude-3-5-haiku"]
5934
+ ]);
5935
+ WILDCARD_REGISTRY = [
5936
+ // Bedrock Anthropic: us.anthropic.claude-sonnet-* → us.anthropic.claude-3-haiku-*
5937
+ ["bedrock/anthropic.claude-sonnet*", "bedrock/anthropic.claude-3-haiku*"],
5938
+ ["bedrock/anthropic.claude-opus*", "bedrock/anthropic.claude-3-haiku*"],
5939
+ ["bedrock/anthropic.claude-3-5-sonnet*", "bedrock/anthropic.claude-3-5-haiku*"]
5940
+ ];
5941
+ NO_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["ollama", "lmstudio", "llamacpp"]);
5942
+ CompressionModelUnresolvedError = class extends Error {
5943
+ name = "CompressionModelUnresolvedError";
5944
+ agentModel;
5945
+ constructor(agentModel) {
5946
+ super(
5947
+ `Could not resolve a same-family-cheaper-tier compression model for "${agentModel}". Provide Agent.create({compression: {model: "<your-cheaper-model>"}}) OR add "${agentModel}" to the compression-model-registry (see ADR D440).`
5948
+ );
5949
+ this.agentModel = agentModel;
5950
+ }
5951
+ };
5952
+ }
5953
+ });
5954
+
5955
+ // src/internal/runtime/compression/compression-summarizer.ts
5956
+ function buildCompressionPrompt(messages) {
5957
+ const formatted = messages.map((m) => `[${m.role}]: ${m.content}`).join("\n\n");
5958
+ return `Summarize the following ${messages.length} conversation messages into a concise summary that preserves ALL facts, decisions, user preferences, and context needed for the conversation to continue naturally. The summary will replace these messages in the context window. Be thorough but concise.
5959
+
5960
+ --- CONVERSATION TO SUMMARIZE ---
5961
+ ${formatted}
5962
+ --- END ---`;
5963
+ }
5964
+ async function compressConversationWindow(opts) {
5965
+ const userPrompt = buildCompressionPrompt(opts.messages);
5966
+ let summary;
5967
+ try {
5968
+ summary = await opts.callLlm(opts.model, COMPRESSION_SYSTEM, userPrompt);
5969
+ } catch (cause) {
5970
+ throw new CompressionFailedError(
5971
+ `Compression LLM call failed: ${cause instanceof Error ? cause.message : String(cause)}`,
5972
+ { cause: cause instanceof Error ? cause : void 0 }
5973
+ );
5974
+ }
5975
+ if (!summary || summary.trim().length === 0) {
5976
+ throw new CompressionFailedError(
5977
+ "Compression LLM returned empty summary \u2014 reduction ineffective."
5978
+ );
5979
+ }
5980
+ return {
5981
+ role: "system",
5982
+ content: `[Compressed conversation summary]: ${summary.trim()}`
5983
+ };
5984
+ }
5985
+ var CompressionFailedError, COMPRESSION_SYSTEM;
5986
+ var init_compression_summarizer = __esm({
5987
+ "src/internal/runtime/compression/compression-summarizer.ts"() {
5988
+ CompressionFailedError = class extends Error {
5989
+ name = "CompressionFailedError";
5990
+ };
5991
+ 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.";
5992
+ }
5993
+ });
5994
+
5995
+ // src/internal/session/agent-session-store.ts
5996
+ function seedTranscript(prior, opts) {
5997
+ return SessionTranscript.fromRecords(prior, opts);
5998
+ }
5999
+ function mapAgentTurn(steps) {
6000
+ const assistant = {};
6001
+ const toolResults = [];
6002
+ const toolCalls = [];
6003
+ for (const step of steps) {
6004
+ if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
6005
+ else if (step.type === "assistantMessage") assistant.text = step.message.text;
6006
+ else if (step.type === "toolCall")
6007
+ toolCalls.push({
6008
+ id: step.message.callId,
6009
+ name: step.message.name,
6010
+ input: step.message.args ?? {}
6011
+ });
6012
+ else
6013
+ toolResults.push({
6014
+ toolUseId: step.message.callId,
6015
+ content: step.message.result,
6016
+ isError: step.message.isError
6017
+ });
6018
+ }
6019
+ if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
6020
+ return { assistant, toolResults };
6021
+ }
6022
+ function hasAssistantContent(a) {
6023
+ return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
6024
+ }
6025
+ function appendConversation(transcript, conversation) {
6026
+ for (const ct of conversation) {
6027
+ if (ct.type !== "agentConversationTurn") continue;
6028
+ const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
6029
+ if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
6030
+ if (toolResults.length > 0) transcript.appendToolResults(toolResults);
6031
+ }
6032
+ }
6033
+ async function readSessionMessages(store, agentId) {
6034
+ const records = await store.readRecords(agentId);
6035
+ return reconstructMessages(records).map(narrowToSessionMessage);
6036
+ }
6037
+ function partToText(p) {
6038
+ if (p.type === "text") return p.text ?? "";
6039
+ if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
6040
+ if (p.type === "tool_result") {
6041
+ const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
6042
+ return `[tool result] ${body}`;
6043
+ }
6044
+ return "";
6045
+ }
6046
+ function narrowToSessionMessage(m) {
6047
+ const role = m.role === "user" ? "user" : "assistant";
6048
+ const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
6049
+ return { role, text };
6050
+ }
6051
+ function deltaRecords(transcript, priorLength) {
6052
+ return transcript.records().slice(priorLength);
6053
+ }
6054
+ async function persistTurn(store, loc, sessionId, turn) {
6055
+ const prior = await store.readRecords(loc.agentId);
6056
+ const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
6057
+ transcript.appendUserTurn(turn.userText);
6058
+ appendConversation(transcript, turn.conversation);
6059
+ await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
6060
+ }
6061
+ var init_agent_session_store = __esm({
6062
+ "src/internal/session/agent-session-store.ts"() {
6063
+ init_session_transcript();
6064
+ }
6065
+ });
6066
+
6067
+ // src/internal/session/agent-session.ts
6068
+ function transcriptKey(cwd, agentId) {
6069
+ return `${cwd}::${agentId}`;
6070
+ }
6071
+ function appendSessionMessage(agentId, message) {
6072
+ const existing = sessions.get(agentId) ?? [];
6073
+ existing.push(message);
6074
+ sessions.set(agentId, existing);
6075
+ }
6076
+ function getSessionMessages(agentId) {
6077
+ return sessions.get(agentId) ?? [];
6078
+ }
6079
+ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
6080
+ const key2 = transcriptKey(loc.cwd, loc.agentId);
6081
+ const chained = (pendingWrites.get(key2) ?? Promise.resolve()).then(async () => {
6082
+ try {
6083
+ await persistTurn(store, loc, sessionId, turn);
6084
+ const count = (recordCounts.get(key2) ?? 0) + 1;
6085
+ recordCounts.set(key2, count);
6086
+ if (turn.autoCompact !== void 0) {
6087
+ const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
6088
+ const fired = await autoCompactIfNeeded2({
6089
+ store,
6090
+ loc,
6091
+ sessionId,
6092
+ usageTotal: turn.autoCompact.usageTotal,
6093
+ contextWindow: turn.autoCompact.contextWindow,
6094
+ turnCount: count,
6095
+ summarize: turn.autoCompact.summarize
6096
+ });
6097
+ if (fired) onCompact?.();
6098
+ }
6099
+ } catch (cause) {
6100
+ const msg = cause instanceof Error ? cause.message : String(cause);
6101
+ process.stderr.write(
6102
+ `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
6103
+ `
6104
+ );
6035
6105
  }
6036
- }
6037
- return void 0;
6106
+ });
6107
+ pendingWrites.set(
6108
+ key2,
6109
+ chained.then(
6110
+ () => void 0,
6111
+ () => void 0
6112
+ )
6113
+ );
6038
6114
  }
6039
- function detectPrimaryProvider() {
6040
- if (process.env.ANTHROPIC_API_KEY !== void 0 && process.env.ANTHROPIC_API_KEY.length > 0) {
6041
- return "anthropic";
6042
- }
6043
- if (process.env.OPENAI_API_KEY !== void 0 && process.env.OPENAI_API_KEY.length > 0) {
6044
- return "openai";
6115
+ async function hydrateSession(agentId, loc) {
6116
+ const key2 = transcriptKey(loc.cwd, agentId);
6117
+ if (hydratedKeys.has(key2)) return;
6118
+ hydratedKeys.add(key2);
6119
+ const persisted = await readSessionMessages(loc.store, agentId);
6120
+ if (persisted.length === 0) return;
6121
+ if (!sessions.has(agentId) || sessions.get(agentId)?.length === 0) {
6122
+ sessions.set(agentId, persisted);
6045
6123
  }
6046
- if (process.env.OPENROUTER_API_KEY !== void 0 && process.env.OPENROUTER_API_KEY.length > 0) {
6047
- return "openrouter";
6124
+ }
6125
+ async function flushSessionWrites() {
6126
+ while (pendingWrites.size > 0) {
6127
+ const all = Array.from(pendingWrites.values());
6128
+ pendingWrites.clear();
6129
+ await Promise.all(all);
6048
6130
  }
6049
- return "openai";
6050
6131
  }
6051
- var init_real_local_run_provider = __esm({
6052
- "src/internal/local-agent/real-local-run-provider.ts"() {
6053
- init_providers();
6132
+ function clearSession(agentId) {
6133
+ sessions.delete(agentId);
6134
+ }
6135
+ function invalidateSessionCache(cwd, agentId) {
6136
+ sessions.delete(agentId);
6137
+ hydratedKeys.delete(transcriptKey(cwd, agentId));
6138
+ }
6139
+ function enqueueSessionWrite(cwd, agentId, fn) {
6140
+ const key2 = transcriptKey(cwd, agentId);
6141
+ const prior = pendingWrites.get(key2) ?? Promise.resolve();
6142
+ const result = prior.then(fn);
6143
+ pendingWrites.set(
6144
+ key2,
6145
+ result.then(
6146
+ () => void 0,
6147
+ () => void 0
6148
+ )
6149
+ );
6150
+ return result;
6151
+ }
6152
+ var sessions, hydratedKeys, pendingWrites, recordCounts;
6153
+ var init_agent_session = __esm({
6154
+ "src/internal/session/agent-session.ts"() {
6155
+ init_agent_session_store();
6156
+ sessions = /* @__PURE__ */ new Map();
6157
+ hydratedKeys = /* @__PURE__ */ new Set();
6158
+ pendingWrites = /* @__PURE__ */ new Map();
6159
+ recordCounts = /* @__PURE__ */ new Map();
6054
6160
  }
6055
6161
  });
6056
6162
 
@@ -6092,7 +6198,14 @@ async function compactSessionTranscript(opts) {
6092
6198
  const m = compressible[i];
6093
6199
  if (m === void 0 || m.role !== "user" || isCompactSummary(m.content)) continue;
6094
6200
  const cost = estimateTokens(m.content);
6095
- if (budget + cost > COMPACT_USER_MESSAGE_MAX_TOKENS) break;
6201
+ if (budget + cost > COMPACT_USER_MESSAGE_MAX_TOKENS) {
6202
+ const remaining = COMPACT_USER_MESSAGE_MAX_TOKENS - budget;
6203
+ if (remaining > 50) {
6204
+ preserved.unshift(`${m.content.slice(0, remaining * 4)}
6205
+ [...truncated for compaction...]`);
6206
+ }
6207
+ break;
6208
+ }
6096
6209
  budget += cost;
6097
6210
  preserved.unshift(m.content);
6098
6211
  }
@@ -6108,30 +6221,29 @@ ${summaryBody}`;
6108
6221
  transcript.appendUserTurn(summary);
6109
6222
  const delta = transcript.records().slice(prior.length);
6110
6223
  await opts.store.appendRecords(opts.loc.agentId, delta);
6224
+ invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);
6111
6225
  const postTokens = estimateTokens([...preserved, summary].join("\n"));
6112
6226
  return { preTokens, postTokens };
6113
6227
  }
6114
6228
  function buildDefaultSummarizer(opts) {
6115
6229
  return async (messages) => {
6116
- const { compressConversationWindow: compressConversationWindow2 } = await Promise.resolve().then(() => (init_compression_summarizer(), compression_summarizer_exports));
6117
- const { resolveCompressionModel: resolveCompressionModel2 } = await Promise.resolve().then(() => (init_compression_model_registry(), compression_model_registry_exports));
6118
- const { resolveProviderChain: resolveProviderChain2 } = await Promise.resolve().then(() => (init_router(), router_exports));
6119
- const { inferProviderFromApiKey: inferProviderFromApiKey2, detectPrimaryProvider: detectPrimaryProvider2 } = await Promise.resolve().then(() => (init_real_local_run_provider(), real_local_run_provider_exports));
6120
- const keyProvider = inferProviderFromApiKey2(opts.apiKey);
6230
+ const keyProvider = inferProviderFromApiKey(opts.apiKey);
6121
6231
  const modelPrefix = opts.agentModel.includes("/") ? opts.agentModel.slice(0, opts.agentModel.indexOf("/")) : void 0;
6122
- const provider = keyProvider ?? detectPrimaryProvider2();
6232
+ registerBuiltins();
6233
+ const prefixProfile = modelPrefix !== void 0 ? getProviderProfile(modelPrefix) : void 0;
6234
+ const provider = prefixProfile !== void 0 ? modelPrefix : keyProvider ?? detectPrimaryProvider();
6123
6235
  let model;
6124
6236
  if (provider !== modelPrefix) {
6125
6237
  model = opts.agentModel;
6126
6238
  } else {
6127
6239
  try {
6128
- model = resolveCompressionModel2(opts.agentModel);
6240
+ model = resolveCompressionModel(opts.agentModel);
6129
6241
  } catch {
6130
6242
  model = opts.agentModel;
6131
6243
  }
6132
6244
  }
6133
6245
  const callLlm = async (m, system, user) => {
6134
- const chain = resolveProviderChain2({
6246
+ const chain = resolveProviderChain({
6135
6247
  primary: provider,
6136
6248
  ...opts.apiKey !== void 0 ? { apiKeys: { [provider]: [opts.apiKey] } } : {}
6137
6249
  });
@@ -6151,7 +6263,7 @@ function buildDefaultSummarizer(opts) {
6151
6263
  }
6152
6264
  return text;
6153
6265
  };
6154
- const summary = await compressConversationWindow2({ messages: [...messages], model, callLlm });
6266
+ const summary = await compressConversationWindow({ messages: [...messages], model, callLlm });
6155
6267
  return summary.content;
6156
6268
  };
6157
6269
  }
@@ -6185,6 +6297,12 @@ var COMPACT_SUMMARY_MARKER, COMPACT_USER_MESSAGE_MAX_TOKENS, autoCompactAttempts
6185
6297
  var init_compact_session = __esm({
6186
6298
  "src/internal/session/compact-session.ts"() {
6187
6299
  init_compaction();
6300
+ init_router();
6301
+ init_real_local_run_provider();
6302
+ init_providers();
6303
+ init_compression_model_registry();
6304
+ init_compression_summarizer();
6305
+ init_agent_session();
6188
6306
  init_session_transcript();
6189
6307
  COMPACT_SUMMARY_MARKER = "[[theokit:compact-summary]]";
6190
6308
  COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
@@ -13015,147 +13133,8 @@ function parseDecisionFromStdout(stdout) {
13015
13133
  // src/internal/runtime/lifecycle/post-run-lifecycle.ts
13016
13134
  init_run_events();
13017
13135
  init_session_summary_writer();
13018
-
13019
- // src/internal/session/agent-session-store.ts
13020
- init_session_transcript();
13021
- function seedTranscript(prior, opts) {
13022
- return SessionTranscript.fromRecords(prior, opts);
13023
- }
13024
- function mapAgentTurn(steps) {
13025
- const assistant = {};
13026
- const toolResults = [];
13027
- const toolCalls = [];
13028
- for (const step of steps) {
13029
- if (step.type === "thinkingMessage") assistant.thinking = step.message.text;
13030
- else if (step.type === "assistantMessage") assistant.text = step.message.text;
13031
- else if (step.type === "toolCall")
13032
- toolCalls.push({
13033
- id: step.message.callId,
13034
- name: step.message.name,
13035
- input: step.message.args ?? {}
13036
- });
13037
- else
13038
- toolResults.push({
13039
- toolUseId: step.message.callId,
13040
- content: step.message.result,
13041
- isError: step.message.isError
13042
- });
13043
- }
13044
- if (toolCalls.length > 0) assistant.toolCalls = toolCalls;
13045
- return { assistant, toolResults };
13046
- }
13047
- function hasAssistantContent(a) {
13048
- return a.text !== void 0 || a.thinking !== void 0 || (a.toolCalls?.length ?? 0) > 0;
13049
- }
13050
- function appendConversation(transcript, conversation) {
13051
- for (const ct of conversation) {
13052
- if (ct.type !== "agentConversationTurn") continue;
13053
- const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);
13054
- if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);
13055
- if (toolResults.length > 0) transcript.appendToolResults(toolResults);
13056
- }
13057
- }
13058
- async function readSessionMessages(store, agentId) {
13059
- const records = await store.readRecords(agentId);
13060
- return reconstructMessages(records).map(narrowToSessionMessage);
13061
- }
13062
- function partToText(p) {
13063
- if (p.type === "text") return p.text ?? "";
13064
- if (p.type === "tool_use") return `[tool call] ${p.name ?? ""}`;
13065
- if (p.type === "tool_result") {
13066
- const body = typeof p.content === "string" ? p.content : JSON.stringify(p.content);
13067
- return `[tool result] ${body}`;
13068
- }
13069
- return "";
13070
- }
13071
- function narrowToSessionMessage(m) {
13072
- const role = m.role === "user" ? "user" : "assistant";
13073
- const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
13074
- return { role, text };
13075
- }
13076
- function deltaRecords(transcript, priorLength) {
13077
- return transcript.records().slice(priorLength);
13078
- }
13079
- async function persistTurn(store, loc, sessionId, turn) {
13080
- const prior = await store.readRecords(loc.agentId);
13081
- const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
13082
- transcript.appendUserTurn(turn.userText);
13083
- appendConversation(transcript, turn.conversation);
13084
- await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
13085
- }
13086
-
13087
- // src/internal/session/agent-session.ts
13088
- var sessions = /* @__PURE__ */ new Map();
13089
- var hydratedKeys = /* @__PURE__ */ new Set();
13090
- var pendingWrites = /* @__PURE__ */ new Map();
13091
- var recordCounts = /* @__PURE__ */ new Map();
13092
- function transcriptKey(cwd, agentId) {
13093
- return `${cwd}::${agentId}`;
13094
- }
13095
- function appendSessionMessage(agentId, message) {
13096
- const existing = sessions.get(agentId) ?? [];
13097
- existing.push(message);
13098
- sessions.set(agentId, existing);
13099
- }
13100
- function getSessionMessages(agentId) {
13101
- return sessions.get(agentId) ?? [];
13102
- }
13103
- function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
13104
- const key2 = transcriptKey(loc.cwd, loc.agentId);
13105
- const chained = (pendingWrites.get(key2) ?? Promise.resolve()).then(async () => {
13106
- try {
13107
- await persistTurn(store, loc, sessionId, turn);
13108
- const count = (recordCounts.get(key2) ?? 0) + 1;
13109
- recordCounts.set(key2, count);
13110
- if (turn.autoCompact !== void 0) {
13111
- const { autoCompactIfNeeded: autoCompactIfNeeded2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
13112
- const fired = await autoCompactIfNeeded2({
13113
- store,
13114
- loc,
13115
- sessionId,
13116
- usageTotal: turn.autoCompact.usageTotal,
13117
- contextWindow: turn.autoCompact.contextWindow,
13118
- turnCount: count,
13119
- summarize: turn.autoCompact.summarize
13120
- });
13121
- if (fired) onCompact?.();
13122
- }
13123
- } catch (cause) {
13124
- const msg = cause instanceof Error ? cause.message : String(cause);
13125
- process.stderr.write(
13126
- `[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}
13127
- `
13128
- );
13129
- }
13130
- });
13131
- pendingWrites.set(
13132
- key2,
13133
- chained.then(
13134
- () => void 0,
13135
- () => void 0
13136
- )
13137
- );
13138
- }
13139
- async function hydrateSession(agentId, loc) {
13140
- const key2 = transcriptKey(loc.cwd, agentId);
13141
- if (hydratedKeys.has(key2)) return;
13142
- hydratedKeys.add(key2);
13143
- const persisted = await readSessionMessages(loc.store, agentId);
13144
- if (persisted.length === 0) return;
13145
- if (!sessions.has(agentId) || sessions.get(agentId)?.length === 0) {
13146
- sessions.set(agentId, persisted);
13147
- }
13148
- }
13149
- async function flushSessionWrites() {
13150
- while (pendingWrites.size > 0) {
13151
- const all = Array.from(pendingWrites.values());
13152
- pendingWrites.clear();
13153
- await Promise.all(all);
13154
- }
13155
- }
13156
- function clearSession(agentId) {
13157
- sessions.delete(agentId);
13158
- }
13136
+ init_catalog_loader();
13137
+ init_compact_session();
13159
13138
 
13160
13139
  // src/internal/runtime/memory/memory-path-selector.ts
13161
13140
  var PORT_MEMORY_PATH_ENV_VAR = "THEOKIT_PORT_MEMORY_PATH";
@@ -13204,9 +13183,21 @@ async function runPostRunLifecycle(inputs) {
13204
13183
  appendSessionMessage(agentId, { role: "assistant", text: result.result });
13205
13184
  }
13206
13185
  const conversation = await safeConversation(run);
13207
- const { getCatalogModelInfo: getCatalogModelInfo2 } = await Promise.resolve().then(() => (init_catalog_loader(), catalog_loader_exports));
13208
- const { buildDefaultSummarizer: buildDefaultSummarizer2 } = await Promise.resolve().then(() => (init_compact_session(), compact_session_exports));
13209
- const contextWindow = getCatalogModelInfo2(model)?.limit?.context;
13186
+ const contextWindow = getCatalogModelInfo(model)?.limit?.context;
13187
+ if (contextWindow === void 0) {
13188
+ const g = globalThis;
13189
+ const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.compact.no-cw-warned");
13190
+ const warned3 = g[sym] ??= /* @__PURE__ */ new Set();
13191
+ if (!warned3.has(model)) {
13192
+ warned3.add(model);
13193
+ process.stderr.write(
13194
+ `[theokit-sdk] auto-compaction disabled: model "${model}" has no context-window entry in the catalog
13195
+ `
13196
+ );
13197
+ }
13198
+ }
13199
+ const lastRequestUsage = result.usage?.requests?.at(-1)?.totalTokens;
13200
+ const usageForTrigger = lastRequestUsage ?? result.usage?.totalTokens;
13210
13201
  persistTurnToTranscript(
13211
13202
  sessionStore,
13212
13203
  { cwd: workspaceCwd, agentId, model },
@@ -13215,9 +13206,9 @@ async function runPostRunLifecycle(inputs) {
13215
13206
  userText,
13216
13207
  conversation,
13217
13208
  autoCompact: {
13218
- usageTotal: result.usage?.totalTokens,
13209
+ usageTotal: usageForTrigger,
13219
13210
  contextWindow,
13220
- summarize: buildDefaultSummarizer2({
13211
+ summarize: buildDefaultSummarizer({
13221
13212
  agentModel: model,
13222
13213
  ...inputs.apiKey !== void 0 ? { apiKey: inputs.apiKey } : {}
13223
13214
  })
@@ -21212,6 +21203,7 @@ async function getRegisteredAgentOrThrow(agentId) {
21212
21203
  // src/agent.ts
21213
21204
  init_errors();
21214
21205
  init_discovery();
21206
+ init_agent_session();
21215
21207
  init_agent_factory_registry();
21216
21208
  var streamObjectImport;
21217
21209
  var Agent = class _Agent {
@@ -21514,7 +21506,7 @@ var Agent = class _Agent {
21514
21506
  const { defaultBaseDir: defaultBaseDir2, expandTilde: expandTilde2 } = await Promise.resolve().then(() => (init_session_transcript(), session_transcript_exports));
21515
21507
  const baseDir = reg.options.local?.baseDir !== void 0 ? expandTilde2(reg.options.local.baseDir) : defaultBaseDir2();
21516
21508
  const store = new FsSessionStore2({ baseDir, cwd });
21517
- return compactSessionTranscript2({
21509
+ return enqueueSessionWrite(cwd, agentId, () => compactSessionTranscript2({
21518
21510
  store,
21519
21511
  loc: { cwd, agentId, model },
21520
21512
  sessionId: agentId,
@@ -21523,7 +21515,7 @@ var Agent = class _Agent {
21523
21515
  agentModel: model,
21524
21516
  ...reg.options.apiKey !== void 0 ? { apiKey: reg.options.apiKey } : {}
21525
21517
  })
21526
- });
21518
+ }));
21527
21519
  }
21528
21520
  /**
21529
21521
  * Permanently delete a cloud agent.