@letta-ai/letta-code 0.29.2 → 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/dist/app-server-client.cjs +531 -0
- package/dist/app-server-client.cjs.map +11 -0
- package/dist/app-server-client.js +45 -2
- package/dist/app-server-client.js.map +5 -4
- package/dist/types/app-server-client.d.ts +30 -2
- package/dist/types/app-server-client.d.ts.map +1 -1
- package/dist/types/types/app-server-info.d.ts +3 -1
- package/dist/types/types/app-server-info.d.ts.map +1 -1
- package/letta.js +653 -584
- package/package.json +6 -2
- package/scripts/source-file-size-baseline.json +1 -1
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.
|
|
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",
|
|
@@ -5480,6 +5480,8 @@ var init_package = __esm(() => {
|
|
|
5480
5480
|
"vendor",
|
|
5481
5481
|
"dist/app-server-client.js",
|
|
5482
5482
|
"dist/app-server-client.js.map",
|
|
5483
|
+
"dist/app-server-client.cjs",
|
|
5484
|
+
"dist/app-server-client.cjs.map",
|
|
5483
5485
|
"dist/agent-presets.js",
|
|
5484
5486
|
"dist/agent-presets.js.map",
|
|
5485
5487
|
"dist/channels-public.js",
|
|
@@ -5497,7 +5499,9 @@ var init_package = __esm(() => {
|
|
|
5497
5499
|
"./app-server-client": {
|
|
5498
5500
|
types: "./dist/types/app-server-client.d.ts",
|
|
5499
5501
|
browser: "./dist/app-server-client.js",
|
|
5500
|
-
import: "./dist/app-server-client.js"
|
|
5502
|
+
import: "./dist/app-server-client.js",
|
|
5503
|
+
require: "./dist/app-server-client.cjs",
|
|
5504
|
+
default: "./dist/app-server-client.js"
|
|
5501
5505
|
},
|
|
5502
5506
|
"./protocol": {
|
|
5503
5507
|
types: "./dist/types/types/protocol.d.ts"
|
|
@@ -375871,7 +375875,7 @@ class LocalStore {
|
|
|
375871
375875
|
const agentsDir = join42(this.storageDir, "agents");
|
|
375872
375876
|
if (existsSync36(agentsDir)) {
|
|
375873
375877
|
for (const file3 of readdirSync13(agentsDir)) {
|
|
375874
|
-
if (!file3.endsWith(".json"))
|
|
375878
|
+
if (!file3.endsWith(".json") || file3.startsWith("._"))
|
|
375875
375879
|
continue;
|
|
375876
375880
|
const raw = readJsonFile2(join42(agentsDir, file3));
|
|
375877
375881
|
const agent2 = normalizeAgentRecord(raw, this.defaultAgentModel);
|
|
@@ -378330,6 +378334,8 @@ function createLocalEndpointPiProvider(options3) {
|
|
|
378330
378334
|
}
|
|
378331
378335
|
}
|
|
378332
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);
|
|
378333
378339
|
return {
|
|
378334
378340
|
id: metadata.id,
|
|
378335
378341
|
name: metadata.id,
|
|
@@ -378339,8 +378345,8 @@ function createLocalEndpointPiProvider(options3) {
|
|
|
378339
378345
|
reasoning: metadata.thinking === true,
|
|
378340
378346
|
input: metadata.vision === true ? ["text", "image"] : ["text"],
|
|
378341
378347
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
378342
|
-
contextWindow
|
|
378343
|
-
maxTokens
|
|
378348
|
+
contextWindow,
|
|
378349
|
+
maxTokens,
|
|
378344
378350
|
compat: {
|
|
378345
378351
|
supportsDeveloperRole: false,
|
|
378346
378352
|
supportsReasoningEffort: false,
|
|
@@ -378512,7 +378518,9 @@ function parseLmStudioModels(data) {
|
|
|
378512
378518
|
if (record5.type === "embeddings")
|
|
378513
378519
|
continue;
|
|
378514
378520
|
const capabilities = stringArray(record5.capabilities);
|
|
378515
|
-
const
|
|
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;
|
|
378516
378524
|
models3.push({
|
|
378517
378525
|
id: record5.id,
|
|
378518
378526
|
vision: record5.type === "vlm" || capabilities.includes("vision"),
|
|
@@ -379020,6 +379028,296 @@ var init_pi_models_runtime = __esm(() => {
|
|
|
379020
379028
|
]);
|
|
379021
379029
|
});
|
|
379022
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
|
+
|
|
379023
379321
|
// src/backend/local/local-context-estimate.ts
|
|
379024
379322
|
function positiveUsageNumber(value) {
|
|
379025
379323
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
@@ -379143,561 +379441,6 @@ function estimateLocalContextTokens(messages) {
|
|
|
379143
379441
|
}
|
|
379144
379442
|
var IMAGE_TOKEN_ESTIMATE = 1200;
|
|
379145
379443
|
|
|
379146
|
-
// src/backend/dev/provider-turn-executor.ts
|
|
379147
|
-
var exports_provider_turn_executor = {};
|
|
379148
|
-
__export(exports_provider_turn_executor, {
|
|
379149
|
-
providerStreamPart: () => providerStreamPart,
|
|
379150
|
-
providerLocalMessage: () => providerLocalMessage,
|
|
379151
|
-
providerLettaChunk: () => providerLettaChunk,
|
|
379152
|
-
estimateProviderRequestBytes: () => estimateProviderRequestBytes,
|
|
379153
|
-
estimateProviderContextTokens: () => estimateProviderContextTokens,
|
|
379154
|
-
contextTokensFromUsage: () => contextTokensFromUsage,
|
|
379155
|
-
buildProviderTurnInput: () => buildProviderTurnInput,
|
|
379156
|
-
ProviderTurnExecutor: () => ProviderTurnExecutor
|
|
379157
|
-
});
|
|
379158
|
-
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
379159
|
-
function providerStreamPart(part) {
|
|
379160
|
-
return { type: "provider-part", part };
|
|
379161
|
-
}
|
|
379162
|
-
function providerLocalMessage(message) {
|
|
379163
|
-
return { type: "local-message", message };
|
|
379164
|
-
}
|
|
379165
|
-
function providerLettaChunk(chunk) {
|
|
379166
|
-
return { type: "letta-chunk", chunk };
|
|
379167
|
-
}
|
|
379168
|
-
|
|
379169
|
-
class MissingProviderStreamAdapter {
|
|
379170
|
-
async* stream() {
|
|
379171
|
-
yield {
|
|
379172
|
-
type: "error",
|
|
379173
|
-
error: new Error("Provider turn adapter is not configured for this dev backend")
|
|
379174
|
-
};
|
|
379175
|
-
}
|
|
379176
|
-
}
|
|
379177
|
-
function bodyListField(body, key) {
|
|
379178
|
-
const value = body[key];
|
|
379179
|
-
return Array.isArray(value) ? value : [];
|
|
379180
|
-
}
|
|
379181
|
-
function buildProviderTurnInput(input) {
|
|
379182
|
-
return {
|
|
379183
|
-
conversationId: input.conversationId,
|
|
379184
|
-
agentId: input.agentId,
|
|
379185
|
-
agent: input.agent,
|
|
379186
|
-
systemPrompt: input.systemPrompt,
|
|
379187
|
-
midConversationSystemPrompt: input.midConversationSystemPrompt,
|
|
379188
|
-
body: input.body,
|
|
379189
|
-
history: input.history,
|
|
379190
|
-
uiMessages: input.uiMessages,
|
|
379191
|
-
clientTools: bodyListField(input.body, "client_tools"),
|
|
379192
|
-
clientSkills: bodyListField(input.body, "client_skills")
|
|
379193
|
-
};
|
|
379194
|
-
}
|
|
379195
|
-
function stringifyToolInput(input) {
|
|
379196
|
-
if (typeof input === "string")
|
|
379197
|
-
return input;
|
|
379198
|
-
return JSON.stringify(input ?? {});
|
|
379199
|
-
}
|
|
379200
|
-
function createLocalMessageChunk(message) {
|
|
379201
|
-
return markLocalStateChunkOnly(attachLocalMessage({ message_type: "local_message" }, message));
|
|
379202
|
-
}
|
|
379203
|
-
function createProviderErrorChunks(error54) {
|
|
379204
|
-
const info = normalizeLocalProviderError(error54);
|
|
379205
|
-
return [
|
|
379206
|
-
{
|
|
379207
|
-
message_type: "error_message",
|
|
379208
|
-
message: info.message,
|
|
379209
|
-
detail: info.detail,
|
|
379210
|
-
error_type: info.error_type,
|
|
379211
|
-
retryable: info.retryable
|
|
379212
|
-
},
|
|
379213
|
-
{
|
|
379214
|
-
message_type: "stop_reason",
|
|
379215
|
-
stop_reason: info.stop_reason
|
|
379216
|
-
}
|
|
379217
|
-
];
|
|
379218
|
-
}
|
|
379219
|
-
function contextTokensFromUsage(usage) {
|
|
379220
|
-
return contextTokensFromLocalUsage(usage);
|
|
379221
|
-
}
|
|
379222
|
-
function estimateSerializedTokens(value) {
|
|
379223
|
-
if (value === undefined || value === null)
|
|
379224
|
-
return 0;
|
|
379225
|
-
try {
|
|
379226
|
-
const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
379227
|
-
return Math.ceil(serialized.length / 4);
|
|
379228
|
-
} catch {
|
|
379229
|
-
return 0;
|
|
379230
|
-
}
|
|
379231
|
-
}
|
|
379232
|
-
function estimateProviderContextTokens(input) {
|
|
379233
|
-
const contextEstimate = estimateLocalContextTokens(input.uiMessages);
|
|
379234
|
-
if (contextEstimate.lastUsageIndex !== null) {
|
|
379235
|
-
return contextEstimate.tokens > 0 ? contextEstimate.tokens : undefined;
|
|
379236
|
-
}
|
|
379237
|
-
const systemPromptTokens = estimateSerializedTokens(input.systemPrompt ?? input.agent.system);
|
|
379238
|
-
const messageTokens = contextEstimate.tokens;
|
|
379239
|
-
const toolTokens = estimateSerializedTokens(input.clientTools);
|
|
379240
|
-
const total = systemPromptTokens + messageTokens + toolTokens;
|
|
379241
|
-
return total > 0 ? total : undefined;
|
|
379242
|
-
}
|
|
379243
|
-
function serializedLength(value) {
|
|
379244
|
-
if (value === undefined || value === null)
|
|
379245
|
-
return 0;
|
|
379246
|
-
try {
|
|
379247
|
-
const serialized = typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
379248
|
-
return serialized.length;
|
|
379249
|
-
} catch {
|
|
379250
|
-
return 0;
|
|
379251
|
-
}
|
|
379252
|
-
}
|
|
379253
|
-
function estimateProviderRequestBytes(input) {
|
|
379254
|
-
const systemPromptBytes = serializedLength(input.systemPrompt ?? input.agent.system);
|
|
379255
|
-
const messageBytes = serializedLength(input.uiMessages);
|
|
379256
|
-
const toolBytes = serializedLength(input.clientTools);
|
|
379257
|
-
const total = systemPromptBytes + messageBytes + toolBytes;
|
|
379258
|
-
return total > 0 ? total : undefined;
|
|
379259
|
-
}
|
|
379260
|
-
function createUsageStatisticsChunk(usage, contextTokensEstimate) {
|
|
379261
|
-
const promptTokens = usage?.input;
|
|
379262
|
-
const completionTokens = usage?.output;
|
|
379263
|
-
const totalTokens = usage?.totalTokens;
|
|
379264
|
-
const usageContextTokens = usage ? contextTokensFromUsage(usage) : undefined;
|
|
379265
|
-
const contextTokens = usageContextTokens ?? contextTokensEstimate;
|
|
379266
|
-
const cachedInputTokens = usage?.cacheRead;
|
|
379267
|
-
const cacheWriteTokens = usage?.cacheWrite;
|
|
379268
|
-
if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined && cachedInputTokens === undefined && cacheWriteTokens === undefined && contextTokens === undefined) {
|
|
379269
|
-
return;
|
|
379270
|
-
}
|
|
379271
|
-
return {
|
|
379272
|
-
message_type: "usage_statistics",
|
|
379273
|
-
...promptTokens !== undefined ? { prompt_tokens: promptTokens } : {},
|
|
379274
|
-
...completionTokens !== undefined ? { completion_tokens: completionTokens } : {},
|
|
379275
|
-
...totalTokens !== undefined ? { total_tokens: totalTokens } : {},
|
|
379276
|
-
...cachedInputTokens !== undefined ? { cached_input_tokens: cachedInputTokens } : {},
|
|
379277
|
-
...cacheWriteTokens !== undefined ? { cache_write_tokens: cacheWriteTokens } : {},
|
|
379278
|
-
...contextTokens !== undefined ? { context_tokens: contextTokens } : {}
|
|
379279
|
-
};
|
|
379280
|
-
}
|
|
379281
|
-
function errorFromAssistantEvent(part) {
|
|
379282
|
-
if (part.type !== "error")
|
|
379283
|
-
return new Error("Unknown provider stream error");
|
|
379284
|
-
return new Error(part.error.errorMessage ?? "Unknown local provider error");
|
|
379285
|
-
}
|
|
379286
|
-
function contentMatchesMessageType(content, messageType) {
|
|
379287
|
-
if (!content || typeof content !== "object" || !("type" in content)) {
|
|
379288
|
-
return false;
|
|
379289
|
-
}
|
|
379290
|
-
return messageType === "assistant_message" ? content.type === "text" : content.type === "thinking";
|
|
379291
|
-
}
|
|
379292
|
-
function contiguousContentStartIndex(partial4, contentIndex, messageType) {
|
|
379293
|
-
let startIndex = contentIndex;
|
|
379294
|
-
while (startIndex > 0 && contentMatchesMessageType(partial4.content[startIndex - 1], messageType)) {
|
|
379295
|
-
startIndex -= 1;
|
|
379296
|
-
}
|
|
379297
|
-
return startIndex;
|
|
379298
|
-
}
|
|
379299
|
-
function otidForContentSegment(otids, prefix, contentIndex, partial4, messageType) {
|
|
379300
|
-
const segmentStartIndex = contiguousContentStartIndex(partial4, contentIndex, messageType);
|
|
379301
|
-
const existing = otids.get(segmentStartIndex);
|
|
379302
|
-
if (existing)
|
|
379303
|
-
return existing;
|
|
379304
|
-
const otid = `${prefix}-${segmentStartIndex}-${randomUUID21()}`;
|
|
379305
|
-
otids.set(segmentStartIndex, otid);
|
|
379306
|
-
return otid;
|
|
379307
|
-
}
|
|
379308
|
-
function createProviderLettaStream(events, contextTokensEstimate) {
|
|
379309
|
-
const controller = new AbortController;
|
|
379310
|
-
return {
|
|
379311
|
-
controller,
|
|
379312
|
-
async* [Symbol.asyncIterator]() {
|
|
379313
|
-
let sawToolCall = false;
|
|
379314
|
-
let pendingStopReason;
|
|
379315
|
-
let sawUsageStatistics = false;
|
|
379316
|
-
const assistantOtids = new Map;
|
|
379317
|
-
const reasoningOtids = new Map;
|
|
379318
|
-
try {
|
|
379319
|
-
for await (const event2 of events) {
|
|
379320
|
-
if (event2.type === "error") {
|
|
379321
|
-
yield* createProviderErrorChunks(event2.error);
|
|
379322
|
-
return;
|
|
379323
|
-
}
|
|
379324
|
-
if (event2.type === "local-message") {
|
|
379325
|
-
yield createLocalMessageChunk(event2.message);
|
|
379326
|
-
continue;
|
|
379327
|
-
}
|
|
379328
|
-
if (event2.type === "letta-chunk") {
|
|
379329
|
-
yield event2.chunk;
|
|
379330
|
-
continue;
|
|
379331
|
-
}
|
|
379332
|
-
const { part } = event2;
|
|
379333
|
-
if (part.type === "text_delta") {
|
|
379334
|
-
yield {
|
|
379335
|
-
message_type: "assistant_message",
|
|
379336
|
-
otid: otidForContentSegment(assistantOtids, "provider-assistant", part.contentIndex, part.partial, "assistant_message"),
|
|
379337
|
-
content: [{ type: "text", text: part.delta }]
|
|
379338
|
-
};
|
|
379339
|
-
continue;
|
|
379340
|
-
}
|
|
379341
|
-
if (part.type === "thinking_delta") {
|
|
379342
|
-
yield {
|
|
379343
|
-
message_type: "reasoning_message",
|
|
379344
|
-
otid: otidForContentSegment(reasoningOtids, "provider-reasoning", part.contentIndex, part.partial, "reasoning_message"),
|
|
379345
|
-
reasoning: part.delta
|
|
379346
|
-
};
|
|
379347
|
-
continue;
|
|
379348
|
-
}
|
|
379349
|
-
if (part.type === "toolcall_end") {
|
|
379350
|
-
sawToolCall = true;
|
|
379351
|
-
yield {
|
|
379352
|
-
message_type: "approval_request_message",
|
|
379353
|
-
tool_call: {
|
|
379354
|
-
tool_call_id: part.toolCall.id,
|
|
379355
|
-
name: part.toolCall.name,
|
|
379356
|
-
arguments: stringifyToolInput(part.toolCall.arguments)
|
|
379357
|
-
}
|
|
379358
|
-
};
|
|
379359
|
-
continue;
|
|
379360
|
-
}
|
|
379361
|
-
if (part.type === "done") {
|
|
379362
|
-
if (!sawUsageStatistics) {
|
|
379363
|
-
const usageChunk = createUsageStatisticsChunk(part.message.usage, contextTokensEstimate);
|
|
379364
|
-
if (usageChunk) {
|
|
379365
|
-
sawUsageStatistics = true;
|
|
379366
|
-
yield usageChunk;
|
|
379367
|
-
}
|
|
379368
|
-
}
|
|
379369
|
-
pendingStopReason = {
|
|
379370
|
-
message_type: "stop_reason",
|
|
379371
|
-
stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : part.reason === "length" ? "max_tokens_exceeded" : "end_turn"
|
|
379372
|
-
};
|
|
379373
|
-
continue;
|
|
379374
|
-
}
|
|
379375
|
-
if (part.type === "error") {
|
|
379376
|
-
yield* createProviderErrorChunks(errorFromAssistantEvent(part));
|
|
379377
|
-
return;
|
|
379378
|
-
}
|
|
379379
|
-
}
|
|
379380
|
-
if (pendingStopReason) {
|
|
379381
|
-
yield pendingStopReason;
|
|
379382
|
-
} else if (sawToolCall) {
|
|
379383
|
-
yield {
|
|
379384
|
-
message_type: "stop_reason",
|
|
379385
|
-
stop_reason: "requires_approval"
|
|
379386
|
-
};
|
|
379387
|
-
}
|
|
379388
|
-
} catch (error54) {
|
|
379389
|
-
yield* createProviderErrorChunks(error54);
|
|
379390
|
-
}
|
|
379391
|
-
}
|
|
379392
|
-
};
|
|
379393
|
-
}
|
|
379394
|
-
|
|
379395
|
-
class ProviderTurnExecutor {
|
|
379396
|
-
adapter;
|
|
379397
|
-
constructor(adapter = new MissingProviderStreamAdapter) {
|
|
379398
|
-
this.adapter = adapter;
|
|
379399
|
-
}
|
|
379400
|
-
async execute(input) {
|
|
379401
|
-
const providerInput = buildProviderTurnInput(input);
|
|
379402
|
-
const events = await this.adapter.stream(providerInput);
|
|
379403
|
-
return createProviderLettaStream(events, estimateProviderContextTokens(providerInput));
|
|
379404
|
-
}
|
|
379405
|
-
}
|
|
379406
|
-
var init_provider_turn_executor = __esm(() => {
|
|
379407
|
-
init_local_stream_chunks();
|
|
379408
|
-
init_local_provider_errors();
|
|
379409
|
-
});
|
|
379410
|
-
|
|
379411
|
-
// src/backend/dev/pi-model-factory.ts
|
|
379412
|
-
function isUnselectedLocalModelHandle(model) {
|
|
379413
|
-
return typeof model !== "string" || model.length === 0 || model === "auto" || model === UNSELECTED_LOCAL_MODEL_HANDLE || model.startsWith("letta/");
|
|
379414
|
-
}
|
|
379415
|
-
function normalizeOpenAICompatibleLocalModelHandle(model) {
|
|
379416
|
-
if (!model?.startsWith("openai/"))
|
|
379417
|
-
return model;
|
|
379418
|
-
const nestedHandle = model.slice("openai/".length);
|
|
379419
|
-
const nestedProvider = resolveProviderFromModelHandle(nestedHandle);
|
|
379420
|
-
if (!nestedProvider)
|
|
379421
|
-
return model;
|
|
379422
|
-
return getPiProviderSpec(nestedProvider).localModelDiscovery === "openai-compatible" ? nestedHandle : model;
|
|
379423
|
-
}
|
|
379424
|
-
function settingString(value) {
|
|
379425
|
-
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
379426
|
-
}
|
|
379427
|
-
function thinkingLevelSetting(value, preserveMax) {
|
|
379428
|
-
const effort = settingString(value);
|
|
379429
|
-
if (effort === "max")
|
|
379430
|
-
return preserveMax ? "max" : "xhigh";
|
|
379431
|
-
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" ? effort : undefined;
|
|
379432
|
-
}
|
|
379433
|
-
function reasoningForSettings(modelSettings, modelHandle) {
|
|
379434
|
-
const thinking = isRecord(modelSettings.thinking) ? modelSettings.thinking : undefined;
|
|
379435
|
-
if (thinking?.type === "disabled")
|
|
379436
|
-
return;
|
|
379437
|
-
const nestedReasoning = isRecord(modelSettings.reasoning) ? modelSettings.reasoning : undefined;
|
|
379438
|
-
const modelId = modelHandle?.slice(modelHandle.indexOf("/") + 1);
|
|
379439
|
-
const preserveMax = modelId?.startsWith("gpt-5.6") === true;
|
|
379440
|
-
return thinkingLevelSetting(nestedReasoning?.reasoning_effort, preserveMax) ?? thinkingLevelSetting(modelSettings.effort, preserveMax) ?? thinkingLevelSetting(modelSettings.reasoning_effort, preserveMax);
|
|
379441
|
-
}
|
|
379442
|
-
function applyPiEnvOverrides(overrides) {
|
|
379443
|
-
if (!overrides)
|
|
379444
|
-
return () => {};
|
|
379445
|
-
const previous = new Map;
|
|
379446
|
-
for (const [key, value] of Object.entries(overrides)) {
|
|
379447
|
-
previous.set(key, process.env[key]);
|
|
379448
|
-
if (value === undefined) {
|
|
379449
|
-
delete process.env[key];
|
|
379450
|
-
} else {
|
|
379451
|
-
process.env[key] = value;
|
|
379452
|
-
}
|
|
379453
|
-
}
|
|
379454
|
-
return () => {
|
|
379455
|
-
for (const [key, value] of previous) {
|
|
379456
|
-
if (value === undefined) {
|
|
379457
|
-
delete process.env[key];
|
|
379458
|
-
} else {
|
|
379459
|
-
process.env[key] = value;
|
|
379460
|
-
}
|
|
379461
|
-
}
|
|
379462
|
-
};
|
|
379463
|
-
}
|
|
379464
|
-
function hasEnvValue2(value) {
|
|
379465
|
-
return typeof value === "string" && value.length > 0;
|
|
379466
|
-
}
|
|
379467
|
-
function inferDefaultProviderFromStandardKeys() {
|
|
379468
|
-
const hasOpenAIKey = hasEnvValue2(process.env.OPENAI_API_KEY);
|
|
379469
|
-
const hasAnthropicKey = hasEnvValue2(process.env.ANTHROPIC_API_KEY);
|
|
379470
|
-
if (!hasOpenAIKey && hasAnthropicKey)
|
|
379471
|
-
return "anthropic";
|
|
379472
|
-
return DEFAULT_PI_PROVIDER;
|
|
379473
|
-
}
|
|
379474
|
-
function resolvePiProvider(provider = process.env.LETTA_CODE_DEV_PI_PROVIDER ?? inferDefaultProviderFromStandardKeys()) {
|
|
379475
|
-
if (isPiProvider(provider))
|
|
379476
|
-
return provider;
|
|
379477
|
-
if (getRegisteredPiProvider(provider))
|
|
379478
|
-
return provider;
|
|
379479
|
-
throw new Error(`Unknown pi provider "${provider}". Expected ${expectedPiProviderList()}.`);
|
|
379480
|
-
}
|
|
379481
|
-
function resolvePiProviderFromAgent(model, modelSettings = {}) {
|
|
379482
|
-
const registeredProvider = resolveRegisteredPiProviderFromModelHandle(model);
|
|
379483
|
-
if (registeredProvider)
|
|
379484
|
-
return registeredProvider;
|
|
379485
|
-
const handleProvider = resolveProviderFromModelHandle(model);
|
|
379486
|
-
if (handleProvider)
|
|
379487
|
-
return handleProvider;
|
|
379488
|
-
const settingsProvider = resolveProviderFromProviderType(modelSettings.provider_type);
|
|
379489
|
-
if (settingsProvider)
|
|
379490
|
-
return settingsProvider;
|
|
379491
|
-
if (model && !isUnselectedLocalModelHandle(model)) {
|
|
379492
|
-
const slashIndex = model.indexOf("/");
|
|
379493
|
-
if (slashIndex > 0) {
|
|
379494
|
-
throw new Error(`Model provider "${model.slice(0, slashIndex)}" is not registered. Load or repair the provider mod, or choose another model with /model.`);
|
|
379495
|
-
}
|
|
379496
|
-
}
|
|
379497
|
-
return resolvePiProvider();
|
|
379498
|
-
}
|
|
379499
|
-
function resolvePiModelFromAgent(model, provider) {
|
|
379500
|
-
return stripProviderHandlePrefix(model, provider);
|
|
379501
|
-
}
|
|
379502
|
-
function localProviderRecord(providerNames, storageDir) {
|
|
379503
|
-
for (const providerName of providerNames) {
|
|
379504
|
-
const record5 = getLocalProviderRecordByName(providerName, storageDir);
|
|
379505
|
-
if (record5)
|
|
379506
|
-
return record5;
|
|
379507
|
-
}
|
|
379508
|
-
return null;
|
|
379509
|
-
}
|
|
379510
|
-
function localProviderConnection(providerNames, storageDir) {
|
|
379511
|
-
const record5 = localProviderRecord(providerNames, storageDir);
|
|
379512
|
-
return {
|
|
379513
|
-
baseURL: record5?.base_url,
|
|
379514
|
-
timeout: resolveLocalProviderTimeout({
|
|
379515
|
-
configuredTimeout: record5?.timeout,
|
|
379516
|
-
providerIds: providerNames
|
|
379517
|
-
}),
|
|
379518
|
-
...record5 ? { record: record5 } : {}
|
|
379519
|
-
};
|
|
379520
|
-
}
|
|
379521
|
-
function resolveZaiConnection(options3) {
|
|
379522
|
-
const regularRecord = localProviderRecord(["zai", LOCAL_ZAI_PROVIDER_NAME], options3.storageDir);
|
|
379523
|
-
const codingRecord = localProviderRecord(["zai_coding", LOCAL_ZAI_CODING_PROVIDER_NAME], options3.storageDir);
|
|
379524
|
-
const regularKey = localProviderApiKeyFromRecord(regularRecord) ?? process.env.ZAI_API_KEY ?? process.env.ZHIPU_API_KEY;
|
|
379525
|
-
const codingKey = localProviderApiKeyFromRecord(codingRecord) ?? process.env.ZAI_CODING_API_KEY;
|
|
379526
|
-
const regularConnection = {
|
|
379527
|
-
providerName: "zai",
|
|
379528
|
-
baseURL: regularRecord?.base_url ?? process.env.ZAI_BASE_URL ?? "https://api.z.ai/api/paas/v4",
|
|
379529
|
-
apiKey: regularKey,
|
|
379530
|
-
timeout: resolveLocalProviderTimeout({
|
|
379531
|
-
configuredTimeout: regularRecord?.timeout,
|
|
379532
|
-
providerIds: [LOCAL_ZAI_PROVIDER_NAME, "zai"]
|
|
379533
|
-
})
|
|
379534
|
-
};
|
|
379535
|
-
const codingConnection = {
|
|
379536
|
-
providerName: "zai-coding",
|
|
379537
|
-
baseURL: codingRecord?.base_url ?? process.env.ZAI_CODING_BASE_URL ?? "https://api.z.ai/api/coding/paas/v4",
|
|
379538
|
-
apiKey: codingKey,
|
|
379539
|
-
timeout: resolveLocalProviderTimeout({
|
|
379540
|
-
configuredTimeout: codingRecord?.timeout,
|
|
379541
|
-
providerIds: [LOCAL_ZAI_CODING_PROVIDER_NAME, "zai-coding"]
|
|
379542
|
-
})
|
|
379543
|
-
};
|
|
379544
|
-
if (options3.preferredProviderType === "zai_coding" && codingKey) {
|
|
379545
|
-
return codingConnection;
|
|
379546
|
-
}
|
|
379547
|
-
if (options3.preferredProviderType === "zai" && regularKey) {
|
|
379548
|
-
return regularConnection;
|
|
379549
|
-
}
|
|
379550
|
-
if (codingKey)
|
|
379551
|
-
return codingConnection;
|
|
379552
|
-
if (regularKey)
|
|
379553
|
-
return regularConnection;
|
|
379554
|
-
return codingConnection;
|
|
379555
|
-
}
|
|
379556
|
-
function fallbackCatalogModelId(provider, modelId) {
|
|
379557
|
-
if (provider !== "openai")
|
|
379558
|
-
return;
|
|
379559
|
-
const withoutReleaseDate = modelId.replace(/-\d{4}-\d{2}-\d{2}$/, "");
|
|
379560
|
-
return withoutReleaseDate === modelId ? undefined : withoutReleaseDate;
|
|
379561
|
-
}
|
|
379562
|
-
function withOverrides(model, overrides) {
|
|
379563
|
-
return {
|
|
379564
|
-
...model,
|
|
379565
|
-
...overrides.baseURL ? { baseUrl: overrides.baseURL } : {},
|
|
379566
|
-
...overrides.headers ? { headers: { ...model.headers, ...overrides.headers } } : {},
|
|
379567
|
-
...overrides.contextWindow ? { contextWindow: overrides.contextWindow } : {},
|
|
379568
|
-
...overrides.maxTokens ? { maxTokens: overrides.maxTokens } : {}
|
|
379569
|
-
};
|
|
379570
|
-
}
|
|
379571
|
-
function nonNullHeaders(headers) {
|
|
379572
|
-
return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null));
|
|
379573
|
-
}
|
|
379574
|
-
function mergeHeaders3(...headers) {
|
|
379575
|
-
const merged = {};
|
|
379576
|
-
for (const header of headers) {
|
|
379577
|
-
if (!header)
|
|
379578
|
-
continue;
|
|
379579
|
-
Object.assign(merged, header);
|
|
379580
|
-
}
|
|
379581
|
-
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
379582
|
-
}
|
|
379583
|
-
function numericSetting(value) {
|
|
379584
|
-
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
379585
|
-
}
|
|
379586
|
-
function bedrockLocalProviderOptions(record5) {
|
|
379587
|
-
if (!record5)
|
|
379588
|
-
return {};
|
|
379589
|
-
const providerOptions = {};
|
|
379590
|
-
const envOverrides = {};
|
|
379591
|
-
if (record5.region) {
|
|
379592
|
-
providerOptions.region = record5.region;
|
|
379593
|
-
envOverrides.AWS_REGION = record5.region;
|
|
379594
|
-
envOverrides.AWS_DEFAULT_REGION = record5.region;
|
|
379595
|
-
}
|
|
379596
|
-
if (record5.profile) {
|
|
379597
|
-
providerOptions.profile = record5.profile;
|
|
379598
|
-
envOverrides.AWS_PROFILE = record5.profile;
|
|
379599
|
-
}
|
|
379600
|
-
if (record5.auth.type === "api" && record5.auth.key) {
|
|
379601
|
-
if (record5.access_key) {
|
|
379602
|
-
envOverrides.AWS_ACCESS_KEY_ID = record5.access_key;
|
|
379603
|
-
envOverrides.AWS_SECRET_ACCESS_KEY = record5.auth.key;
|
|
379604
|
-
} else {
|
|
379605
|
-
providerOptions.bearerToken = record5.auth.key;
|
|
379606
|
-
envOverrides.AWS_BEARER_TOKEN_BEDROCK = record5.auth.key;
|
|
379607
|
-
}
|
|
379608
|
-
}
|
|
379609
|
-
return {
|
|
379610
|
-
...Object.keys(providerOptions).length > 0 ? { providerOptions } : {},
|
|
379611
|
-
...Object.keys(envOverrides).length > 0 ? { envOverrides } : {}
|
|
379612
|
-
};
|
|
379613
|
-
}
|
|
379614
|
-
async function resolvePiModelForAgent(modelHandle, modelSettings = {}, options3 = {}) {
|
|
379615
|
-
const concreteModelHandle = normalizeOpenAICompatibleLocalModelHandle(isUnselectedLocalModelHandle(modelHandle) ? undefined : modelHandle);
|
|
379616
|
-
const provider = options3.provider ? resolvePiProvider(options3.provider) : resolvePiProviderFromAgent(concreteModelHandle, modelSettings);
|
|
379617
|
-
const registeredProvider = getRegisteredPiProvider(provider);
|
|
379618
|
-
const spec = isPiProvider(provider) ? getPiProviderSpec(provider) : undefined;
|
|
379619
|
-
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 ?? "";
|
|
379620
|
-
const storageDir = options3.localProviderAuthStorageDir;
|
|
379621
|
-
const modelsRuntime = options3.modelsRuntime ?? new LocalPiModelsRuntime({
|
|
379622
|
-
...storageDir ? { storageDir } : {}
|
|
379623
|
-
});
|
|
379624
|
-
const preferredProviderType = typeof modelSettings.provider_type === "string" ? modelSettings.provider_type : options3.preferredProviderType;
|
|
379625
|
-
const localNames = registeredProvider ? localNamesForProviderId(provider) : spec?.localProviderNames ?? [provider];
|
|
379626
|
-
let connection = localProviderConnection(localNames, storageDir);
|
|
379627
|
-
let baseURL = connection.baseURL ?? spec?.baseUrlEnv?.() ?? spec?.defaultBaseURL ?? registeredProvider?.config.baseUrl;
|
|
379628
|
-
let headers = mergeHeaders3(spec?.headers?.());
|
|
379629
|
-
let providerOptions;
|
|
379630
|
-
let envOverrides;
|
|
379631
|
-
let oauthCredentials;
|
|
379632
|
-
if (!modelId) {
|
|
379633
|
-
throw new Error(`No model selected for provider "${provider}". Choose an available model with /model.`);
|
|
379634
|
-
}
|
|
379635
|
-
const runtimeProviderId = registeredProvider ? provider : spec && modelsRuntime.isRuntimeManagedProvider(spec.id) ? spec.id : spec?.piProvider;
|
|
379636
|
-
if (!runtimeProviderId) {
|
|
379637
|
-
throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Register the provider with models before using it.");
|
|
379638
|
-
}
|
|
379639
|
-
const fallbackModelId = !registeredProvider && spec?.piProvider ? fallbackCatalogModelId(spec.piProvider, modelId) : undefined;
|
|
379640
|
-
const { model: publishedModel, auth: authResult } = await modelsRuntime.resolveTurn(runtimeProviderId, modelId, fallbackModelId);
|
|
379641
|
-
connection = { ...connection, apiKey: authResult?.auth.apiKey };
|
|
379642
|
-
if (authResult?.auth.baseUrl)
|
|
379643
|
-
baseURL = authResult.auth.baseUrl;
|
|
379644
|
-
if (authResult?.auth.headers) {
|
|
379645
|
-
headers = mergeHeaders3(headers, nonNullHeaders(authResult.auth.headers));
|
|
379646
|
-
}
|
|
379647
|
-
if (connection.record?.auth.type === "oauth") {
|
|
379648
|
-
const stored = await modelsRuntime.getStoredCredential(runtimeProviderId);
|
|
379649
|
-
oauthCredentials = stored?.type === "oauth" ? stored : undefined;
|
|
379650
|
-
}
|
|
379651
|
-
if (provider === "zai") {
|
|
379652
|
-
const zai = resolveZaiConnection({
|
|
379653
|
-
storageDir,
|
|
379654
|
-
preferredProviderType: preferredProviderType === "zai" || preferredProviderType === "zai_coding" ? preferredProviderType : undefined
|
|
379655
|
-
});
|
|
379656
|
-
connection = {
|
|
379657
|
-
apiKey: zai.apiKey,
|
|
379658
|
-
baseURL: zai.baseURL,
|
|
379659
|
-
timeout: zai.timeout
|
|
379660
|
-
};
|
|
379661
|
-
baseURL = zai.baseURL;
|
|
379662
|
-
}
|
|
379663
|
-
if (provider === "amazon-bedrock") {
|
|
379664
|
-
const bedrock = bedrockLocalProviderOptions(connection.record);
|
|
379665
|
-
providerOptions = bedrock.providerOptions;
|
|
379666
|
-
envOverrides = bedrock.envOverrides;
|
|
379667
|
-
}
|
|
379668
|
-
if (!publishedModel) {
|
|
379669
|
-
throw new Error(`Unknown model "${modelId}" for provider "${provider}". ` + "Choose an available model with /model.");
|
|
379670
|
-
}
|
|
379671
|
-
const hookedModel = oauthCredentials && registeredProvider?.config.oauth?.modifyModels ? registeredProvider.config.oauth.modifyModels([structuredClone(publishedModel)], oauthCredentials)[0] ?? publishedModel : publishedModel;
|
|
379672
|
-
const contextWindow = numericSetting(modelSettings.context_window_limit);
|
|
379673
|
-
const maxTokens = numericSetting(modelSettings.max_tokens);
|
|
379674
|
-
const allowBaseUrlOverride = !registeredProvider && spec !== undefined && !modelsRuntime.isRuntimeManagedProvider(spec.id);
|
|
379675
|
-
const overrides = {
|
|
379676
|
-
...allowBaseUrlOverride && baseURL && baseURL !== hookedModel.baseUrl ? { baseURL } : {},
|
|
379677
|
-
...contextWindow && contextWindow !== hookedModel.contextWindow ? { contextWindow } : {},
|
|
379678
|
-
...maxTokens && maxTokens !== hookedModel.maxTokens ? { maxTokens } : {}
|
|
379679
|
-
};
|
|
379680
|
-
const model = Object.keys(overrides).length > 0 ? withOverrides(hookedModel, overrides) : hookedModel;
|
|
379681
|
-
return {
|
|
379682
|
-
provider,
|
|
379683
|
-
model,
|
|
379684
|
-
apiKey: connection.apiKey,
|
|
379685
|
-
timeout: connection.timeout,
|
|
379686
|
-
headers,
|
|
379687
|
-
providerOptions,
|
|
379688
|
-
envOverrides
|
|
379689
|
-
};
|
|
379690
|
-
}
|
|
379691
|
-
var DEFAULT_PI_PROVIDER = "openai", UNSELECTED_LOCAL_MODEL_HANDLE = "local/default";
|
|
379692
|
-
var init_pi_model_factory = __esm(() => {
|
|
379693
|
-
init_local_pi_credential_store();
|
|
379694
|
-
init_local_provider_auth_store();
|
|
379695
|
-
init_local_provider_timeout();
|
|
379696
|
-
init_pi_models_runtime();
|
|
379697
|
-
init_pi_provider_mod_registry();
|
|
379698
|
-
init_pi_provider_registry();
|
|
379699
|
-
});
|
|
379700
|
-
|
|
379701
379444
|
// src/backend/local/local-model-config.ts
|
|
379702
379445
|
function localProviderNamesFromRecords(records) {
|
|
379703
379446
|
return new Set(records.map((record5) => record5.name));
|
|
@@ -380354,6 +380097,285 @@ Write in first person as a factual record of what occurred. Be thorough and deta
|
|
|
380354
380097
|
Keep your summary under ${SLIDING_WORD_LIMIT} words. Only output the summary.`;
|
|
380355
380098
|
});
|
|
380356
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
|
+
|
|
380357
380379
|
// src/backend/dev/pi-image-elision.ts
|
|
380358
380380
|
function localProviderRequestByteLimit() {
|
|
380359
380381
|
const raw = process.env[LOCAL_PROVIDER_REQUEST_BYTE_LIMIT_ENV];
|
|
@@ -380739,7 +380761,7 @@ class PiStreamAdapter {
|
|
|
380739
380761
|
localProviderAuthStorageDir;
|
|
380740
380762
|
modelsRuntime;
|
|
380741
380763
|
onContextWindowOverflow;
|
|
380742
|
-
|
|
380764
|
+
onContextPressure;
|
|
380743
380765
|
onLlmStart;
|
|
380744
380766
|
onLlmEnd;
|
|
380745
380767
|
constructor(options3 = {}) {
|
|
@@ -380750,7 +380772,7 @@ class PiStreamAdapter {
|
|
|
380750
380772
|
this.abortSignal = options3.abortSignal;
|
|
380751
380773
|
this.localProviderAuthStorageDir = options3.localProviderAuthStorageDir;
|
|
380752
380774
|
this.onContextWindowOverflow = options3.onContextWindowOverflow;
|
|
380753
|
-
this.
|
|
380775
|
+
this.onContextPressure = options3.onContextPressure;
|
|
380754
380776
|
this.onLlmStart = options3.onLlmStart;
|
|
380755
380777
|
this.onLlmEnd = options3.onLlmEnd;
|
|
380756
380778
|
}
|
|
@@ -380767,6 +380789,33 @@ class PiStreamAdapter {
|
|
|
380767
380789
|
...compaction.stats ? { compaction_stats: compaction.stats } : {}
|
|
380768
380790
|
});
|
|
380769
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
|
+
}
|
|
380770
380819
|
async* streamOnce(input) {
|
|
380771
380820
|
const tools = toPiTools(input.clientTools);
|
|
380772
380821
|
const localModel = await resolveAvailableLocalModelForTurn({
|
|
@@ -380835,6 +380884,7 @@ class PiStreamAdapter {
|
|
|
380835
380884
|
const result = this.runStream(resolved.model, context3, options3);
|
|
380836
380885
|
let streamError;
|
|
380837
380886
|
let finalMessage;
|
|
380887
|
+
let finalLocalMessage;
|
|
380838
380888
|
for await (const part of result) {
|
|
380839
380889
|
if (part.type === "error") {
|
|
380840
380890
|
const error54 = new PiProviderError(part.error);
|
|
@@ -380845,7 +380895,8 @@ class PiStreamAdapter {
|
|
|
380845
380895
|
}
|
|
380846
380896
|
if (part.type === "done") {
|
|
380847
380897
|
finalMessage = part.message;
|
|
380848
|
-
|
|
380898
|
+
finalLocalMessage = toLocalAssistantMessage(part.message, input);
|
|
380899
|
+
yield providerLocalMessage(finalLocalMessage);
|
|
380849
380900
|
}
|
|
380850
380901
|
yield providerStreamPart(part);
|
|
380851
380902
|
}
|
|
@@ -380865,8 +380916,22 @@ class PiStreamAdapter {
|
|
|
380865
380916
|
if (finalMessage.stopReason === "error" || finalMessage.stopReason === "aborted") {
|
|
380866
380917
|
throw new PiProviderError(finalMessage);
|
|
380867
380918
|
}
|
|
380868
|
-
if (this.
|
|
380869
|
-
const
|
|
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;
|
|
380870
380935
|
if (compaction) {
|
|
380871
380936
|
yield* this.emitCompactionChunks(compaction, "context_window_limit");
|
|
380872
380937
|
}
|
|
@@ -380887,9 +380952,19 @@ class PiStreamAdapter {
|
|
|
380887
380952
|
}
|
|
380888
380953
|
async* stream(input) {
|
|
380889
380954
|
let activeInput = input;
|
|
380955
|
+
let preflightCompactionChecked = false;
|
|
380890
380956
|
let contextOverflowCompactions = 0;
|
|
380891
380957
|
let transientRetries = 0;
|
|
380892
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
|
+
}
|
|
380893
380968
|
let emittedModelOutput = false;
|
|
380894
380969
|
try {
|
|
380895
380970
|
for await (const event2 of this.streamOnce(activeInput)) {
|
|
@@ -380990,7 +381065,7 @@ var init_pi_stream_adapter = __esm(() => {
|
|
|
380990
381065
|
});
|
|
380991
381066
|
|
|
380992
381067
|
// src/backend/local/local-executor-factory.ts
|
|
380993
|
-
function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow,
|
|
381068
|
+
function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow, onContextPressure, onLlmStart, onLlmEnd) {
|
|
380994
381069
|
if (options3.executor)
|
|
380995
381070
|
return options3.executor;
|
|
380996
381071
|
if (options3.executionMode === "deterministic") {
|
|
@@ -381001,7 +381076,7 @@ function createLocalExecutor(options3, modelsRuntime, onContextWindowOverflow, o
|
|
|
381001
381076
|
localProviderAuthStorageDir: options3.storageDir,
|
|
381002
381077
|
modelsRuntime,
|
|
381003
381078
|
onContextWindowOverflow,
|
|
381004
|
-
|
|
381079
|
+
onContextPressure,
|
|
381005
381080
|
onLlmStart,
|
|
381006
381081
|
onLlmEnd
|
|
381007
381082
|
}));
|
|
@@ -381451,7 +381526,6 @@ var init_local_backend = __esm(() => {
|
|
|
381451
381526
|
init_memory_git();
|
|
381452
381527
|
init_headless_backend();
|
|
381453
381528
|
init_pi_models_runtime();
|
|
381454
|
-
init_provider_turn_executor();
|
|
381455
381529
|
init_compaction();
|
|
381456
381530
|
init_local_executor_factory();
|
|
381457
381531
|
init_local_model_config();
|
|
@@ -381491,7 +381565,7 @@ var init_local_backend = __esm(() => {
|
|
|
381491
381565
|
storedMessageIdPrefix: "letta-msg-",
|
|
381492
381566
|
localMessageIdPrefix: "ui-msg-"
|
|
381493
381567
|
};
|
|
381494
|
-
super(options3.defaultAgentId ?? "agent-local-default", createLocalExecutor(options3, runtime, (input, error54) => localBackendRef.current?.compactAfterContextOverflow(input, error54) ?? Promise.resolve(null), (input,
|
|
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, {
|
|
381495
381569
|
modelHandle: modelConfig.handle,
|
|
381496
381570
|
runIdPrefix: "local-run-",
|
|
381497
381571
|
runMetadataBackend: "local"
|
|
@@ -381650,12 +381724,7 @@ var init_local_backend = __esm(() => {
|
|
|
381650
381724
|
stats: result.stats
|
|
381651
381725
|
};
|
|
381652
381726
|
}
|
|
381653
|
-
async
|
|
381654
|
-
const contextTokens = contextTokensFromUsage(usage) ?? estimateProviderContextTokens(input);
|
|
381655
|
-
const contextWindow = this.effectiveContextWindow(input.conversationId, input.agentId);
|
|
381656
|
-
if (contextTokens === undefined || contextWindow === undefined || contextTokens <= contextWindow) {
|
|
381657
|
-
return null;
|
|
381658
|
-
}
|
|
381727
|
+
async compactForContextPressure(input, _pressure) {
|
|
381659
381728
|
const result = await this.compactLocalConversation(input.conversationId, input.agentId, "context_window_limit");
|
|
381660
381729
|
return {
|
|
381661
381730
|
uiMessages: this.store.listLocalMessages(input.conversationId, input.agentId),
|
|
@@ -469998,11 +470067,6 @@ async function startAppServer(options3 = {}) {
|
|
|
469998
470067
|
});
|
|
469999
470068
|
server2.on("upgrade", (request, socket, head2) => {
|
|
470000
470069
|
const requestUrl = getRequestUrl(request, listen.host);
|
|
470001
|
-
if (request.headers.origin) {
|
|
470002
|
-
options3.onLog?.(`Rejecting app-server websocket request with Origin header: ${request.url ?? "/"}`);
|
|
470003
|
-
rejectUpgrade(socket, 403, "Forbidden");
|
|
470004
|
-
return;
|
|
470005
|
-
}
|
|
470006
470070
|
if (requestUrl.pathname !== listen.path && requestUrl.pathname !== "/") {
|
|
470007
470071
|
rejectUpgrade(socket, 404, "Not Found");
|
|
470008
470072
|
return;
|
|
@@ -470018,6 +470082,11 @@ async function startAppServer(options3 = {}) {
|
|
|
470018
470082
|
rejectUpgrade(socket, authError.statusCode, authError.message);
|
|
470019
470083
|
return;
|
|
470020
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
|
+
}
|
|
470021
470090
|
wss.handleUpgrade(request, socket, head2, (websocket) => {
|
|
470022
470091
|
handleWebSocketConnection(websocket, channel);
|
|
470023
470092
|
});
|
|
@@ -470126,7 +470195,7 @@ Run the local App Server using native v2 WebSocket frames.
|
|
|
470126
470195
|
Options:
|
|
470127
470196
|
--listen [url] WebSocket listen URL. Defaults to an available loopback port
|
|
470128
470197
|
--openai-api Serve OpenAI-compatible /v1/models and /v1/chat/completions routes (each agent is a model)
|
|
470129
|
-
--ws-auth <mode> WebSocket auth
|
|
470198
|
+
--ws-auth <mode> WebSocket auth for non-loopback listeners and Origin-bearing native clients. Supported: capability-token, signed-bearer-token
|
|
470130
470199
|
--ws-token-file <path> Absolute path to the capability-token file
|
|
470131
470200
|
--ws-token-sha256 <hex> Hex-encoded SHA-256 digest of the capability token
|
|
470132
470201
|
--ws-shared-secret-file <path> Absolute path to the shared secret file for signed JWT bearer tokens
|
|
@@ -470246,7 +470315,7 @@ Remote environment options:
|
|
|
470246
470315
|
App Server options:
|
|
470247
470316
|
--listen [url] Accept App Server connections. If URL is omitted, binds to an available loopback port
|
|
470248
470317
|
--openai-api Serve OpenAI-compatible /v1/models and /v1/chat/completions routes (each agent is a model)
|
|
470249
|
-
--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
|
|
470250
470319
|
--ws-token-file <path> Absolute path to the capability-token file
|
|
470251
470320
|
--ws-token-sha256 <hex> Hex-encoded SHA-256 digest of the capability token
|
|
470252
470321
|
--ws-shared-secret-file <path> Absolute path to the shared secret file for signed JWT bearer tokens
|
|
@@ -541228,4 +541297,4 @@ function registerBunOAuthFlows() {
|
|
|
541228
541297
|
registerBunOAuthFlows();
|
|
541229
541298
|
await init_src5().then(() => exports_src2);
|
|
541230
541299
|
|
|
541231
|
-
//# debugId=
|
|
541300
|
+
//# debugId=D4FE51D0A61DE3F364756E2164756E21
|