@letta-ai/letta-code 0.29.3 → 0.29.4

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/letta.js CHANGED
@@ -5462,7 +5462,7 @@ var package_default;
5462
5462
  var init_package = __esm(() => {
5463
5463
  package_default = {
5464
5464
  name: "@letta-ai/letta-code",
5465
- version: "0.29.3",
5465
+ version: "0.29.4",
5466
5466
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5467
5467
  type: "module",
5468
5468
  packageManager: "bun@1.3.0",
@@ -375875,7 +375875,7 @@ class LocalStore {
375875
375875
  const agentsDir = join42(this.storageDir, "agents");
375876
375876
  if (existsSync36(agentsDir)) {
375877
375877
  for (const file3 of readdirSync13(agentsDir)) {
375878
- if (!file3.endsWith(".json"))
375878
+ if (!file3.endsWith(".json") || file3.startsWith("._"))
375879
375879
  continue;
375880
375880
  const raw = readJsonFile2(join42(agentsDir, file3));
375881
375881
  const agent2 = normalizeAgentRecord(raw, this.defaultAgentModel);
@@ -378334,6 +378334,8 @@ function createLocalEndpointPiProvider(options3) {
378334
378334
  }
378335
378335
  }
378336
378336
  function buildModel(metadata) {
378337
+ const contextWindow = Math.min(metadata.contextLength ?? LOCAL_ENDPOINT_DEFAULT_CONTEXT_WINDOW, LOCAL_ENDPOINT_DEFAULT_CONTEXT_WINDOW);
378338
+ const maxTokens = Math.min(metadata.maxTokens ?? LOCAL_ENDPOINT_DEFAULT_MAX_TOKENS, contextWindow);
378337
378339
  return {
378338
378340
  id: metadata.id,
378339
378341
  name: metadata.id,
@@ -378343,8 +378345,8 @@ function createLocalEndpointPiProvider(options3) {
378343
378345
  reasoning: metadata.thinking === true,
378344
378346
  input: metadata.vision === true ? ["text", "image"] : ["text"],
378345
378347
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
378346
- contextWindow: metadata.contextLength ?? LOCAL_ENDPOINT_DEFAULT_CONTEXT_WINDOW,
378347
- maxTokens: metadata.maxTokens ?? LOCAL_ENDPOINT_DEFAULT_MAX_TOKENS,
378348
+ contextWindow,
378349
+ maxTokens,
378348
378350
  compat: {
378349
378351
  supportsDeveloperRole: false,
378350
378352
  supportsReasoningEffort: false,
@@ -378516,7 +378518,9 @@ function parseLmStudioModels(data) {
378516
378518
  if (record5.type === "embeddings")
378517
378519
  continue;
378518
378520
  const capabilities = stringArray(record5.capabilities);
378519
- const contextLength = record5.max_context_length;
378521
+ const loadedContextLength = record5.state === "loaded" && typeof record5.loaded_context_length === "number" && record5.loaded_context_length > 0 ? record5.loaded_context_length : undefined;
378522
+ const maxContextLength = typeof record5.max_context_length === "number" && record5.max_context_length > 0 ? record5.max_context_length : undefined;
378523
+ const contextLength = loadedContextLength ?? maxContextLength;
378520
378524
  models3.push({
378521
378525
  id: record5.id,
378522
378526
  vision: record5.type === "vlm" || capabilities.includes("vision"),
@@ -379024,6 +379028,296 @@ var init_pi_models_runtime = __esm(() => {
379024
379028
  ]);
379025
379029
  });
379026
379030
 
379031
+ // src/backend/dev/pi-model-factory.ts
379032
+ function isUnselectedLocalModelHandle(model) {
379033
+ return typeof model !== "string" || model.length === 0 || model === "auto" || model === UNSELECTED_LOCAL_MODEL_HANDLE || model.startsWith("letta/");
379034
+ }
379035
+ function normalizeOpenAICompatibleLocalModelHandle(model) {
379036
+ if (!model?.startsWith("openai/"))
379037
+ return model;
379038
+ const nestedHandle = model.slice("openai/".length);
379039
+ const nestedProvider = resolveProviderFromModelHandle(nestedHandle);
379040
+ if (!nestedProvider)
379041
+ return model;
379042
+ return getPiProviderSpec(nestedProvider).localModelDiscovery === "openai-compatible" ? nestedHandle : model;
379043
+ }
379044
+ function settingString(value) {
379045
+ return typeof value === "string" && value.length > 0 ? value : undefined;
379046
+ }
379047
+ function thinkingLevelSetting(value, preserveMax) {
379048
+ const effort = settingString(value);
379049
+ if (effort === "max")
379050
+ return preserveMax ? "max" : "xhigh";
379051
+ return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" ? effort : undefined;
379052
+ }
379053
+ function reasoningForSettings(modelSettings, modelHandle) {
379054
+ const thinking = isRecord(modelSettings.thinking) ? modelSettings.thinking : undefined;
379055
+ if (thinking?.type === "disabled")
379056
+ return;
379057
+ const nestedReasoning = isRecord(modelSettings.reasoning) ? modelSettings.reasoning : undefined;
379058
+ const modelId = modelHandle?.slice(modelHandle.indexOf("/") + 1);
379059
+ const preserveMax = modelId?.startsWith("gpt-5.6") === true;
379060
+ return thinkingLevelSetting(nestedReasoning?.reasoning_effort, preserveMax) ?? thinkingLevelSetting(modelSettings.effort, preserveMax) ?? thinkingLevelSetting(modelSettings.reasoning_effort, preserveMax);
379061
+ }
379062
+ function applyPiEnvOverrides(overrides) {
379063
+ if (!overrides)
379064
+ return () => {};
379065
+ const previous = new Map;
379066
+ for (const [key, value] of Object.entries(overrides)) {
379067
+ previous.set(key, process.env[key]);
379068
+ if (value === undefined) {
379069
+ delete process.env[key];
379070
+ } else {
379071
+ process.env[key] = value;
379072
+ }
379073
+ }
379074
+ return () => {
379075
+ for (const [key, value] of previous) {
379076
+ if (value === undefined) {
379077
+ delete process.env[key];
379078
+ } else {
379079
+ process.env[key] = value;
379080
+ }
379081
+ }
379082
+ };
379083
+ }
379084
+ function hasEnvValue2(value) {
379085
+ return typeof value === "string" && value.length > 0;
379086
+ }
379087
+ function inferDefaultProviderFromStandardKeys() {
379088
+ const hasOpenAIKey = hasEnvValue2(process.env.OPENAI_API_KEY);
379089
+ const hasAnthropicKey = hasEnvValue2(process.env.ANTHROPIC_API_KEY);
379090
+ if (!hasOpenAIKey && hasAnthropicKey)
379091
+ return "anthropic";
379092
+ return DEFAULT_PI_PROVIDER;
379093
+ }
379094
+ function resolvePiProvider(provider = process.env.LETTA_CODE_DEV_PI_PROVIDER ?? inferDefaultProviderFromStandardKeys()) {
379095
+ if (isPiProvider(provider))
379096
+ return provider;
379097
+ if (getRegisteredPiProvider(provider))
379098
+ return provider;
379099
+ throw new Error(`Unknown pi provider "${provider}". Expected ${expectedPiProviderList()}.`);
379100
+ }
379101
+ function resolvePiProviderFromAgent(model, modelSettings = {}) {
379102
+ const registeredProvider = resolveRegisteredPiProviderFromModelHandle(model);
379103
+ if (registeredProvider)
379104
+ return registeredProvider;
379105
+ const handleProvider = resolveProviderFromModelHandle(model);
379106
+ if (handleProvider)
379107
+ return handleProvider;
379108
+ const settingsProvider = resolveProviderFromProviderType(modelSettings.provider_type);
379109
+ if (settingsProvider)
379110
+ return settingsProvider;
379111
+ if (model && !isUnselectedLocalModelHandle(model)) {
379112
+ const slashIndex = model.indexOf("/");
379113
+ if (slashIndex > 0) {
379114
+ throw new Error(`Model provider "${model.slice(0, slashIndex)}" is not registered. Load or repair the provider mod, or choose another model with /model.`);
379115
+ }
379116
+ }
379117
+ return resolvePiProvider();
379118
+ }
379119
+ function resolvePiModelFromAgent(model, provider) {
379120
+ return stripProviderHandlePrefix(model, provider);
379121
+ }
379122
+ function localProviderRecord(providerNames, storageDir) {
379123
+ for (const providerName of providerNames) {
379124
+ const record5 = getLocalProviderRecordByName(providerName, storageDir);
379125
+ if (record5)
379126
+ return record5;
379127
+ }
379128
+ return null;
379129
+ }
379130
+ function localProviderConnection(providerNames, storageDir) {
379131
+ const record5 = localProviderRecord(providerNames, storageDir);
379132
+ return {
379133
+ baseURL: record5?.base_url,
379134
+ timeout: resolveLocalProviderTimeout({
379135
+ configuredTimeout: record5?.timeout,
379136
+ providerIds: providerNames
379137
+ }),
379138
+ ...record5 ? { record: record5 } : {}
379139
+ };
379140
+ }
379141
+ function resolveZaiConnection(options3) {
379142
+ const regularRecord = localProviderRecord(["zai", LOCAL_ZAI_PROVIDER_NAME], options3.storageDir);
379143
+ const codingRecord = localProviderRecord(["zai_coding", LOCAL_ZAI_CODING_PROVIDER_NAME], options3.storageDir);
379144
+ const regularKey = localProviderApiKeyFromRecord(regularRecord) ?? process.env.ZAI_API_KEY ?? process.env.ZHIPU_API_KEY;
379145
+ const codingKey = localProviderApiKeyFromRecord(codingRecord) ?? process.env.ZAI_CODING_API_KEY;
379146
+ const regularConnection = {
379147
+ providerName: "zai",
379148
+ baseURL: regularRecord?.base_url ?? process.env.ZAI_BASE_URL ?? "https://api.z.ai/api/paas/v4",
379149
+ apiKey: regularKey,
379150
+ timeout: resolveLocalProviderTimeout({
379151
+ configuredTimeout: regularRecord?.timeout,
379152
+ providerIds: [LOCAL_ZAI_PROVIDER_NAME, "zai"]
379153
+ })
379154
+ };
379155
+ const codingConnection = {
379156
+ providerName: "zai-coding",
379157
+ baseURL: codingRecord?.base_url ?? process.env.ZAI_CODING_BASE_URL ?? "https://api.z.ai/api/coding/paas/v4",
379158
+ apiKey: codingKey,
379159
+ timeout: resolveLocalProviderTimeout({
379160
+ configuredTimeout: codingRecord?.timeout,
379161
+ providerIds: [LOCAL_ZAI_CODING_PROVIDER_NAME, "zai-coding"]
379162
+ })
379163
+ };
379164
+ if (options3.preferredProviderType === "zai_coding" && codingKey) {
379165
+ return codingConnection;
379166
+ }
379167
+ if (options3.preferredProviderType === "zai" && regularKey) {
379168
+ return regularConnection;
379169
+ }
379170
+ if (codingKey)
379171
+ return codingConnection;
379172
+ if (regularKey)
379173
+ return regularConnection;
379174
+ return codingConnection;
379175
+ }
379176
+ function fallbackCatalogModelId(provider, modelId) {
379177
+ if (provider !== "openai")
379178
+ return;
379179
+ const withoutReleaseDate = modelId.replace(/-\d{4}-\d{2}-\d{2}$/, "");
379180
+ return withoutReleaseDate === modelId ? undefined : withoutReleaseDate;
379181
+ }
379182
+ function withOverrides(model, overrides) {
379183
+ return {
379184
+ ...model,
379185
+ ...overrides.baseURL ? { baseUrl: overrides.baseURL } : {},
379186
+ ...overrides.headers ? { headers: { ...model.headers, ...overrides.headers } } : {},
379187
+ ...overrides.contextWindow ? { contextWindow: overrides.contextWindow } : {},
379188
+ ...overrides.maxTokens ? { maxTokens: overrides.maxTokens } : {}
379189
+ };
379190
+ }
379191
+ function nonNullHeaders(headers) {
379192
+ return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null));
379193
+ }
379194
+ function mergeHeaders3(...headers) {
379195
+ const merged = {};
379196
+ for (const header of headers) {
379197
+ if (!header)
379198
+ continue;
379199
+ Object.assign(merged, header);
379200
+ }
379201
+ return Object.keys(merged).length > 0 ? merged : undefined;
379202
+ }
379203
+ function numericSetting(value) {
379204
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
379205
+ }
379206
+ function bedrockLocalProviderOptions(record5) {
379207
+ if (!record5)
379208
+ return {};
379209
+ const providerOptions = {};
379210
+ const envOverrides = {};
379211
+ if (record5.region) {
379212
+ providerOptions.region = record5.region;
379213
+ envOverrides.AWS_REGION = record5.region;
379214
+ envOverrides.AWS_DEFAULT_REGION = record5.region;
379215
+ }
379216
+ if (record5.profile) {
379217
+ providerOptions.profile = record5.profile;
379218
+ envOverrides.AWS_PROFILE = record5.profile;
379219
+ }
379220
+ if (record5.auth.type === "api" && record5.auth.key) {
379221
+ if (record5.access_key) {
379222
+ envOverrides.AWS_ACCESS_KEY_ID = record5.access_key;
379223
+ envOverrides.AWS_SECRET_ACCESS_KEY = record5.auth.key;
379224
+ } else {
379225
+ providerOptions.bearerToken = record5.auth.key;
379226
+ envOverrides.AWS_BEARER_TOKEN_BEDROCK = record5.auth.key;
379227
+ }
379228
+ }
379229
+ return {
379230
+ ...Object.keys(providerOptions).length > 0 ? { providerOptions } : {},
379231
+ ...Object.keys(envOverrides).length > 0 ? { envOverrides } : {}
379232
+ };
379233
+ }
379234
+ async function resolvePiModelForAgent(modelHandle, modelSettings = {}, options3 = {}) {
379235
+ const concreteModelHandle = normalizeOpenAICompatibleLocalModelHandle(isUnselectedLocalModelHandle(modelHandle) ? undefined : modelHandle);
379236
+ const provider = options3.provider ? resolvePiProvider(options3.provider) : resolvePiProviderFromAgent(concreteModelHandle, modelSettings);
379237
+ const registeredProvider = getRegisteredPiProvider(provider);
379238
+ const spec = isPiProvider(provider) ? getPiProviderSpec(provider) : undefined;
379239
+ const modelId = options3.model ?? (registeredProvider ? stripRegisteredProviderHandlePrefix(concreteModelHandle, provider) : undefined) ?? (spec ? resolvePiModelFromAgent(concreteModelHandle, spec.id) : undefined) ?? registeredProvider?.config.models?.[0]?.id ?? (spec?.defaultModel ? resolvePiModelFromAgent(spec.defaultModel, spec.id) : undefined) ?? process.env.LETTA_CODE_DEV_PI_MODEL ?? "";
379240
+ const storageDir = options3.localProviderAuthStorageDir;
379241
+ const modelsRuntime = options3.modelsRuntime ?? new LocalPiModelsRuntime({
379242
+ ...storageDir ? { storageDir } : {}
379243
+ });
379244
+ const preferredProviderType = typeof modelSettings.provider_type === "string" ? modelSettings.provider_type : options3.preferredProviderType;
379245
+ const localNames = registeredProvider ? localNamesForProviderId(provider) : spec?.localProviderNames ?? [provider];
379246
+ let connection = localProviderConnection(localNames, storageDir);
379247
+ let baseURL = connection.baseURL ?? spec?.baseUrlEnv?.() ?? spec?.defaultBaseURL ?? registeredProvider?.config.baseUrl;
379248
+ let headers = mergeHeaders3(spec?.headers?.());
379249
+ let providerOptions;
379250
+ let envOverrides;
379251
+ let oauthCredentials;
379252
+ if (!modelId) {
379253
+ throw new Error(`No model selected for provider "${provider}". Choose an available model with /model.`);
379254
+ }
379255
+ const runtimeProviderId = registeredProvider ? provider : spec && modelsRuntime.isRuntimeManagedProvider(spec.id) ? spec.id : spec?.piProvider;
379256
+ if (!runtimeProviderId) {
379257
+ throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Register the provider with models before using it.");
379258
+ }
379259
+ const fallbackModelId = !registeredProvider && spec?.piProvider ? fallbackCatalogModelId(spec.piProvider, modelId) : undefined;
379260
+ const { model: publishedModel, auth: authResult } = await modelsRuntime.resolveTurn(runtimeProviderId, modelId, fallbackModelId);
379261
+ connection = { ...connection, apiKey: authResult?.auth.apiKey };
379262
+ if (authResult?.auth.baseUrl)
379263
+ baseURL = authResult.auth.baseUrl;
379264
+ if (authResult?.auth.headers) {
379265
+ headers = mergeHeaders3(headers, nonNullHeaders(authResult.auth.headers));
379266
+ }
379267
+ if (connection.record?.auth.type === "oauth") {
379268
+ const stored = await modelsRuntime.getStoredCredential(runtimeProviderId);
379269
+ oauthCredentials = stored?.type === "oauth" ? stored : undefined;
379270
+ }
379271
+ if (provider === "zai") {
379272
+ const zai = resolveZaiConnection({
379273
+ storageDir,
379274
+ preferredProviderType: preferredProviderType === "zai" || preferredProviderType === "zai_coding" ? preferredProviderType : undefined
379275
+ });
379276
+ connection = {
379277
+ apiKey: zai.apiKey,
379278
+ baseURL: zai.baseURL,
379279
+ timeout: zai.timeout
379280
+ };
379281
+ baseURL = zai.baseURL;
379282
+ }
379283
+ if (provider === "amazon-bedrock") {
379284
+ const bedrock = bedrockLocalProviderOptions(connection.record);
379285
+ providerOptions = bedrock.providerOptions;
379286
+ envOverrides = bedrock.envOverrides;
379287
+ }
379288
+ if (!publishedModel) {
379289
+ throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Choose an available model with /model.");
379290
+ }
379291
+ const hookedModel = oauthCredentials && registeredProvider?.config.oauth?.modifyModels ? registeredProvider.config.oauth.modifyModels([structuredClone(publishedModel)], oauthCredentials)[0] ?? publishedModel : publishedModel;
379292
+ const contextWindow = numericSetting(modelSettings.context_window_limit);
379293
+ const maxTokens = numericSetting(modelSettings.max_tokens);
379294
+ const allowBaseUrlOverride = !registeredProvider && spec !== undefined && !modelsRuntime.isRuntimeManagedProvider(spec.id);
379295
+ const overrides = {
379296
+ ...allowBaseUrlOverride && baseURL && baseURL !== hookedModel.baseUrl ? { baseURL } : {},
379297
+ ...contextWindow && contextWindow !== hookedModel.contextWindow ? { contextWindow } : {},
379298
+ ...maxTokens && maxTokens !== hookedModel.maxTokens ? { maxTokens } : {}
379299
+ };
379300
+ const model = Object.keys(overrides).length > 0 ? withOverrides(hookedModel, overrides) : hookedModel;
379301
+ return {
379302
+ provider,
379303
+ model,
379304
+ apiKey: connection.apiKey,
379305
+ timeout: connection.timeout,
379306
+ headers,
379307
+ providerOptions,
379308
+ envOverrides
379309
+ };
379310
+ }
379311
+ var DEFAULT_PI_PROVIDER = "openai", UNSELECTED_LOCAL_MODEL_HANDLE = "local/default";
379312
+ var init_pi_model_factory = __esm(() => {
379313
+ init_local_pi_credential_store();
379314
+ init_local_provider_auth_store();
379315
+ init_local_provider_timeout();
379316
+ init_pi_models_runtime();
379317
+ init_pi_provider_mod_registry();
379318
+ init_pi_provider_registry();
379319
+ });
379320
+
379027
379321
  // src/backend/local/local-context-estimate.ts
379028
379322
  function positiveUsageNumber(value) {
379029
379323
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
@@ -379147,561 +379441,6 @@ function estimateLocalContextTokens(messages) {
379147
379441
  }
379148
379442
  var IMAGE_TOKEN_ESTIMATE = 1200;
379149
379443
 
379150
- // src/backend/dev/provider-turn-executor.ts
379151
- var exports_provider_turn_executor = {};
379152
- __export(exports_provider_turn_executor, {
379153
- providerStreamPart: () => providerStreamPart,
379154
- providerLocalMessage: () => providerLocalMessage,
379155
- providerLettaChunk: () => providerLettaChunk,
379156
- estimateProviderRequestBytes: () => estimateProviderRequestBytes,
379157
- estimateProviderContextTokens: () => estimateProviderContextTokens,
379158
- contextTokensFromUsage: () => contextTokensFromUsage,
379159
- buildProviderTurnInput: () => buildProviderTurnInput,
379160
- ProviderTurnExecutor: () => ProviderTurnExecutor
379161
- });
379162
- import { randomUUID as randomUUID21 } from "node:crypto";
379163
- function providerStreamPart(part) {
379164
- return { type: "provider-part", part };
379165
- }
379166
- function providerLocalMessage(message) {
379167
- return { type: "local-message", message };
379168
- }
379169
- function providerLettaChunk(chunk) {
379170
- return { type: "letta-chunk", chunk };
379171
- }
379172
-
379173
- class MissingProviderStreamAdapter {
379174
- async* stream() {
379175
- yield {
379176
- type: "error",
379177
- error: new Error("Provider turn adapter is not configured for this dev backend")
379178
- };
379179
- }
379180
- }
379181
- function bodyListField(body, key) {
379182
- const value = body[key];
379183
- return Array.isArray(value) ? value : [];
379184
- }
379185
- function buildProviderTurnInput(input) {
379186
- return {
379187
- conversationId: input.conversationId,
379188
- agentId: input.agentId,
379189
- agent: input.agent,
379190
- systemPrompt: input.systemPrompt,
379191
- midConversationSystemPrompt: input.midConversationSystemPrompt,
379192
- body: input.body,
379193
- history: input.history,
379194
- uiMessages: input.uiMessages,
379195
- clientTools: bodyListField(input.body, "client_tools"),
379196
- clientSkills: bodyListField(input.body, "client_skills")
379197
- };
379198
- }
379199
- function stringifyToolInput(input) {
379200
- if (typeof input === "string")
379201
- return input;
379202
- return JSON.stringify(input ?? {});
379203
- }
379204
- function createLocalMessageChunk(message) {
379205
- return markLocalStateChunkOnly(attachLocalMessage({ message_type: "local_message" }, message));
379206
- }
379207
- function createProviderErrorChunks(error54) {
379208
- const info = normalizeLocalProviderError(error54);
379209
- return [
379210
- {
379211
- message_type: "error_message",
379212
- message: info.message,
379213
- detail: info.detail,
379214
- error_type: info.error_type,
379215
- retryable: info.retryable
379216
- },
379217
- {
379218
- message_type: "stop_reason",
379219
- stop_reason: info.stop_reason
379220
- }
379221
- ];
379222
- }
379223
- function contextTokensFromUsage(usage) {
379224
- return contextTokensFromLocalUsage(usage);
379225
- }
379226
- function estimateSerializedTokens(value) {
379227
- if (value === undefined || value === null)
379228
- return 0;
379229
- try {
379230
- const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
379231
- return Math.ceil(serialized.length / 4);
379232
- } catch {
379233
- return 0;
379234
- }
379235
- }
379236
- function estimateProviderContextTokens(input) {
379237
- const contextEstimate = estimateLocalContextTokens(input.uiMessages);
379238
- if (contextEstimate.lastUsageIndex !== null) {
379239
- return contextEstimate.tokens > 0 ? contextEstimate.tokens : undefined;
379240
- }
379241
- const systemPromptTokens = estimateSerializedTokens(input.systemPrompt ?? input.agent.system);
379242
- const messageTokens = contextEstimate.tokens;
379243
- const toolTokens = estimateSerializedTokens(input.clientTools);
379244
- const total = systemPromptTokens + messageTokens + toolTokens;
379245
- return total > 0 ? total : undefined;
379246
- }
379247
- function serializedLength(value) {
379248
- if (value === undefined || value === null)
379249
- return 0;
379250
- try {
379251
- const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
379252
- return serialized.length;
379253
- } catch {
379254
- return 0;
379255
- }
379256
- }
379257
- function estimateProviderRequestBytes(input) {
379258
- const systemPromptBytes = serializedLength(input.systemPrompt ?? input.agent.system);
379259
- const messageBytes = serializedLength(input.uiMessages);
379260
- const toolBytes = serializedLength(input.clientTools);
379261
- const total = systemPromptBytes + messageBytes + toolBytes;
379262
- return total > 0 ? total : undefined;
379263
- }
379264
- function createUsageStatisticsChunk(usage, contextTokensEstimate) {
379265
- const promptTokens = usage?.input;
379266
- const completionTokens = usage?.output;
379267
- const totalTokens = usage?.totalTokens;
379268
- const usageContextTokens = usage ? contextTokensFromUsage(usage) : undefined;
379269
- const contextTokens = usageContextTokens ?? contextTokensEstimate;
379270
- const cachedInputTokens = usage?.cacheRead;
379271
- const cacheWriteTokens = usage?.cacheWrite;
379272
- if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined && cachedInputTokens === undefined && cacheWriteTokens === undefined && contextTokens === undefined) {
379273
- return;
379274
- }
379275
- return {
379276
- message_type: "usage_statistics",
379277
- ...promptTokens !== undefined ? { prompt_tokens: promptTokens } : {},
379278
- ...completionTokens !== undefined ? { completion_tokens: completionTokens } : {},
379279
- ...totalTokens !== undefined ? { total_tokens: totalTokens } : {},
379280
- ...cachedInputTokens !== undefined ? { cached_input_tokens: cachedInputTokens } : {},
379281
- ...cacheWriteTokens !== undefined ? { cache_write_tokens: cacheWriteTokens } : {},
379282
- ...contextTokens !== undefined ? { context_tokens: contextTokens } : {}
379283
- };
379284
- }
379285
- function errorFromAssistantEvent(part) {
379286
- if (part.type !== "error")
379287
- return new Error("Unknown provider stream error");
379288
- return new Error(part.error.errorMessage ?? "Unknown local provider error");
379289
- }
379290
- function contentMatchesMessageType(content, messageType) {
379291
- if (!content || typeof content !== "object" || !("type" in content)) {
379292
- return false;
379293
- }
379294
- return messageType === "assistant_message" ? content.type === "text" : content.type === "thinking";
379295
- }
379296
- function contiguousContentStartIndex(partial4, contentIndex, messageType) {
379297
- let startIndex = contentIndex;
379298
- while (startIndex > 0 && contentMatchesMessageType(partial4.content[startIndex - 1], messageType)) {
379299
- startIndex -= 1;
379300
- }
379301
- return startIndex;
379302
- }
379303
- function otidForContentSegment(otids, prefix, contentIndex, partial4, messageType) {
379304
- const segmentStartIndex = contiguousContentStartIndex(partial4, contentIndex, messageType);
379305
- const existing = otids.get(segmentStartIndex);
379306
- if (existing)
379307
- return existing;
379308
- const otid = `${prefix}-${segmentStartIndex}-${randomUUID21()}`;
379309
- otids.set(segmentStartIndex, otid);
379310
- return otid;
379311
- }
379312
- function createProviderLettaStream(events, contextTokensEstimate) {
379313
- const controller = new AbortController;
379314
- return {
379315
- controller,
379316
- async* [Symbol.asyncIterator]() {
379317
- let sawToolCall = false;
379318
- let pendingStopReason;
379319
- let sawUsageStatistics = false;
379320
- const assistantOtids = new Map;
379321
- const reasoningOtids = new Map;
379322
- try {
379323
- for await (const event2 of events) {
379324
- if (event2.type === "error") {
379325
- yield* createProviderErrorChunks(event2.error);
379326
- return;
379327
- }
379328
- if (event2.type === "local-message") {
379329
- yield createLocalMessageChunk(event2.message);
379330
- continue;
379331
- }
379332
- if (event2.type === "letta-chunk") {
379333
- yield event2.chunk;
379334
- continue;
379335
- }
379336
- const { part } = event2;
379337
- if (part.type === "text_delta") {
379338
- yield {
379339
- message_type: "assistant_message",
379340
- otid: otidForContentSegment(assistantOtids, "provider-assistant", part.contentIndex, part.partial, "assistant_message"),
379341
- content: [{ type: "text", text: part.delta }]
379342
- };
379343
- continue;
379344
- }
379345
- if (part.type === "thinking_delta") {
379346
- yield {
379347
- message_type: "reasoning_message",
379348
- otid: otidForContentSegment(reasoningOtids, "provider-reasoning", part.contentIndex, part.partial, "reasoning_message"),
379349
- reasoning: part.delta
379350
- };
379351
- continue;
379352
- }
379353
- if (part.type === "toolcall_end") {
379354
- sawToolCall = true;
379355
- yield {
379356
- message_type: "approval_request_message",
379357
- tool_call: {
379358
- tool_call_id: part.toolCall.id,
379359
- name: part.toolCall.name,
379360
- arguments: stringifyToolInput(part.toolCall.arguments)
379361
- }
379362
- };
379363
- continue;
379364
- }
379365
- if (part.type === "done") {
379366
- if (!sawUsageStatistics) {
379367
- const usageChunk = createUsageStatisticsChunk(part.message.usage, contextTokensEstimate);
379368
- if (usageChunk) {
379369
- sawUsageStatistics = true;
379370
- yield usageChunk;
379371
- }
379372
- }
379373
- pendingStopReason = {
379374
- message_type: "stop_reason",
379375
- stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : part.reason === "length" ? "max_tokens_exceeded" : "end_turn"
379376
- };
379377
- continue;
379378
- }
379379
- if (part.type === "error") {
379380
- yield* createProviderErrorChunks(errorFromAssistantEvent(part));
379381
- return;
379382
- }
379383
- }
379384
- if (pendingStopReason) {
379385
- yield pendingStopReason;
379386
- } else if (sawToolCall) {
379387
- yield {
379388
- message_type: "stop_reason",
379389
- stop_reason: "requires_approval"
379390
- };
379391
- }
379392
- } catch (error54) {
379393
- yield* createProviderErrorChunks(error54);
379394
- }
379395
- }
379396
- };
379397
- }
379398
-
379399
- class ProviderTurnExecutor {
379400
- adapter;
379401
- constructor(adapter = new MissingProviderStreamAdapter) {
379402
- this.adapter = adapter;
379403
- }
379404
- async execute(input) {
379405
- const providerInput = buildProviderTurnInput(input);
379406
- const events = await this.adapter.stream(providerInput);
379407
- return createProviderLettaStream(events, estimateProviderContextTokens(providerInput));
379408
- }
379409
- }
379410
- var init_provider_turn_executor = __esm(() => {
379411
- init_local_stream_chunks();
379412
- init_local_provider_errors();
379413
- });
379414
-
379415
- // src/backend/dev/pi-model-factory.ts
379416
- function isUnselectedLocalModelHandle(model) {
379417
- return typeof model !== "string" || model.length === 0 || model === "auto" || model === UNSELECTED_LOCAL_MODEL_HANDLE || model.startsWith("letta/");
379418
- }
379419
- function normalizeOpenAICompatibleLocalModelHandle(model) {
379420
- if (!model?.startsWith("openai/"))
379421
- return model;
379422
- const nestedHandle = model.slice("openai/".length);
379423
- const nestedProvider = resolveProviderFromModelHandle(nestedHandle);
379424
- if (!nestedProvider)
379425
- return model;
379426
- return getPiProviderSpec(nestedProvider).localModelDiscovery === "openai-compatible" ? nestedHandle : model;
379427
- }
379428
- function settingString(value) {
379429
- return typeof value === "string" && value.length > 0 ? value : undefined;
379430
- }
379431
- function thinkingLevelSetting(value, preserveMax) {
379432
- const effort = settingString(value);
379433
- if (effort === "max")
379434
- return preserveMax ? "max" : "xhigh";
379435
- return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" ? effort : undefined;
379436
- }
379437
- function reasoningForSettings(modelSettings, modelHandle) {
379438
- const thinking = isRecord(modelSettings.thinking) ? modelSettings.thinking : undefined;
379439
- if (thinking?.type === "disabled")
379440
- return;
379441
- const nestedReasoning = isRecord(modelSettings.reasoning) ? modelSettings.reasoning : undefined;
379442
- const modelId = modelHandle?.slice(modelHandle.indexOf("/") + 1);
379443
- const preserveMax = modelId?.startsWith("gpt-5.6") === true;
379444
- return thinkingLevelSetting(nestedReasoning?.reasoning_effort, preserveMax) ?? thinkingLevelSetting(modelSettings.effort, preserveMax) ?? thinkingLevelSetting(modelSettings.reasoning_effort, preserveMax);
379445
- }
379446
- function applyPiEnvOverrides(overrides) {
379447
- if (!overrides)
379448
- return () => {};
379449
- const previous = new Map;
379450
- for (const [key, value] of Object.entries(overrides)) {
379451
- previous.set(key, process.env[key]);
379452
- if (value === undefined) {
379453
- delete process.env[key];
379454
- } else {
379455
- process.env[key] = value;
379456
- }
379457
- }
379458
- return () => {
379459
- for (const [key, value] of previous) {
379460
- if (value === undefined) {
379461
- delete process.env[key];
379462
- } else {
379463
- process.env[key] = value;
379464
- }
379465
- }
379466
- };
379467
- }
379468
- function hasEnvValue2(value) {
379469
- return typeof value === "string" && value.length > 0;
379470
- }
379471
- function inferDefaultProviderFromStandardKeys() {
379472
- const hasOpenAIKey = hasEnvValue2(process.env.OPENAI_API_KEY);
379473
- const hasAnthropicKey = hasEnvValue2(process.env.ANTHROPIC_API_KEY);
379474
- if (!hasOpenAIKey && hasAnthropicKey)
379475
- return "anthropic";
379476
- return DEFAULT_PI_PROVIDER;
379477
- }
379478
- function resolvePiProvider(provider = process.env.LETTA_CODE_DEV_PI_PROVIDER ?? inferDefaultProviderFromStandardKeys()) {
379479
- if (isPiProvider(provider))
379480
- return provider;
379481
- if (getRegisteredPiProvider(provider))
379482
- return provider;
379483
- throw new Error(`Unknown pi provider "${provider}". Expected ${expectedPiProviderList()}.`);
379484
- }
379485
- function resolvePiProviderFromAgent(model, modelSettings = {}) {
379486
- const registeredProvider = resolveRegisteredPiProviderFromModelHandle(model);
379487
- if (registeredProvider)
379488
- return registeredProvider;
379489
- const handleProvider = resolveProviderFromModelHandle(model);
379490
- if (handleProvider)
379491
- return handleProvider;
379492
- const settingsProvider = resolveProviderFromProviderType(modelSettings.provider_type);
379493
- if (settingsProvider)
379494
- return settingsProvider;
379495
- if (model && !isUnselectedLocalModelHandle(model)) {
379496
- const slashIndex = model.indexOf("/");
379497
- if (slashIndex > 0) {
379498
- throw new Error(`Model provider "${model.slice(0, slashIndex)}" is not registered. Load or repair the provider mod, or choose another model with /model.`);
379499
- }
379500
- }
379501
- return resolvePiProvider();
379502
- }
379503
- function resolvePiModelFromAgent(model, provider) {
379504
- return stripProviderHandlePrefix(model, provider);
379505
- }
379506
- function localProviderRecord(providerNames, storageDir) {
379507
- for (const providerName of providerNames) {
379508
- const record5 = getLocalProviderRecordByName(providerName, storageDir);
379509
- if (record5)
379510
- return record5;
379511
- }
379512
- return null;
379513
- }
379514
- function localProviderConnection(providerNames, storageDir) {
379515
- const record5 = localProviderRecord(providerNames, storageDir);
379516
- return {
379517
- baseURL: record5?.base_url,
379518
- timeout: resolveLocalProviderTimeout({
379519
- configuredTimeout: record5?.timeout,
379520
- providerIds: providerNames
379521
- }),
379522
- ...record5 ? { record: record5 } : {}
379523
- };
379524
- }
379525
- function resolveZaiConnection(options3) {
379526
- const regularRecord = localProviderRecord(["zai", LOCAL_ZAI_PROVIDER_NAME], options3.storageDir);
379527
- const codingRecord = localProviderRecord(["zai_coding", LOCAL_ZAI_CODING_PROVIDER_NAME], options3.storageDir);
379528
- const regularKey = localProviderApiKeyFromRecord(regularRecord) ?? process.env.ZAI_API_KEY ?? process.env.ZHIPU_API_KEY;
379529
- const codingKey = localProviderApiKeyFromRecord(codingRecord) ?? process.env.ZAI_CODING_API_KEY;
379530
- const regularConnection = {
379531
- providerName: "zai",
379532
- baseURL: regularRecord?.base_url ?? process.env.ZAI_BASE_URL ?? "https://api.z.ai/api/paas/v4",
379533
- apiKey: regularKey,
379534
- timeout: resolveLocalProviderTimeout({
379535
- configuredTimeout: regularRecord?.timeout,
379536
- providerIds: [LOCAL_ZAI_PROVIDER_NAME, "zai"]
379537
- })
379538
- };
379539
- const codingConnection = {
379540
- providerName: "zai-coding",
379541
- baseURL: codingRecord?.base_url ?? process.env.ZAI_CODING_BASE_URL ?? "https://api.z.ai/api/coding/paas/v4",
379542
- apiKey: codingKey,
379543
- timeout: resolveLocalProviderTimeout({
379544
- configuredTimeout: codingRecord?.timeout,
379545
- providerIds: [LOCAL_ZAI_CODING_PROVIDER_NAME, "zai-coding"]
379546
- })
379547
- };
379548
- if (options3.preferredProviderType === "zai_coding" && codingKey) {
379549
- return codingConnection;
379550
- }
379551
- if (options3.preferredProviderType === "zai" && regularKey) {
379552
- return regularConnection;
379553
- }
379554
- if (codingKey)
379555
- return codingConnection;
379556
- if (regularKey)
379557
- return regularConnection;
379558
- return codingConnection;
379559
- }
379560
- function fallbackCatalogModelId(provider, modelId) {
379561
- if (provider !== "openai")
379562
- return;
379563
- const withoutReleaseDate = modelId.replace(/-\d{4}-\d{2}-\d{2}$/, "");
379564
- return withoutReleaseDate === modelId ? undefined : withoutReleaseDate;
379565
- }
379566
- function withOverrides(model, overrides) {
379567
- return {
379568
- ...model,
379569
- ...overrides.baseURL ? { baseUrl: overrides.baseURL } : {},
379570
- ...overrides.headers ? { headers: { ...model.headers, ...overrides.headers } } : {},
379571
- ...overrides.contextWindow ? { contextWindow: overrides.contextWindow } : {},
379572
- ...overrides.maxTokens ? { maxTokens: overrides.maxTokens } : {}
379573
- };
379574
- }
379575
- function nonNullHeaders(headers) {
379576
- return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null));
379577
- }
379578
- function mergeHeaders3(...headers) {
379579
- const merged = {};
379580
- for (const header of headers) {
379581
- if (!header)
379582
- continue;
379583
- Object.assign(merged, header);
379584
- }
379585
- return Object.keys(merged).length > 0 ? merged : undefined;
379586
- }
379587
- function numericSetting(value) {
379588
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
379589
- }
379590
- function bedrockLocalProviderOptions(record5) {
379591
- if (!record5)
379592
- return {};
379593
- const providerOptions = {};
379594
- const envOverrides = {};
379595
- if (record5.region) {
379596
- providerOptions.region = record5.region;
379597
- envOverrides.AWS_REGION = record5.region;
379598
- envOverrides.AWS_DEFAULT_REGION = record5.region;
379599
- }
379600
- if (record5.profile) {
379601
- providerOptions.profile = record5.profile;
379602
- envOverrides.AWS_PROFILE = record5.profile;
379603
- }
379604
- if (record5.auth.type === "api" && record5.auth.key) {
379605
- if (record5.access_key) {
379606
- envOverrides.AWS_ACCESS_KEY_ID = record5.access_key;
379607
- envOverrides.AWS_SECRET_ACCESS_KEY = record5.auth.key;
379608
- } else {
379609
- providerOptions.bearerToken = record5.auth.key;
379610
- envOverrides.AWS_BEARER_TOKEN_BEDROCK = record5.auth.key;
379611
- }
379612
- }
379613
- return {
379614
- ...Object.keys(providerOptions).length > 0 ? { providerOptions } : {},
379615
- ...Object.keys(envOverrides).length > 0 ? { envOverrides } : {}
379616
- };
379617
- }
379618
- async function resolvePiModelForAgent(modelHandle, modelSettings = {}, options3 = {}) {
379619
- const concreteModelHandle = normalizeOpenAICompatibleLocalModelHandle(isUnselectedLocalModelHandle(modelHandle) ? undefined : modelHandle);
379620
- const provider = options3.provider ? resolvePiProvider(options3.provider) : resolvePiProviderFromAgent(concreteModelHandle, modelSettings);
379621
- const registeredProvider = getRegisteredPiProvider(provider);
379622
- const spec = isPiProvider(provider) ? getPiProviderSpec(provider) : undefined;
379623
- const modelId = options3.model ?? (registeredProvider ? stripRegisteredProviderHandlePrefix(concreteModelHandle, provider) : undefined) ?? (spec ? resolvePiModelFromAgent(concreteModelHandle, spec.id) : undefined) ?? registeredProvider?.config.models?.[0]?.id ?? (spec?.defaultModel ? resolvePiModelFromAgent(spec.defaultModel, spec.id) : undefined) ?? process.env.LETTA_CODE_DEV_PI_MODEL ?? "";
379624
- const storageDir = options3.localProviderAuthStorageDir;
379625
- const modelsRuntime = options3.modelsRuntime ?? new LocalPiModelsRuntime({
379626
- ...storageDir ? { storageDir } : {}
379627
- });
379628
- const preferredProviderType = typeof modelSettings.provider_type === "string" ? modelSettings.provider_type : options3.preferredProviderType;
379629
- const localNames = registeredProvider ? localNamesForProviderId(provider) : spec?.localProviderNames ?? [provider];
379630
- let connection = localProviderConnection(localNames, storageDir);
379631
- let baseURL = connection.baseURL ?? spec?.baseUrlEnv?.() ?? spec?.defaultBaseURL ?? registeredProvider?.config.baseUrl;
379632
- let headers = mergeHeaders3(spec?.headers?.());
379633
- let providerOptions;
379634
- let envOverrides;
379635
- let oauthCredentials;
379636
- if (!modelId) {
379637
- throw new Error(`No model selected for provider "${provider}". Choose an available model with /model.`);
379638
- }
379639
- const runtimeProviderId = registeredProvider ? provider : spec && modelsRuntime.isRuntimeManagedProvider(spec.id) ? spec.id : spec?.piProvider;
379640
- if (!runtimeProviderId) {
379641
- throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Register the provider with models before using it.");
379642
- }
379643
- const fallbackModelId = !registeredProvider && spec?.piProvider ? fallbackCatalogModelId(spec.piProvider, modelId) : undefined;
379644
- const { model: publishedModel, auth: authResult } = await modelsRuntime.resolveTurn(runtimeProviderId, modelId, fallbackModelId);
379645
- connection = { ...connection, apiKey: authResult?.auth.apiKey };
379646
- if (authResult?.auth.baseUrl)
379647
- baseURL = authResult.auth.baseUrl;
379648
- if (authResult?.auth.headers) {
379649
- headers = mergeHeaders3(headers, nonNullHeaders(authResult.auth.headers));
379650
- }
379651
- if (connection.record?.auth.type === "oauth") {
379652
- const stored = await modelsRuntime.getStoredCredential(runtimeProviderId);
379653
- oauthCredentials = stored?.type === "oauth" ? stored : undefined;
379654
- }
379655
- if (provider === "zai") {
379656
- const zai = resolveZaiConnection({
379657
- storageDir,
379658
- preferredProviderType: preferredProviderType === "zai" || preferredProviderType === "zai_coding" ? preferredProviderType : undefined
379659
- });
379660
- connection = {
379661
- apiKey: zai.apiKey,
379662
- baseURL: zai.baseURL,
379663
- timeout: zai.timeout
379664
- };
379665
- baseURL = zai.baseURL;
379666
- }
379667
- if (provider === "amazon-bedrock") {
379668
- const bedrock = bedrockLocalProviderOptions(connection.record);
379669
- providerOptions = bedrock.providerOptions;
379670
- envOverrides = bedrock.envOverrides;
379671
- }
379672
- if (!publishedModel) {
379673
- throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Choose an available model with /model.");
379674
- }
379675
- const hookedModel = oauthCredentials && registeredProvider?.config.oauth?.modifyModels ? registeredProvider.config.oauth.modifyModels([structuredClone(publishedModel)], oauthCredentials)[0] ?? publishedModel : publishedModel;
379676
- const contextWindow = numericSetting(modelSettings.context_window_limit);
379677
- const maxTokens = numericSetting(modelSettings.max_tokens);
379678
- const allowBaseUrlOverride = !registeredProvider && spec !== undefined && !modelsRuntime.isRuntimeManagedProvider(spec.id);
379679
- const overrides = {
379680
- ...allowBaseUrlOverride && baseURL && baseURL !== hookedModel.baseUrl ? { baseURL } : {},
379681
- ...contextWindow && contextWindow !== hookedModel.contextWindow ? { contextWindow } : {},
379682
- ...maxTokens && maxTokens !== hookedModel.maxTokens ? { maxTokens } : {}
379683
- };
379684
- const model = Object.keys(overrides).length > 0 ? withOverrides(hookedModel, overrides) : hookedModel;
379685
- return {
379686
- provider,
379687
- model,
379688
- apiKey: connection.apiKey,
379689
- timeout: connection.timeout,
379690
- headers,
379691
- providerOptions,
379692
- envOverrides
379693
- };
379694
- }
379695
- var DEFAULT_PI_PROVIDER = "openai", UNSELECTED_LOCAL_MODEL_HANDLE = "local/default";
379696
- var init_pi_model_factory = __esm(() => {
379697
- init_local_pi_credential_store();
379698
- init_local_provider_auth_store();
379699
- init_local_provider_timeout();
379700
- init_pi_models_runtime();
379701
- init_pi_provider_mod_registry();
379702
- init_pi_provider_registry();
379703
- });
379704
-
379705
379444
  // src/backend/local/local-model-config.ts
379706
379445
  function localProviderNamesFromRecords(records) {
379707
379446
  return new Set(records.map((record5) => record5.name));
@@ -380358,6 +380097,285 @@ Write in first person as a factual record of what occurred. Be thorough and deta
380358
380097
  Keep your summary under ${SLIDING_WORD_LIMIT} words. Only output the summary.`;
380359
380098
  });
380360
380099
 
380100
+ // src/backend/dev/provider-turn-executor.ts
380101
+ var exports_provider_turn_executor = {};
380102
+ __export(exports_provider_turn_executor, {
380103
+ shouldCompactForContextPressure: () => shouldCompactForContextPressure,
380104
+ providerStreamPart: () => providerStreamPart,
380105
+ providerLocalMessage: () => providerLocalMessage,
380106
+ providerLettaChunk: () => providerLettaChunk,
380107
+ estimateProviderRequestBytes: () => estimateProviderRequestBytes,
380108
+ estimateProviderContextTokens: () => estimateProviderContextTokens,
380109
+ contextTokensFromUsage: () => contextTokensFromUsage,
380110
+ contextCompactionThreshold: () => contextCompactionThreshold,
380111
+ buildProviderTurnInput: () => buildProviderTurnInput,
380112
+ ProviderTurnExecutor: () => ProviderTurnExecutor
380113
+ });
380114
+ import { randomUUID as randomUUID21 } from "node:crypto";
380115
+ function providerStreamPart(part) {
380116
+ return { type: "provider-part", part };
380117
+ }
380118
+ function providerLocalMessage(message) {
380119
+ return { type: "local-message", message };
380120
+ }
380121
+ function providerLettaChunk(chunk) {
380122
+ return { type: "letta-chunk", chunk };
380123
+ }
380124
+
380125
+ class MissingProviderStreamAdapter {
380126
+ async* stream() {
380127
+ yield {
380128
+ type: "error",
380129
+ error: new Error("Provider turn adapter is not configured for this dev backend")
380130
+ };
380131
+ }
380132
+ }
380133
+ function bodyListField(body, key) {
380134
+ const value = body[key];
380135
+ return Array.isArray(value) ? value : [];
380136
+ }
380137
+ function buildProviderTurnInput(input) {
380138
+ return {
380139
+ conversationId: input.conversationId,
380140
+ agentId: input.agentId,
380141
+ agent: input.agent,
380142
+ systemPrompt: input.systemPrompt,
380143
+ midConversationSystemPrompt: input.midConversationSystemPrompt,
380144
+ body: input.body,
380145
+ history: input.history,
380146
+ uiMessages: input.uiMessages,
380147
+ clientTools: bodyListField(input.body, "client_tools"),
380148
+ clientSkills: bodyListField(input.body, "client_skills")
380149
+ };
380150
+ }
380151
+ function stringifyToolInput(input) {
380152
+ if (typeof input === "string")
380153
+ return input;
380154
+ return JSON.stringify(input ?? {});
380155
+ }
380156
+ function createLocalMessageChunk(message) {
380157
+ return markLocalStateChunkOnly(attachLocalMessage({ message_type: "local_message" }, message));
380158
+ }
380159
+ function createProviderErrorChunks(error54) {
380160
+ const info = normalizeLocalProviderError(error54);
380161
+ return [
380162
+ {
380163
+ message_type: "error_message",
380164
+ message: info.message,
380165
+ detail: info.detail,
380166
+ error_type: info.error_type,
380167
+ retryable: info.retryable
380168
+ },
380169
+ {
380170
+ message_type: "stop_reason",
380171
+ stop_reason: info.stop_reason
380172
+ }
380173
+ ];
380174
+ }
380175
+ function contextTokensFromUsage(usage) {
380176
+ return contextTokensFromLocalUsage(usage);
380177
+ }
380178
+ function estimateSerializedTokens(value) {
380179
+ if (value === undefined || value === null)
380180
+ return 0;
380181
+ try {
380182
+ const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
380183
+ return Math.ceil(serialized.length / 4);
380184
+ } catch {
380185
+ return 0;
380186
+ }
380187
+ }
380188
+ function estimateProviderContextTokens(input) {
380189
+ const contextEstimate = estimateLocalContextTokens(input.uiMessages);
380190
+ if (contextEstimate.lastUsageIndex !== null) {
380191
+ return contextEstimate.tokens > 0 ? contextEstimate.tokens : undefined;
380192
+ }
380193
+ const systemPromptTokens = estimateSerializedTokens(input.systemPrompt ?? input.agent.system);
380194
+ const messageTokens = contextEstimate.tokens;
380195
+ const toolTokens = estimateSerializedTokens(input.clientTools);
380196
+ const total = systemPromptTokens + messageTokens + toolTokens;
380197
+ return total > 0 ? total : undefined;
380198
+ }
380199
+ function contextCompactionThreshold(contextWindow) {
380200
+ if (typeof contextWindow !== "number" || !Number.isFinite(contextWindow) || contextWindow <= 0) {
380201
+ return;
380202
+ }
380203
+ const reserveTokens = Math.min(LOCAL_CONTEXT_COMPACTION_RESERVE_TOKENS, Math.max(1, Math.floor(contextWindow * LOCAL_SMALL_CONTEXT_COMPACTION_RESERVE_RATIO)));
380204
+ return Math.max(0, contextWindow - reserveTokens);
380205
+ }
380206
+ function shouldCompactForContextPressure(input) {
380207
+ const threshold = contextCompactionThreshold(input.contextWindow);
380208
+ return input.contextTokens !== undefined && threshold !== undefined && input.contextTokens > threshold;
380209
+ }
380210
+ function serializedLength(value) {
380211
+ if (value === undefined || value === null)
380212
+ return 0;
380213
+ try {
380214
+ const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
380215
+ return serialized.length;
380216
+ } catch {
380217
+ return 0;
380218
+ }
380219
+ }
380220
+ function estimateProviderRequestBytes(input) {
380221
+ const systemPromptBytes = serializedLength(input.systemPrompt ?? input.agent.system);
380222
+ const messageBytes = serializedLength(input.uiMessages);
380223
+ const toolBytes = serializedLength(input.clientTools);
380224
+ const total = systemPromptBytes + messageBytes + toolBytes;
380225
+ return total > 0 ? total : undefined;
380226
+ }
380227
+ function createUsageStatisticsChunk(usage, contextTokensEstimate) {
380228
+ const promptTokens = usage?.input;
380229
+ const completionTokens = usage?.output;
380230
+ const totalTokens = usage?.totalTokens;
380231
+ const usageContextTokens = usage ? contextTokensFromUsage(usage) : undefined;
380232
+ const contextTokens = usageContextTokens ?? contextTokensEstimate;
380233
+ const cachedInputTokens = usage?.cacheRead;
380234
+ const cacheWriteTokens = usage?.cacheWrite;
380235
+ if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined && cachedInputTokens === undefined && cacheWriteTokens === undefined && contextTokens === undefined) {
380236
+ return;
380237
+ }
380238
+ return {
380239
+ message_type: "usage_statistics",
380240
+ ...promptTokens !== undefined ? { prompt_tokens: promptTokens } : {},
380241
+ ...completionTokens !== undefined ? { completion_tokens: completionTokens } : {},
380242
+ ...totalTokens !== undefined ? { total_tokens: totalTokens } : {},
380243
+ ...cachedInputTokens !== undefined ? { cached_input_tokens: cachedInputTokens } : {},
380244
+ ...cacheWriteTokens !== undefined ? { cache_write_tokens: cacheWriteTokens } : {},
380245
+ ...contextTokens !== undefined ? { context_tokens: contextTokens } : {}
380246
+ };
380247
+ }
380248
+ function errorFromAssistantEvent(part) {
380249
+ if (part.type !== "error")
380250
+ return new Error("Unknown provider stream error");
380251
+ return new Error(part.error.errorMessage ?? "Unknown local provider error");
380252
+ }
380253
+ function contentMatchesMessageType(content, messageType) {
380254
+ if (!content || typeof content !== "object" || !("type" in content)) {
380255
+ return false;
380256
+ }
380257
+ return messageType === "assistant_message" ? content.type === "text" : content.type === "thinking";
380258
+ }
380259
+ function contiguousContentStartIndex(partial4, contentIndex, messageType) {
380260
+ let startIndex = contentIndex;
380261
+ while (startIndex > 0 && contentMatchesMessageType(partial4.content[startIndex - 1], messageType)) {
380262
+ startIndex -= 1;
380263
+ }
380264
+ return startIndex;
380265
+ }
380266
+ function otidForContentSegment(otids, prefix, contentIndex, partial4, messageType) {
380267
+ const segmentStartIndex = contiguousContentStartIndex(partial4, contentIndex, messageType);
380268
+ const existing = otids.get(segmentStartIndex);
380269
+ if (existing)
380270
+ return existing;
380271
+ const otid = `${prefix}-${segmentStartIndex}-${randomUUID21()}`;
380272
+ otids.set(segmentStartIndex, otid);
380273
+ return otid;
380274
+ }
380275
+ function createProviderLettaStream(events, contextTokensEstimate) {
380276
+ const controller = new AbortController;
380277
+ return {
380278
+ controller,
380279
+ async* [Symbol.asyncIterator]() {
380280
+ let sawToolCall = false;
380281
+ let pendingStopReason;
380282
+ let sawUsageStatistics = false;
380283
+ const assistantOtids = new Map;
380284
+ const reasoningOtids = new Map;
380285
+ try {
380286
+ for await (const event2 of events) {
380287
+ if (event2.type === "error") {
380288
+ yield* createProviderErrorChunks(event2.error);
380289
+ return;
380290
+ }
380291
+ if (event2.type === "local-message") {
380292
+ yield createLocalMessageChunk(event2.message);
380293
+ continue;
380294
+ }
380295
+ if (event2.type === "letta-chunk") {
380296
+ yield event2.chunk;
380297
+ continue;
380298
+ }
380299
+ const { part } = event2;
380300
+ if (part.type === "text_delta") {
380301
+ yield {
380302
+ message_type: "assistant_message",
380303
+ otid: otidForContentSegment(assistantOtids, "provider-assistant", part.contentIndex, part.partial, "assistant_message"),
380304
+ content: [{ type: "text", text: part.delta }]
380305
+ };
380306
+ continue;
380307
+ }
380308
+ if (part.type === "thinking_delta") {
380309
+ yield {
380310
+ message_type: "reasoning_message",
380311
+ otid: otidForContentSegment(reasoningOtids, "provider-reasoning", part.contentIndex, part.partial, "reasoning_message"),
380312
+ reasoning: part.delta
380313
+ };
380314
+ continue;
380315
+ }
380316
+ if (part.type === "toolcall_end") {
380317
+ sawToolCall = true;
380318
+ yield {
380319
+ message_type: "approval_request_message",
380320
+ tool_call: {
380321
+ tool_call_id: part.toolCall.id,
380322
+ name: part.toolCall.name,
380323
+ arguments: stringifyToolInput(part.toolCall.arguments)
380324
+ }
380325
+ };
380326
+ continue;
380327
+ }
380328
+ if (part.type === "done") {
380329
+ if (!sawUsageStatistics) {
380330
+ const usageChunk = createUsageStatisticsChunk(part.message.usage, contextTokensEstimate);
380331
+ if (usageChunk) {
380332
+ sawUsageStatistics = true;
380333
+ yield usageChunk;
380334
+ }
380335
+ }
380336
+ pendingStopReason = {
380337
+ message_type: "stop_reason",
380338
+ stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : part.reason === "length" ? "max_tokens_exceeded" : "end_turn"
380339
+ };
380340
+ continue;
380341
+ }
380342
+ if (part.type === "error") {
380343
+ yield* createProviderErrorChunks(errorFromAssistantEvent(part));
380344
+ return;
380345
+ }
380346
+ }
380347
+ if (pendingStopReason) {
380348
+ yield pendingStopReason;
380349
+ } else if (sawToolCall) {
380350
+ yield {
380351
+ message_type: "stop_reason",
380352
+ stop_reason: "requires_approval"
380353
+ };
380354
+ }
380355
+ } catch (error54) {
380356
+ yield* createProviderErrorChunks(error54);
380357
+ }
380358
+ }
380359
+ };
380360
+ }
380361
+
380362
+ class ProviderTurnExecutor {
380363
+ adapter;
380364
+ constructor(adapter = new MissingProviderStreamAdapter) {
380365
+ this.adapter = adapter;
380366
+ }
380367
+ async execute(input) {
380368
+ const providerInput = buildProviderTurnInput(input);
380369
+ const events = await this.adapter.stream(providerInput);
380370
+ return createProviderLettaStream(events, estimateProviderContextTokens(providerInput));
380371
+ }
380372
+ }
380373
+ var LOCAL_CONTEXT_COMPACTION_RESERVE_TOKENS = 16384, LOCAL_SMALL_CONTEXT_COMPACTION_RESERVE_RATIO = 0.2;
380374
+ var init_provider_turn_executor = __esm(() => {
380375
+ init_local_stream_chunks();
380376
+ init_local_provider_errors();
380377
+ });
380378
+
380361
380379
  // src/backend/dev/pi-image-elision.ts
380362
380380
  function localProviderRequestByteLimit() {
380363
380381
  const raw = process.env[LOCAL_PROVIDER_REQUEST_BYTE_LIMIT_ENV];
@@ -380743,7 +380761,7 @@ class PiStreamAdapter {
380743
380761
  localProviderAuthStorageDir;
380744
380762
  modelsRuntime;
380745
380763
  onContextWindowOverflow;
380746
- onContextUsage;
380764
+ onContextPressure;
380747
380765
  onLlmStart;
380748
380766
  onLlmEnd;
380749
380767
  constructor(options3 = {}) {
@@ -380754,7 +380772,7 @@ class PiStreamAdapter {
380754
380772
  this.abortSignal = options3.abortSignal;
380755
380773
  this.localProviderAuthStorageDir = options3.localProviderAuthStorageDir;
380756
380774
  this.onContextWindowOverflow = options3.onContextWindowOverflow;
380757
- this.onContextUsage = options3.onContextUsage;
380775
+ this.onContextPressure = options3.onContextPressure;
380758
380776
  this.onLlmStart = options3.onLlmStart;
380759
380777
  this.onLlmEnd = options3.onLlmEnd;
380760
380778
  }
@@ -380771,6 +380789,33 @@ class PiStreamAdapter {
380771
380789
  ...compaction.stats ? { compaction_stats: compaction.stats } : {}
380772
380790
  });
380773
380791
  }
380792
+ async compactBeforeProviderCall(input) {
380793
+ if (!this.onContextPressure)
380794
+ return null;
380795
+ const contextTokens = estimateProviderContextTokens(input);
380796
+ if (contextTokens === undefined)
380797
+ return null;
380798
+ const localModel = await resolveAvailableLocalModelForTurn({
380799
+ model: input.agent.model,
380800
+ modelSettings: input.agent.model_settings,
380801
+ storageDir: this.localProviderAuthStorageDir,
380802
+ modelsRuntime: this.modelsRuntime
380803
+ });
380804
+ const resolved = await resolvePiModelForAgent(localModel.model, localModel.modelSettings, {
380805
+ localProviderAuthStorageDir: this.localProviderAuthStorageDir,
380806
+ modelsRuntime: this.modelsRuntime
380807
+ });
380808
+ const contextWindow = resolved.model.contextWindow;
380809
+ if (!shouldCompactForContextPressure({ contextTokens, contextWindow })) {
380810
+ return null;
380811
+ }
380812
+ return this.onContextPressure(input, {
380813
+ contextTokens,
380814
+ contextWindow,
380815
+ phase: "preflight",
380816
+ source: "estimate"
380817
+ });
380818
+ }
380774
380819
  async* streamOnce(input) {
380775
380820
  const tools = toPiTools(input.clientTools);
380776
380821
  const localModel = await resolveAvailableLocalModelForTurn({
@@ -380839,6 +380884,7 @@ class PiStreamAdapter {
380839
380884
  const result = this.runStream(resolved.model, context3, options3);
380840
380885
  let streamError;
380841
380886
  let finalMessage;
380887
+ let finalLocalMessage;
380842
380888
  for await (const part of result) {
380843
380889
  if (part.type === "error") {
380844
380890
  const error54 = new PiProviderError(part.error);
@@ -380849,7 +380895,8 @@ class PiStreamAdapter {
380849
380895
  }
380850
380896
  if (part.type === "done") {
380851
380897
  finalMessage = part.message;
380852
- yield providerLocalMessage(toLocalAssistantMessage(part.message, input));
380898
+ finalLocalMessage = toLocalAssistantMessage(part.message, input);
380899
+ yield providerLocalMessage(finalLocalMessage);
380853
380900
  }
380854
380901
  yield providerStreamPart(part);
380855
380902
  }
@@ -380869,8 +380916,22 @@ class PiStreamAdapter {
380869
380916
  if (finalMessage.stopReason === "error" || finalMessage.stopReason === "aborted") {
380870
380917
  throw new PiProviderError(finalMessage);
380871
380918
  }
380872
- if (this.onContextUsage) {
380873
- const compaction = await this.onContextUsage(input, finalMessage.usage);
380919
+ if (this.onContextPressure) {
380920
+ const usageContextTokens = contextTokensFromUsage(finalMessage.usage);
380921
+ const contextTokens = usageContextTokens ?? estimateProviderContextTokens({
380922
+ ...input,
380923
+ uiMessages: [
380924
+ ...input.uiMessages,
380925
+ finalLocalMessage ?? toLocalAssistantMessage(finalMessage, input)
380926
+ ]
380927
+ });
380928
+ const contextWindow = resolved.model.contextWindow;
380929
+ const compaction = shouldCompactForContextPressure({ contextTokens, contextWindow }) && contextTokens !== undefined ? await this.onContextPressure(input, {
380930
+ contextTokens,
380931
+ contextWindow,
380932
+ phase: "post_turn",
380933
+ source: usageContextTokens === undefined ? "estimate" : "usage"
380934
+ }) : null;
380874
380935
  if (compaction) {
380875
380936
  yield* this.emitCompactionChunks(compaction, "context_window_limit");
380876
380937
  }
@@ -380891,9 +380952,19 @@ class PiStreamAdapter {
380891
380952
  }
380892
380953
  async* stream(input) {
380893
380954
  let activeInput = input;
380955
+ let preflightCompactionChecked = false;
380894
380956
  let contextOverflowCompactions = 0;
380895
380957
  let transientRetries = 0;
380896
380958
  while (true) {
380959
+ if (!preflightCompactionChecked) {
380960
+ preflightCompactionChecked = true;
380961
+ const compaction = await this.compactBeforeProviderCall(activeInput);
380962
+ if (compaction) {
380963
+ activeInput = { ...activeInput, uiMessages: compaction.uiMessages };
380964
+ yield* this.emitCompactionChunks(compaction, "context_window_limit");
380965
+ continue;
380966
+ }
380967
+ }
380897
380968
  let emittedModelOutput = false;
380898
380969
  try {
380899
380970
  for await (const event2 of this.streamOnce(activeInput)) {
@@ -380994,7 +381065,7 @@ var init_pi_stream_adapter = __esm(() => {
380994
381065
  });
380995
381066
 
380996
381067
  // src/backend/local/local-executor-factory.ts
380997
- function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow, onContextUsage, onLlmStart, onLlmEnd) {
381068
+ function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow, onContextPressure, onLlmStart, onLlmEnd) {
380998
381069
  if (options3.executor)
380999
381070
  return options3.executor;
381000
381071
  if (options3.executionMode === "deterministic") {
@@ -381005,7 +381076,7 @@ function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow, o
381005
381076
  localProviderAuthStorageDir: options3.storageDir,
381006
381077
  modelsRuntime,
381007
381078
  onContextWindowOverflow,
381008
- onContextUsage,
381079
+ onContextPressure,
381009
381080
  onLlmStart,
381010
381081
  onLlmEnd
381011
381082
  }));
@@ -381455,7 +381526,6 @@ var init_local_backend = __esm(() => {
381455
381526
  init_memory_git();
381456
381527
  init_headless_backend();
381457
381528
  init_pi_models_runtime();
381458
- init_provider_turn_executor();
381459
381529
  init_compaction();
381460
381530
  init_local_executor_factory();
381461
381531
  init_local_model_config();
@@ -381495,7 +381565,7 @@ var init_local_backend = __esm(() => {
381495
381565
  storedMessageIdPrefix: "letta-msg-",
381496
381566
  localMessageIdPrefix: "ui-msg-"
381497
381567
  };
381498
- super(options3.defaultAgentId ?? "agent-local-default", createLocalExecutor(options3, runtime, (input, error54) => localBackendRef.current?.compactAfterContextOverflow(input, error54) ?? Promise.resolve(null), (input, usage) => localBackendRef.current?.compactAfterContextUsage(input, usage) ?? Promise.resolve(null), (info) => localBackendRef.current?.emitLlmStart(info) ?? Promise.resolve(), (info) => localBackendRef.current?.emitLlmEnd(info) ?? Promise.resolve()), storeOptions, {
381568
+ super(options3.defaultAgentId ?? "agent-local-default", createLocalExecutor(options3, runtime, (input, error54) => localBackendRef.current?.compactAfterContextOverflow(input, error54) ?? Promise.resolve(null), (input, pressure) => localBackendRef.current?.compactForContextPressure(input, pressure) ?? Promise.resolve(null), (info) => localBackendRef.current?.emitLlmStart(info) ?? Promise.resolve(), (info) => localBackendRef.current?.emitLlmEnd(info) ?? Promise.resolve()), storeOptions, {
381499
381569
  modelHandle: modelConfig.handle,
381500
381570
  runIdPrefix: "local-run-",
381501
381571
  runMetadataBackend: "local"
@@ -381654,12 +381724,7 @@ var init_local_backend = __esm(() => {
381654
381724
  stats: result.stats
381655
381725
  };
381656
381726
  }
381657
- async compactAfterContextUsage(input, usage) {
381658
- const contextTokens = contextTokensFromUsage(usage) ?? estimateProviderContextTokens(input);
381659
- const contextWindow = this.effectiveContextWindow(input.conversationId, input.agentId);
381660
- if (contextTokens === undefined || contextWindow === undefined || contextTokens <= contextWindow) {
381661
- return null;
381662
- }
381727
+ async compactForContextPressure(input, _pressure) {
381663
381728
  const result = await this.compactLocalConversation(input.conversationId, input.agentId, "context_window_limit");
381664
381729
  return {
381665
381730
  uiMessages: this.store.listLocalMessages(input.conversationId, input.agentId),
@@ -470002,11 +470067,6 @@ async function startAppServer(options3 = {}) {
470002
470067
  });
470003
470068
  server2.on("upgrade", (request, socket, head2) => {
470004
470069
  const requestUrl = getRequestUrl(request, listen.host);
470005
- if (request.headers.origin) {
470006
- options3.onLog?.(`Rejecting app-server websocket request with Origin header: ${request.url ?? "/"}`);
470007
- rejectUpgrade(socket, 403, "Forbidden");
470008
- return;
470009
- }
470010
470070
  if (requestUrl.pathname !== listen.path && requestUrl.pathname !== "/") {
470011
470071
  rejectUpgrade(socket, 404, "Not Found");
470012
470072
  return;
@@ -470022,6 +470082,11 @@ async function startAppServer(options3 = {}) {
470022
470082
  rejectUpgrade(socket, authError.statusCode, authError.message);
470023
470083
  return;
470024
470084
  }
470085
+ if (request.headers.origin !== undefined && authPolicy.mode === undefined) {
470086
+ options3.onLog?.(`Rejecting unauthenticated app-server websocket request with Origin header: ${request.url ?? "/"}; native clients such as React Native must configure --ws-auth capability-token or --ws-auth signed-bearer-token`);
470087
+ rejectUpgrade(socket, 403, "Forbidden");
470088
+ return;
470089
+ }
470025
470090
  wss.handleUpgrade(request, socket, head2, (websocket) => {
470026
470091
  handleWebSocketConnection(websocket, channel);
470027
470092
  });
@@ -470130,7 +470195,7 @@ Run the local App Server using native v2 WebSocket frames.
470130
470195
  Options:
470131
470196
  --listen [url] WebSocket listen URL. Defaults to an available loopback port
470132
470197
  --openai-api Serve OpenAI-compatible /v1/models and /v1/chat/completions routes (each agent is a model)
470133
- --ws-auth <mode> WebSocket auth mode for non-loopback listeners. Supported: capability-token, signed-bearer-token
470198
+ --ws-auth <mode> WebSocket auth for non-loopback listeners and Origin-bearing native clients. Supported: capability-token, signed-bearer-token
470134
470199
  --ws-token-file <path> Absolute path to the capability-token file
470135
470200
  --ws-token-sha256 <hex> Hex-encoded SHA-256 digest of the capability token
470136
470201
  --ws-shared-secret-file <path> Absolute path to the shared secret file for signed JWT bearer tokens
@@ -470250,7 +470315,7 @@ Remote environment options:
470250
470315
  App Server options:
470251
470316
  --listen [url] Accept App Server connections. If URL is omitted, binds to an available loopback port
470252
470317
  --openai-api Serve OpenAI-compatible /v1/models and /v1/chat/completions routes (each agent is a model)
470253
- --ws-auth <mode> Authentication for non-loopback listeners: capability-token or signed-bearer-token
470318
+ --ws-auth <mode> Authentication for non-loopback listeners and Origin-bearing native clients: capability-token or signed-bearer-token
470254
470319
  --ws-token-file <path> Absolute path to the capability-token file
470255
470320
  --ws-token-sha256 <hex> Hex-encoded SHA-256 digest of the capability token
470256
470321
  --ws-shared-secret-file <path> Absolute path to the shared secret file for signed JWT bearer tokens
@@ -541232,4 +541297,4 @@ function registerBunOAuthFlows() {
541232
541297
  registerBunOAuthFlows();
541233
541298
  await init_src5().then(() => exports_src2);
541234
541299
 
541235
- //# debugId=CFB812BEB8775E6764756E2164756E21
541300
+ //# debugId=D4FE51D0A61DE3F364756E2164756E21