@letta-ai/letta-code 0.30.5 → 0.30.7
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/agent-presets.js +3 -13
- package/dist/agent-presets.js.map +2 -2
- package/dist/channels-slack.js +1 -1
- package/dist/channels-slack.js.map +3 -3
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/agent/subagents/subagent-launcher.d.ts +2 -0
- package/dist/types/agent/subagents/subagent-launcher.d.ts.map +1 -1
- package/dist/types/backend/api/client.d.ts +1 -0
- package/dist/types/backend/api/client.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-local-endpoint-provider.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-model-factory.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-models-runtime.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-openai-compatible-provider.d.ts +14 -0
- package/dist/types/backend/dev/pi-openai-compatible-provider.d.ts.map +1 -0
- package/dist/types/backend/dev/pi-provider-registry.d.ts +3 -1
- package/dist/types/backend/dev/pi-provider-registry.d.ts.map +1 -1
- package/dist/types/backend/local/local-provider-auth-store.d.ts +1 -1
- package/dist/types/backend/local/local-provider-auth-store.d.ts.map +1 -1
- package/dist/types/channels/accounts.d.ts.map +1 -1
- package/dist/types/channels/config.d.ts.map +1 -1
- package/dist/types/channels/plugin-types.d.ts +1 -0
- package/dist/types/channels/plugin-types.d.ts.map +1 -1
- package/dist/types/channels/slack/ingress-controller.d.ts.map +1 -1
- package/dist/types/channels/slack/ingress-policy.d.ts +1 -0
- package/dist/types/channels/slack/ingress-policy.d.ts.map +1 -1
- package/dist/types/channels/types.d.ts +2 -0
- package/dist/types/channels/types.d.ts.map +1 -1
- package/dist/types/cli/helpers/error-formatter.d.ts +1 -0
- package/dist/types/cli/helpers/error-formatter.d.ts.map +1 -1
- package/dist/types/cli/helpers/stream-processor.d.ts +6 -0
- package/dist/types/cli/helpers/stream-processor.d.ts.map +1 -1
- package/dist/types/cli/helpers/stream.d.ts +2 -7
- package/dist/types/cli/helpers/stream.d.ts.map +1 -1
- package/dist/types/providers/byok-providers.d.ts.map +1 -1
- package/dist/types/runtime-context.d.ts +2 -0
- package/dist/types/runtime-context.d.ts.map +1 -1
- package/dist/types/tools/impl/shell-env.d.ts.map +1 -1
- package/dist/types/tools/toolset.d.ts +1 -0
- package/dist/types/tools/toolset.d.ts.map +1 -1
- package/dist/types/websocket/listener/mod-adapter.d.ts +1 -0
- package/dist/types/websocket/listener/mod-adapter.d.ts.map +1 -1
- package/dist/types/websocket/listener/runtime.d.ts.map +1 -1
- package/dist/types/websocket/listener/types.d.ts +7 -0
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +454 -203
- package/package.json +1 -1
- package/scripts/check-test-mock-isolation.js +5 -1
- package/scripts/isolated-unit-tests.json +15 -0
- package/scripts/source-file-size-baseline.json +2 -2
- package/skills/scheduling-tasks/SKILL.md +58 -54
package/letta.js
CHANGED
|
@@ -5464,7 +5464,7 @@ var package_default;
|
|
|
5464
5464
|
var init_package = __esm(() => {
|
|
5465
5465
|
package_default = {
|
|
5466
5466
|
name: "@letta-ai/letta-code",
|
|
5467
|
-
version: "0.30.
|
|
5467
|
+
version: "0.30.7",
|
|
5468
5468
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5469
5469
|
type: "module",
|
|
5470
5470
|
packageManager: "bun@1.3.0",
|
|
@@ -5746,6 +5746,7 @@ var init_memfs_git_proxy = __esm(() => {
|
|
|
5746
5746
|
var exports_client = {};
|
|
5747
5747
|
__export(exports_client, {
|
|
5748
5748
|
getServerUrl: () => getServerUrl,
|
|
5749
|
+
getRuntimeEnvironmentDeviceId: () => getRuntimeEnvironmentDeviceId,
|
|
5749
5750
|
getMemfsServerUrl: () => getMemfsServerUrl,
|
|
5750
5751
|
getMemfsGitProxyRewriteConfig: () => getMemfsGitProxyRewriteConfig,
|
|
5751
5752
|
getClientDefaultHeaders: () => getClientDefaultHeaders,
|
|
@@ -7125,12 +7126,7 @@ You **MUST** be proactive in creating crons when work extends beyond the current
|
|
|
7125
7126
|
|
|
7126
7127
|
**Cost**: Self-invocation is critical, but expensive. Default to the longest interval that still serves the user. Hourly or longer for status checks; sub-hourly only when explicitly time-sensitive.
|
|
7127
7128
|
|
|
7128
|
-
|
|
7129
|
-
- One-shot follow-up: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --at "in 30m"\`
|
|
7130
|
-
- Recurring monitoring/heartbeat: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --every "2h"\` or \`--cron "0 9 * * *"\`
|
|
7131
|
-
Always include \`--name\`, \`--description\`, and \`--prompt\`. \`$AGENT_ID\` is automatically injected into the shell environment, and \`letta cron\` uses it by default, so you do not need to specify which agent to invoke unless overriding the current agent intentionally.
|
|
7132
|
-
|
|
7133
|
-
Where crons run: for cloud agents, schedules default to durable Cloud schedules that fire from the cloud and execute in your cloud sandbox — they survive local shutdown, so this is the right default. If the scheduled work must run on a specific computer (e.g. it needs that computer's filesystem or local services), add \`--computer <deviceId>\` (from \`letta environments list\`) to keep the durable Cloud schedule but execute on that computer, with sandbox fallback if it is offline. Use \`--runner local\` only when that fallback is unacceptable; local schedules only fire while a Letta session is running on that computer.
|
|
7129
|
+
The mechanics — flags, where schedules run and execute, timezone handling — live in the scheduling-tasks skill. Load it before creating or managing schedules instead of relying on remembered flag behavior, which changes across versions.
|
|
7134
7130
|
|
|
7135
7131
|
# Harness Architecture
|
|
7136
7132
|
|
|
@@ -7310,12 +7306,7 @@ You **MUST** be proactive in creating crons when work extends beyond the current
|
|
|
7310
7306
|
|
|
7311
7307
|
**Cost**: Self-invocation is critical, but expensive. Default to the longest interval that still serves the user. Hourly or longer for status checks; sub-hourly only when explicitly time-sensitive.
|
|
7312
7308
|
|
|
7313
|
-
|
|
7314
|
-
- One-shot follow-up: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --at "in 30m"\`
|
|
7315
|
-
- Recurring monitoring/heartbeat: \`letta cron add --name <short-name> --description <description> --prompt <future-message> --every "2h"\` or \`--cron "0 9 * * *"\`
|
|
7316
|
-
Always include \`--name\`, \`--description\`, and \`--prompt\`. \`$AGENT_ID\` is automatically injected into the shell environment, and \`letta cron\` uses it by default, so you do not need to specify which agent to invoke unless overriding the current agent intentionally.
|
|
7317
|
-
|
|
7318
|
-
Where crons run: for cloud agents, schedules default to durable Cloud schedules that fire from the cloud and execute in your cloud sandbox — they survive local shutdown, so this is the right default. If the scheduled work must run on a specific computer (e.g. it needs that computer's filesystem or local services), add \`--computer <deviceId>\` (from \`letta environments list\`) to keep the durable Cloud schedule but execute on that computer, with sandbox fallback if it is offline. Use \`--runner local\` only when that fallback is unacceptable; local schedules only fire while a Letta session is running on that computer.
|
|
7309
|
+
The mechanics — flags, where schedules run and execute, timezone handling — live in the scheduling-tasks skill. Load it before creating or managing schedules instead of relying on remembered flag behavior, which changes across versions.
|
|
7319
7310
|
|
|
7320
7311
|
# Harness Architecture
|
|
7321
7312
|
|
|
@@ -139326,7 +139317,7 @@ function isProviderConfigured(provider, localProviderNames) {
|
|
|
139326
139317
|
function listConfiguredPiProviders(localProviderNames) {
|
|
139327
139318
|
return PI_PROVIDER_SPECS.filter((provider) => isProviderConfigured(provider, localProviderNames)).map((provider) => provider.id);
|
|
139328
139319
|
}
|
|
139329
|
-
var LOCAL_CHATGPT_PROVIDER_NAME = "chatgpt-plus-pro", LOCAL_OPENAI_PROVIDER_NAME = "lc-openai", LOCAL_ANTHROPIC_PROVIDER_NAME = "lc-anthropic", LOCAL_OPENROUTER_PROVIDER_NAME = "lc-openrouter", LOCAL_OLLAMA_PROVIDER_NAME = "lc-ollama", LOCAL_OLLAMA_CLOUD_PROVIDER_NAME = "lc-ollama-cloud", LOCAL_LMSTUDIO_PROVIDER_NAME = "lc-lmstudio", LMSTUDIO_OPENAI_PROVIDER_TYPE = "lmstudio_openai", LEGACY_LMSTUDIO_PROVIDER_TYPE = "lmstudio", LOCAL_LLAMA_CPP_PROVIDER_NAME = "lc-llama-cpp", LOCAL_ZAI_PROVIDER_NAME = "lc-zai", LOCAL_ZAI_CODING_PROVIDER_NAME = "lc-zai-coding", LOCAL_MINIMAX_PROVIDER_NAME = "lc-minimax", LOCAL_MOONSHOT_PROVIDER_NAME = "lc-moonshot", LOCAL_KIMI_CODE_PROVIDER_NAME = "lc-kimi-code", LOCAL_GOOGLE_AI_PROVIDER_NAME = "lc-gemini", LOCAL_BEDROCK_PROVIDER_NAME = "lc-bedrock", prefixedCatalogModelHandle = (prefix) => (model) => `${prefix}${model.id}`, PI_PROVIDER_ALIASES, PI_TUI_DEFAULT_MODEL_IDS, PI_TUI_DEFAULTLESS_PROVIDER_IDS, PI_PROVIDER_OVERRIDES, LOCAL_ENDPOINT_PROVIDER_SPECS, PI_PROVIDER_SPECS, SUPPORTED_LOCAL_PROVIDER_TYPES, KNOWN_PI_PROVIDERS, PROVIDER_TYPE_TO_BASE_PROVIDER;
|
|
139320
|
+
var LOCAL_CHATGPT_PROVIDER_NAME = "chatgpt-plus-pro", LOCAL_OPENAI_PROVIDER_NAME = "lc-openai", LOCAL_OPENAI_COMPATIBLE_PROVIDER_NAME = "lc-openai-compatible", OPENAI_COMPATIBLE_PI_PROVIDER_ID = "openai-compatible", LOCAL_ANTHROPIC_PROVIDER_NAME = "lc-anthropic", LOCAL_OPENROUTER_PROVIDER_NAME = "lc-openrouter", LOCAL_OLLAMA_PROVIDER_NAME = "lc-ollama", LOCAL_OLLAMA_CLOUD_PROVIDER_NAME = "lc-ollama-cloud", LOCAL_LMSTUDIO_PROVIDER_NAME = "lc-lmstudio", LMSTUDIO_OPENAI_PROVIDER_TYPE = "lmstudio_openai", LEGACY_LMSTUDIO_PROVIDER_TYPE = "lmstudio", LOCAL_LLAMA_CPP_PROVIDER_NAME = "lc-llama-cpp", LOCAL_ZAI_PROVIDER_NAME = "lc-zai", LOCAL_ZAI_CODING_PROVIDER_NAME = "lc-zai-coding", LOCAL_MINIMAX_PROVIDER_NAME = "lc-minimax", LOCAL_MOONSHOT_PROVIDER_NAME = "lc-moonshot", LOCAL_KIMI_CODE_PROVIDER_NAME = "lc-kimi-code", LOCAL_GOOGLE_AI_PROVIDER_NAME = "lc-gemini", LOCAL_BEDROCK_PROVIDER_NAME = "lc-bedrock", prefixedCatalogModelHandle = (prefix) => (model) => `${prefix}${model.id}`, PI_PROVIDER_ALIASES, PI_TUI_DEFAULT_MODEL_IDS, PI_TUI_DEFAULTLESS_PROVIDER_IDS, PI_PROVIDER_OVERRIDES, LOCAL_ENDPOINT_PROVIDER_SPECS, PI_PROVIDER_SPECS, SUPPORTED_LOCAL_PROVIDER_TYPES, KNOWN_PI_PROVIDERS, PROVIDER_TYPE_TO_BASE_PROVIDER;
|
|
139330
139321
|
var init_pi_provider_registry = __esm(() => {
|
|
139331
139322
|
init_compat2();
|
|
139332
139323
|
init_all();
|
|
@@ -139473,6 +139464,18 @@ var init_pi_provider_registry = __esm(() => {
|
|
|
139473
139464
|
envConfigured: () => hasEnvValue(process.env.OLLAMA_API_KEY),
|
|
139474
139465
|
createCustomModel: true
|
|
139475
139466
|
},
|
|
139467
|
+
{
|
|
139468
|
+
id: OPENAI_COMPATIBLE_PI_PROVIDER_ID,
|
|
139469
|
+
providerTypes: ["openai-compatible"],
|
|
139470
|
+
handlePrefixes: ["openai-compatible/"],
|
|
139471
|
+
localProviderNames: [
|
|
139472
|
+
OPENAI_COMPATIBLE_PI_PROVIDER_ID,
|
|
139473
|
+
LOCAL_OPENAI_COMPATIBLE_PROVIDER_NAME
|
|
139474
|
+
],
|
|
139475
|
+
fallbackApiKey: "not-needed",
|
|
139476
|
+
localModelDiscovery: "openai-compatible",
|
|
139477
|
+
createCustomModel: true
|
|
139478
|
+
},
|
|
139476
139479
|
{
|
|
139477
139480
|
id: "lmstudio",
|
|
139478
139481
|
providerTypes: [
|
|
@@ -139595,6 +139598,10 @@ async function createOrUpdateLocalProvider(input) {
|
|
|
139595
139598
|
}
|
|
139596
139599
|
const file3 = readAuthFile(input.storageDir);
|
|
139597
139600
|
const existing = file3.providers[input.providerName];
|
|
139601
|
+
const baseURL = input.baseURL ?? existing?.base_url;
|
|
139602
|
+
if (input.providerType === OPENAI_COMPATIBLE_PI_PROVIDER_ID && !baseURL?.trim()) {
|
|
139603
|
+
throw new Error("OpenAI-compatible API requires a base URL.");
|
|
139604
|
+
}
|
|
139598
139605
|
const now = new Date().toISOString();
|
|
139599
139606
|
const auth = input.providerType === "chatgpt_oauth" ? parseChatGPTOAuth(input.apiKey) : { type: "api", key: input.apiKey };
|
|
139600
139607
|
const next = {
|
|
@@ -139606,7 +139613,7 @@ async function createOrUpdateLocalProvider(input) {
|
|
|
139606
139613
|
...input.accessKey ? { access_key: input.accessKey } : {},
|
|
139607
139614
|
...input.region ? { region: input.region } : {},
|
|
139608
139615
|
...input.profile ? { profile: input.profile } : {},
|
|
139609
|
-
...
|
|
139616
|
+
...baseURL ? { base_url: baseURL } : {},
|
|
139610
139617
|
...input.timeout !== undefined ? { timeout: input.timeout } : existing?.timeout !== undefined ? { timeout: existing.timeout } : {},
|
|
139611
139618
|
created_at: existing?.created_at ?? now,
|
|
139612
139619
|
updated_at: now
|
|
@@ -140225,6 +140232,20 @@ var init_byok_providers = __esm(() => {
|
|
|
140225
140232
|
providerName: "ollama-cloud",
|
|
140226
140233
|
providerNames: ["ollama-cloud", "lc-ollama-cloud"]
|
|
140227
140234
|
},
|
|
140235
|
+
{
|
|
140236
|
+
id: "openai-compatible",
|
|
140237
|
+
displayName: "OpenAI-compatible API",
|
|
140238
|
+
description: "Connect an OpenAI-compatible Chat Completions endpoint",
|
|
140239
|
+
providerType: "openai-compatible",
|
|
140240
|
+
providerName: "openai-compatible",
|
|
140241
|
+
providerNames: ["openai-compatible", "lc-openai-compatible"],
|
|
140242
|
+
requiresApiKey: false,
|
|
140243
|
+
defaultApiKey: LOCAL_PROVIDER_NO_API_KEY,
|
|
140244
|
+
fields: [
|
|
140245
|
+
{ key: "apiKey", label: "API Key", secret: true, required: false },
|
|
140246
|
+
{ key: "baseUrl", label: "Base URL" }
|
|
140247
|
+
]
|
|
140248
|
+
},
|
|
140228
140249
|
{
|
|
140229
140250
|
id: "lmstudio",
|
|
140230
140251
|
displayName: "LM Studio (local)",
|
|
@@ -146165,6 +146186,7 @@ var init_config2 = __esm(() => {
|
|
|
146165
146186
|
allowedUsers: parsed.allowed_users ?? [],
|
|
146166
146187
|
transcribeVoice: parsed.transcribe_voice === true,
|
|
146167
146188
|
listenMode: parsed.listen_mode === true,
|
|
146189
|
+
mentionOnlyChannels: Array.isArray(parsed.mention_only_channels) ? parsed.mention_only_channels.filter((channelId) => typeof channelId === "string") : [],
|
|
146168
146190
|
allowBots: normalizeSlackAllowBotsMode(parsed.allow_bots)
|
|
146169
146191
|
};
|
|
146170
146192
|
}
|
|
@@ -150405,6 +150427,11 @@ function cloneAccount(account) {
|
|
|
150405
150427
|
if (isTelegramChannelAccount(account)) {
|
|
150406
150428
|
cloned.binding = { ...account.binding };
|
|
150407
150429
|
}
|
|
150430
|
+
if (isSlackChannelAccount(account)) {
|
|
150431
|
+
cloned.mentionOnlyChannels = [
|
|
150432
|
+
...account.mentionOnlyChannels ?? []
|
|
150433
|
+
];
|
|
150434
|
+
}
|
|
150408
150435
|
if (isDiscordChannelAccount(account) && account.allowedChannels) {
|
|
150409
150436
|
cloned.allowedChannels = Array.isArray(account.allowedChannels) ? [...account.allowedChannels] : { ...account.allowedChannels };
|
|
150410
150437
|
}
|
|
@@ -150474,6 +150501,8 @@ function normalizeLoadedAccount(account) {
|
|
|
150474
150501
|
delete next.progress_ui;
|
|
150475
150502
|
delete next.progressUi;
|
|
150476
150503
|
next.listenMode = next.listenMode === true;
|
|
150504
|
+
const mentionOnlyChannels = next.mentionOnlyChannels;
|
|
150505
|
+
next.mentionOnlyChannels = Array.isArray(mentionOnlyChannels) ? [...mentionOnlyChannels] : [];
|
|
150477
150506
|
next.allowBots = normalizeSlackAllowBotsMode(next.allowBots);
|
|
150478
150507
|
}
|
|
150479
150508
|
if (isDiscordChannelAccount(next)) {
|
|
@@ -150623,6 +150652,7 @@ function makeDefaultLegacyAccount(channelId) {
|
|
|
150623
150652
|
defaultPermissionMode: DEFAULT_SLACK_PERMISSION_MODE,
|
|
150624
150653
|
transcribeVoice: config3.transcribeVoice === true,
|
|
150625
150654
|
listenMode: config3.listenMode === true,
|
|
150655
|
+
mentionOnlyChannels: [...config3.mentionOnlyChannels ?? []],
|
|
150626
150656
|
allowBots: config3.allowBots ?? false,
|
|
150627
150657
|
createdAt: now,
|
|
150628
150658
|
updatedAt: now
|
|
@@ -150822,6 +150852,7 @@ var init_accounts = __esm(() => {
|
|
|
150822
150852
|
group_mode: "groupMode",
|
|
150823
150853
|
inbound_debounce_ms: "inboundDebounceMs",
|
|
150824
150854
|
listen_mode: "listenMode",
|
|
150855
|
+
mention_only_channels: "mentionOnlyChannels",
|
|
150825
150856
|
message_prefix: "messagePrefix",
|
|
150826
150857
|
media_max_bytes: "mediaMaxBytes",
|
|
150827
150858
|
attachment_filter: "attachmentFilter",
|
|
@@ -154533,6 +154564,9 @@ var init_inbound_debounce = __esm(() => {
|
|
|
154533
154564
|
});
|
|
154534
154565
|
|
|
154535
154566
|
// src/channels/slack/ingress-policy.ts
|
|
154567
|
+
function isSlackMentionOnlyChannel(channelId, mentionOnlyChannels) {
|
|
154568
|
+
return mentionOnlyChannels?.includes(channelId) === true;
|
|
154569
|
+
}
|
|
154536
154570
|
function hasRecordValue(value) {
|
|
154537
154571
|
return value !== null && typeof value === "object";
|
|
154538
154572
|
}
|
|
@@ -154763,6 +154797,9 @@ function createSlackIngressController(params) {
|
|
|
154763
154797
|
})) {
|
|
154764
154798
|
return;
|
|
154765
154799
|
}
|
|
154800
|
+
if (basePolicy.chatType === "channel" && !basePolicy.wasMentioned && isSlackMentionOnlyChannel(channelId, config3.mentionOnlyChannels)) {
|
|
154801
|
+
return;
|
|
154802
|
+
}
|
|
154766
154803
|
const attachments = await resolveSlackInboundAttachments({
|
|
154767
154804
|
accountId: config3.accountId,
|
|
154768
154805
|
token: config3.botToken,
|
|
@@ -154944,6 +154981,9 @@ function createSlackIngressController(params) {
|
|
|
154944
154981
|
return;
|
|
154945
154982
|
}
|
|
154946
154983
|
const chatType = resolveSlackChatType(chatId);
|
|
154984
|
+
if (chatType === "channel" && isSlackMentionOnlyChannel(chatId, config3.mentionOnlyChannels)) {
|
|
154985
|
+
return;
|
|
154986
|
+
}
|
|
154947
154987
|
const threadId = chatType === "channel" ? knownThreadIdsByMessageId.get(targetMessageId) ?? targetMessageId : knownThreadIdsByMessageId.get(targetMessageId) ?? null;
|
|
154948
154988
|
try {
|
|
154949
154989
|
await adapter.onMessage({
|
|
@@ -172754,6 +172794,7 @@ function createConversationRuntime(listener, agentId, conversationId) {
|
|
|
172754
172794
|
currentToolsetPreference: "auto",
|
|
172755
172795
|
currentLoadedTools: [],
|
|
172756
172796
|
pendingApprovalBatchByToolCallId: new Map,
|
|
172797
|
+
approvalMessageIdByToolCallId: new Map,
|
|
172757
172798
|
pendingInterruptedResults: null,
|
|
172758
172799
|
pendingInterruptedContext: null,
|
|
172759
172800
|
continuationEpoch: 0,
|
|
@@ -172790,6 +172831,7 @@ function clearConversationRuntimeState(runtime) {
|
|
|
172790
172831
|
conversationId: runtime.conversationId
|
|
172791
172832
|
});
|
|
172792
172833
|
runtime.pendingApprovalBatchByToolCallId.clear();
|
|
172834
|
+
runtime.approvalMessageIdByToolCallId.clear();
|
|
172793
172835
|
runtime.pendingInterruptedResults = null;
|
|
172794
172836
|
runtime.pendingInterruptedContext = null;
|
|
172795
172837
|
runtime.pendingInterruptedToolCallIds = null;
|
|
@@ -173673,6 +173715,10 @@ function getShellEnv() {
|
|
|
173673
173715
|
env3[pathKey] = existingPath ? `${pathPrefixes.join(shellPathDelimiter())}${shellPathDelimiter()}${existingPath}` : pathPrefixes.join(shellPathDelimiter());
|
|
173674
173716
|
}
|
|
173675
173717
|
env3.USER_CWD = getCurrentWorkingDirectory();
|
|
173718
|
+
const environmentDeviceId = getRuntimeContext()?.environmentDeviceId?.trim();
|
|
173719
|
+
if (environmentDeviceId) {
|
|
173720
|
+
env3.LETTA_RUNTIME_ENVIRONMENT_DEVICE_ID = environmentDeviceId;
|
|
173721
|
+
}
|
|
173676
173722
|
let agentId;
|
|
173677
173723
|
try {
|
|
173678
173724
|
const resolvedAgentId = getCurrentAgentId();
|
|
@@ -348867,9 +348913,21 @@ import { join as join34 } from "node:path";
|
|
|
348867
348913
|
async function getUnavailableListenerClient() {
|
|
348868
348914
|
throw new Error("letta.client is not available in listener mods");
|
|
348869
348915
|
}
|
|
348916
|
+
function resolveListenerAgentMemfsContext(agentId) {
|
|
348917
|
+
if (!agentId)
|
|
348918
|
+
return { enabled: false, memoryDir: null };
|
|
348919
|
+
try {
|
|
348920
|
+
return settingsManager.isMemfsEnabled(agentId) ? {
|
|
348921
|
+
enabled: true,
|
|
348922
|
+
memoryDir: getScopedMemoryFilesystemRoot(agentId)
|
|
348923
|
+
} : { enabled: false, memoryDir: null };
|
|
348924
|
+
} catch {
|
|
348925
|
+
return { enabled: false, memoryDir: null };
|
|
348926
|
+
}
|
|
348927
|
+
}
|
|
348870
348928
|
function createListenerModContext(options3 = {}) {
|
|
348871
348929
|
const cwd = options3.workingDirectory ?? getCurrentWorkingDirectory();
|
|
348872
|
-
|
|
348930
|
+
const context3 = buildModInvocationContext({
|
|
348873
348931
|
agent: options3.agent ?? null,
|
|
348874
348932
|
conversationId: options3.sessionId ?? null,
|
|
348875
348933
|
modelIdentifier: options3.modelIdentifier ?? null,
|
|
@@ -348877,6 +348935,13 @@ function createListenerModContext(options3 = {}) {
|
|
|
348877
348935
|
toolset: options3.toolset ?? null,
|
|
348878
348936
|
workingDirectory: cwd
|
|
348879
348937
|
});
|
|
348938
|
+
return {
|
|
348939
|
+
...context3,
|
|
348940
|
+
memfs: resolveListenerAgentMemfsContext(context3.agent.id)
|
|
348941
|
+
};
|
|
348942
|
+
}
|
|
348943
|
+
function createListenerAgentModContext(agentId) {
|
|
348944
|
+
return createListenerModContext({ agent: { id: agentId } });
|
|
348880
348945
|
}
|
|
348881
348946
|
function createListenerModAdapter(options3 = {}) {
|
|
348882
348947
|
return createModAdapter({
|
|
@@ -350048,7 +350113,7 @@ function scheduleQueueEmit(runtime, scope) {
|
|
|
350048
350113
|
}
|
|
350049
350114
|
function createLifecycleMessageBase(messageType, runId) {
|
|
350050
350115
|
return {
|
|
350051
|
-
id: `
|
|
350116
|
+
id: `lifecycle-${crypto.randomUUID()}`,
|
|
350052
350117
|
date: new Date().toISOString(),
|
|
350053
350118
|
message_type: messageType,
|
|
350054
350119
|
...runId ? { run_id: runId } : {}
|
|
@@ -364865,6 +364930,7 @@ function composeSubagentChildEnv(options3) {
|
|
|
364865
364930
|
backendMode,
|
|
364866
364931
|
localBackendStorageDir,
|
|
364867
364932
|
parentAgentId,
|
|
364933
|
+
subagentType,
|
|
364868
364934
|
launchProfile,
|
|
364869
364935
|
inheritedPrimaryRoot,
|
|
364870
364936
|
memoryScope,
|
|
@@ -364878,6 +364944,7 @@ function composeSubagentChildEnv(options3) {
|
|
|
364878
364944
|
...inheritedApiKey && { LETTA_API_KEY: inheritedApiKey },
|
|
364879
364945
|
...inheritedBaseUrl && { LETTA_BASE_URL: inheritedBaseUrl },
|
|
364880
364946
|
LETTA_CODE_AGENT_ROLE: "subagent",
|
|
364947
|
+
...subagentType === "reflection" && { [LETTA_DISABLE_MODS_ENV]: "1" },
|
|
364881
364948
|
...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId },
|
|
364882
364949
|
...transcriptPath && { TRANSCRIPT_PATH: transcriptPath },
|
|
364883
364950
|
...inheritedChannelContext && {
|
|
@@ -365410,6 +365477,7 @@ async function executeSubagent(type3, config3, model, userPrompt, subagentId, is
|
|
|
365410
365477
|
backendMode,
|
|
365411
365478
|
localBackendStorageDir,
|
|
365412
365479
|
parentAgentId,
|
|
365480
|
+
subagentType: type3,
|
|
365413
365481
|
launchProfile: effectiveLaunchProfile,
|
|
365414
365482
|
inheritedPrimaryRoot,
|
|
365415
365483
|
memoryScope,
|
|
@@ -373761,6 +373829,7 @@ function parseInheritedChannelContextEnv() {
|
|
|
373761
373829
|
async function prepareToolExecutionContextForScope(params) {
|
|
373762
373830
|
const {
|
|
373763
373831
|
connectionId,
|
|
373832
|
+
environmentDeviceId,
|
|
373764
373833
|
agentId,
|
|
373765
373834
|
conversationId,
|
|
373766
373835
|
overrideModel,
|
|
@@ -373826,6 +373895,7 @@ async function prepareToolExecutionContextForScope(params) {
|
|
|
373826
373895
|
agent: agent2,
|
|
373827
373896
|
runtimeContext: {
|
|
373828
373897
|
connectionId,
|
|
373898
|
+
environmentDeviceId,
|
|
373829
373899
|
agentId,
|
|
373830
373900
|
agentName: agent2.name ?? null,
|
|
373831
373901
|
conversationId: scopedConversationId,
|
|
@@ -375025,13 +375095,13 @@ echo password=${token}
|
|
|
375025
375095
|
} else {
|
|
375026
375096
|
helper = `!f() { echo "username=letta"; echo "password=${token}"; }; f`;
|
|
375027
375097
|
}
|
|
375028
|
-
|
|
375029
|
-
"config",
|
|
375030
|
-
|
|
375031
|
-
|
|
375032
|
-
|
|
375098
|
+
const writeHelperWithReset = async (key) => {
|
|
375099
|
+
await gitConfig(dir, ["config", "--local", "--replace-all", key, ""]);
|
|
375100
|
+
await gitConfig(dir, ["config", "--local", "--add", key, helper]);
|
|
375101
|
+
};
|
|
375102
|
+
await writeHelperWithReset(`credential.${normalizedBaseUrl}.helper`);
|
|
375033
375103
|
if (rawBaseUrl !== normalizedBaseUrl) {
|
|
375034
|
-
await
|
|
375104
|
+
await writeHelperWithReset(`credential.${rawBaseUrl}.helper`);
|
|
375035
375105
|
}
|
|
375036
375106
|
debugLog("memfs-git", `Configured local credential helper for ${normalizedBaseUrl}${rawBaseUrl !== normalizedBaseUrl ? ` (and raw ${rawBaseUrl})` : ""}`);
|
|
375037
375107
|
}
|
|
@@ -379215,6 +379285,7 @@ function isEncryptedContentError(e2) {
|
|
|
379215
379285
|
function formatErrorDetails2(e2, agentId, conversationId, options3 = {}) {
|
|
379216
379286
|
let runId;
|
|
379217
379287
|
const surface = options3.surface ?? "terminal";
|
|
379288
|
+
const fallback = (raw) => options3.unclassifiedFallback === "generic" ? GENERIC_ERROR_MESSAGE : raw;
|
|
379218
379289
|
const encryptedContentMsg = checkEncryptedContentError(e2);
|
|
379219
379290
|
if (encryptedContentMsg)
|
|
379220
379291
|
return encryptedContentMsg;
|
|
@@ -379303,6 +379374,8 @@ Detail: ${detail}` : "";
|
|
|
379303
379374
|
const conversationBusyMessage = formatConversationBusyErrorForDisplay(baseError, runId, options3);
|
|
379304
379375
|
if (conversationBusyMessage)
|
|
379305
379376
|
return conversationBusyMessage;
|
|
379377
|
+
if (options3.unclassifiedFallback === "generic")
|
|
379378
|
+
return fallback(baseError);
|
|
379306
379379
|
return runId && agentId ? `${baseError}
|
|
379307
379380
|
${createAgentLink(runId, agentId, conversationId, surface)}` : baseError;
|
|
379308
379381
|
}
|
|
@@ -379316,32 +379389,34 @@ ${createAgentLink(runId, agentId, conversationId, surface)}` : baseError;
|
|
|
379316
379389
|
const conversationBusyMessage = formatConversationBusyErrorForDisplay(baseError, runId, options3);
|
|
379317
379390
|
if (conversationBusyMessage)
|
|
379318
379391
|
return conversationBusyMessage;
|
|
379392
|
+
if (options3.unclassifiedFallback === "generic")
|
|
379393
|
+
return fallback(baseError);
|
|
379319
379394
|
return runId && agentId ? `${baseError}
|
|
379320
379395
|
${createAgentLink(runId, agentId, conversationId, surface)}` : baseError;
|
|
379321
379396
|
}
|
|
379322
|
-
return e2.message;
|
|
379397
|
+
return fallback(e2.message);
|
|
379323
379398
|
}
|
|
379324
379399
|
if (e2 instanceof Error) {
|
|
379325
|
-
return e2.message;
|
|
379400
|
+
return fallback(e2.message);
|
|
379326
379401
|
}
|
|
379327
379402
|
if (typeof e2 === "object" && e2 !== null) {
|
|
379328
379403
|
const obj = e2;
|
|
379329
379404
|
if (typeof obj.message === "string") {
|
|
379330
|
-
return obj.message;
|
|
379405
|
+
return fallback(obj.message);
|
|
379331
379406
|
}
|
|
379332
379407
|
if (typeof obj.error === "string") {
|
|
379333
|
-
return obj.error;
|
|
379408
|
+
return fallback(obj.error);
|
|
379334
379409
|
}
|
|
379335
379410
|
if (typeof obj.detail === "string") {
|
|
379336
|
-
return obj.detail;
|
|
379411
|
+
return fallback(obj.detail);
|
|
379337
379412
|
}
|
|
379338
379413
|
try {
|
|
379339
|
-
return JSON.stringify(e2, null, 2);
|
|
379414
|
+
return fallback(JSON.stringify(e2, null, 2));
|
|
379340
379415
|
} catch {
|
|
379341
|
-
return "[Error: Unable to serialize error object]";
|
|
379416
|
+
return fallback("[Error: Unable to serialize error object]");
|
|
379342
379417
|
}
|
|
379343
379418
|
}
|
|
379344
|
-
return String(e2);
|
|
379419
|
+
return fallback(String(e2));
|
|
379345
379420
|
}
|
|
379346
379421
|
function getRetryStatusMessage(errorDetail2) {
|
|
379347
379422
|
if (!errorDetail2)
|
|
@@ -379373,7 +379448,7 @@ function createAgentLink(runId, agentId, conversationId, surface) {
|
|
|
379373
379448
|
const agentRef = surface === "terminal" ? buildAgentTerminalLink(agentId, { conversationId }) : agentId;
|
|
379374
379449
|
return `View agent: ${agentRef} (run: ${runId})`;
|
|
379375
379450
|
}
|
|
379376
|
-
var LETTA_USAGE_URL, LETTA_AGENTS_URL, CLOUDFLARE_EDGE_5XX_MARKER_PATTERN, CLOUDFLARE_EDGE_5XX_TITLE_PATTERN, CLOUDFLARE_EDGE_5XX_FORMATTED_PATTERN, CLOUDFLARE_JSON_5XX_PATTERN, CHATGPT_USAGE_LIMIT_HINT = "Switch models with /model, or connect your own provider keys with /connect.", ENCRYPTED_CONTENT_HINT, DEFAULT_RETRY_MESSAGE = "Unexpected downstream LLM API error, retrying...", ENDPOINT_TYPE_DISPLAY_NAMES;
|
|
379451
|
+
var LETTA_USAGE_URL, LETTA_AGENTS_URL, GENERIC_ERROR_MESSAGE = "The request failed. Please try again.", CLOUDFLARE_EDGE_5XX_MARKER_PATTERN, CLOUDFLARE_EDGE_5XX_TITLE_PATTERN, CLOUDFLARE_EDGE_5XX_FORMATTED_PATTERN, CLOUDFLARE_JSON_5XX_PATTERN, CHATGPT_USAGE_LIMIT_HINT = "Switch models with /model, or connect your own provider keys with /connect.", ENCRYPTED_CONTENT_HINT, DEFAULT_RETRY_MESSAGE = "Unexpected downstream LLM API error, retrying...", ENDPOINT_TYPE_DISPLAY_NAMES;
|
|
379377
379452
|
var init_error_formatter = __esm(() => {
|
|
379378
379453
|
init_error();
|
|
379379
379454
|
init_conversation_busy_error();
|
|
@@ -380797,7 +380872,10 @@ function createLocalEndpointPiProvider(options3) {
|
|
|
380797
380872
|
name: `${options3.name} API key`,
|
|
380798
380873
|
resolve: async ({ credential }) => {
|
|
380799
380874
|
const apiKey = credential?.key ?? options3.apiKey;
|
|
380800
|
-
return apiKey ? {
|
|
380875
|
+
return apiKey ? {
|
|
380876
|
+
auth: apiKey === "not-needed" ? { apiKey, headers: { Authorization: null } } : { apiKey },
|
|
380877
|
+
source: "local provider record"
|
|
380878
|
+
} : undefined;
|
|
380801
380879
|
}
|
|
380802
380880
|
}
|
|
380803
380881
|
},
|
|
@@ -381158,6 +381236,27 @@ var init_pi_ollama_provider = __esm(() => {
|
|
|
381158
381236
|
init_pi_local_endpoint_provider();
|
|
381159
381237
|
});
|
|
381160
381238
|
|
|
381239
|
+
// src/backend/dev/pi-openai-compatible-provider.ts
|
|
381240
|
+
function createOpenAICompatiblePiProvider(options3) {
|
|
381241
|
+
return createLocalEndpointPiProvider({
|
|
381242
|
+
id: OPENAI_COMPATIBLE_PI_PROVIDER_ID,
|
|
381243
|
+
name: "OpenAI-compatible API",
|
|
381244
|
+
baseURL: options3.baseURL,
|
|
381245
|
+
...options3.apiKey ? { apiKey: options3.apiKey } : {},
|
|
381246
|
+
...options3.fetchImpl ? { fetchImpl: options3.fetchImpl } : {},
|
|
381247
|
+
...options3.discoveryTimeoutMs ? { discoveryTimeoutMs: options3.discoveryTimeoutMs } : {},
|
|
381248
|
+
discover: openAICompatibleDiscover
|
|
381249
|
+
});
|
|
381250
|
+
}
|
|
381251
|
+
var openAICompatibleDiscover = async (context3) => {
|
|
381252
|
+
const list = await context3.fetchJson(`${context3.openAIBaseURL}/models`);
|
|
381253
|
+
return modelIdsFromOpenAICompatibleList(list).map((modelId) => context3.lastKnown.get(modelId) ?? context3.buildModel({ id: modelId }));
|
|
381254
|
+
};
|
|
381255
|
+
var init_pi_openai_compatible_provider = __esm(() => {
|
|
381256
|
+
init_pi_local_endpoint_provider();
|
|
381257
|
+
init_pi_provider_registry();
|
|
381258
|
+
});
|
|
381259
|
+
|
|
381161
381260
|
// src/backend/dev/pi-models-runtime.ts
|
|
381162
381261
|
function aliasedAuthContext() {
|
|
381163
381262
|
const base2 = defaultProviderAuthContext();
|
|
@@ -381185,7 +381284,7 @@ function resolveLocalEndpointConnection(providerId2, storageDir) {
|
|
|
381185
381284
|
break;
|
|
381186
381285
|
}
|
|
381187
381286
|
const baseURL = record5?.base_url ?? spec.baseUrlEnv?.() ?? spec.defaultBaseURL ?? "";
|
|
381188
|
-
const apiKey = localProviderApiKeyFromRecord(record5) ?? spec.apiKeyEnv?.() ?? spec.fallbackApiKey;
|
|
381287
|
+
const apiKey = localProviderApiKeyFromRecord(record5) ?? spec.apiKeyEnv?.() ?? (record5 !== null || spec.autoDetectLocalEndpoint === true ? spec.fallbackApiKey : undefined);
|
|
381189
381288
|
return {
|
|
381190
381289
|
baseURL,
|
|
381191
381290
|
apiKey,
|
|
@@ -381424,6 +381523,7 @@ var init_pi_models_runtime = __esm(() => {
|
|
|
381424
381523
|
init_pi_lmstudio_provider();
|
|
381425
381524
|
init_pi_mod_provider();
|
|
381426
381525
|
init_pi_ollama_provider();
|
|
381526
|
+
init_pi_openai_compatible_provider();
|
|
381427
381527
|
init_pi_provider_mod_registry();
|
|
381428
381528
|
init_pi_provider_registry();
|
|
381429
381529
|
init_registered_pi_provider_runtime();
|
|
@@ -381440,7 +381540,11 @@ var init_pi_models_runtime = __esm(() => {
|
|
|
381440
381540
|
})
|
|
381441
381541
|
],
|
|
381442
381542
|
[LLAMA_CPP_PI_PROVIDER_ID, (input) => createLlamaCppPiProvider(input)],
|
|
381443
|
-
[LMSTUDIO_PI_PROVIDER_ID, (input) => createLmStudioPiProvider(input)]
|
|
381543
|
+
[LMSTUDIO_PI_PROVIDER_ID, (input) => createLmStudioPiProvider(input)],
|
|
381544
|
+
[
|
|
381545
|
+
OPENAI_COMPATIBLE_PI_PROVIDER_ID,
|
|
381546
|
+
(input) => createOpenAICompatiblePiProvider(input)
|
|
381547
|
+
]
|
|
381444
381548
|
]);
|
|
381445
381549
|
});
|
|
381446
381550
|
|
|
@@ -381674,7 +381778,10 @@ async function resolvePiModelForAgent(modelHandle, modelSettings = {}, options3
|
|
|
381674
381778
|
}
|
|
381675
381779
|
const fallbackModelId = !registeredProvider && spec?.piProvider ? fallbackCatalogModelId(spec.piProvider, modelId) : undefined;
|
|
381676
381780
|
const { model: publishedModel, auth: authResult } = await modelsRuntime.resolveTurn(runtimeProviderId, modelId, fallbackModelId);
|
|
381677
|
-
connection = {
|
|
381781
|
+
connection = {
|
|
381782
|
+
...connection,
|
|
381783
|
+
apiKey: authResult?.auth.apiKey === LOCAL_PROVIDER_NO_API_KEY ? undefined : authResult?.auth.apiKey
|
|
381784
|
+
};
|
|
381678
381785
|
if (authResult?.auth.baseUrl)
|
|
381679
381786
|
baseURL = authResult.auth.baseUrl;
|
|
381680
381787
|
if (authResult?.auth.headers) {
|
|
@@ -384635,10 +384742,12 @@ function isResumedConversation(conversation) {
|
|
|
384635
384742
|
function approvalRequestsFromMessage(messageToCheck) {
|
|
384636
384743
|
const approvalMsg = messageToCheck;
|
|
384637
384744
|
const toolCalls = Array.isArray(approvalMsg.tool_calls) ? approvalMsg.tool_calls : approvalMsg.tool_call ? [approvalMsg.tool_call] : [];
|
|
384745
|
+
const messageId = "id" in messageToCheck && typeof messageToCheck.id === "string" ? messageToCheck.id : undefined;
|
|
384638
384746
|
return toolCalls.filter((tc) => !!tc && !!tc.tool_call_id).map((tc) => ({
|
|
384639
384747
|
toolCallId: tc.tool_call_id,
|
|
384640
384748
|
toolName: tc.name || "",
|
|
384641
|
-
toolArgs: tc.arguments || ""
|
|
384749
|
+
toolArgs: tc.arguments || "",
|
|
384750
|
+
...messageId ? { messageId } : {}
|
|
384642
384751
|
}));
|
|
384643
384752
|
}
|
|
384644
384753
|
function logPendingApprovals(pendingApprovals) {
|
|
@@ -426741,6 +426850,9 @@ function isNullableString4(value) {
|
|
|
426741
426850
|
function isBoolean3(value) {
|
|
426742
426851
|
return value === true || value === false;
|
|
426743
426852
|
}
|
|
426853
|
+
function isStringArray5(value) {
|
|
426854
|
+
return Array.isArray(value) && value.every(isString3);
|
|
426855
|
+
}
|
|
426744
426856
|
function isDefaultPermissionMode2(value) {
|
|
426745
426857
|
return value === "standard" || value === "acceptEdits" || value === "unrestricted" || value === "default" || value === "bypassPermissions" || value === "fullAccess";
|
|
426746
426858
|
}
|
|
@@ -426757,6 +426869,7 @@ var init_account_config4 = __esm(() => {
|
|
|
426757
426869
|
"transcribe_voice",
|
|
426758
426870
|
"show_completed_reaction",
|
|
426759
426871
|
"listen_mode",
|
|
426872
|
+
"mention_only_channels",
|
|
426760
426873
|
"allow_bots"
|
|
426761
426874
|
]);
|
|
426762
426875
|
slackAccountConfigAdapter = {
|
|
@@ -426766,7 +426879,7 @@ var init_account_config4 = __esm(() => {
|
|
|
426766
426879
|
return false;
|
|
426767
426880
|
}
|
|
426768
426881
|
}
|
|
426769
|
-
return (config3.bot_token === undefined || isString3(config3.bot_token)) && (config3.app_token === undefined || isString3(config3.app_token)) && (config3.mode === undefined || config3.mode === "socket") && (config3.agent_id === undefined || isNullableString4(config3.agent_id)) && (config3.default_permission_mode === undefined || isDefaultPermissionMode2(config3.default_permission_mode)) && (config3.transcribe_voice === undefined || isBoolean3(config3.transcribe_voice)) && (config3.show_completed_reaction === undefined || isBoolean3(config3.show_completed_reaction)) && (config3.listen_mode === undefined || isBoolean3(config3.listen_mode)) && isValidSlackAllowBotsConfigValue(config3.allow_bots);
|
|
426882
|
+
return (config3.bot_token === undefined || isString3(config3.bot_token)) && (config3.app_token === undefined || isString3(config3.app_token)) && (config3.mode === undefined || config3.mode === "socket") && (config3.agent_id === undefined || isNullableString4(config3.agent_id)) && (config3.default_permission_mode === undefined || isDefaultPermissionMode2(config3.default_permission_mode)) && (config3.transcribe_voice === undefined || isBoolean3(config3.transcribe_voice)) && (config3.show_completed_reaction === undefined || isBoolean3(config3.show_completed_reaction)) && (config3.listen_mode === undefined || isBoolean3(config3.listen_mode)) && (config3.mention_only_channels === undefined || isStringArray5(config3.mention_only_channels)) && isValidSlackAllowBotsConfigValue(config3.allow_bots);
|
|
426770
426883
|
},
|
|
426771
426884
|
toAccountPatch(config3) {
|
|
426772
426885
|
return {
|
|
@@ -426777,6 +426890,7 @@ var init_account_config4 = __esm(() => {
|
|
|
426777
426890
|
defaultPermissionMode: isDefaultPermissionMode2(config3.default_permission_mode) ? migratePermissionMode(config3.default_permission_mode) : undefined,
|
|
426778
426891
|
transcribeVoice: isBoolean3(config3.transcribe_voice) ? config3.transcribe_voice : undefined,
|
|
426779
426892
|
listenMode: isBoolean3(config3.listen_mode) ? config3.listen_mode : undefined,
|
|
426893
|
+
mentionOnlyChannels: isStringArray5(config3.mention_only_channels) ? [...config3.mention_only_channels] : undefined,
|
|
426780
426894
|
allowBots: config3.allow_bots !== undefined && isValidSlackAllowBotsConfigValue(config3.allow_bots) ? normalizeSlackAllowBotsMode(config3.allow_bots) : undefined
|
|
426781
426895
|
};
|
|
426782
426896
|
},
|
|
@@ -426789,6 +426903,7 @@ var init_account_config4 = __esm(() => {
|
|
|
426789
426903
|
default_permission_mode: account.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
426790
426904
|
transcribe_voice: account.transcribeVoice === true,
|
|
426791
426905
|
listen_mode: account.listenMode === true,
|
|
426906
|
+
mention_only_channels: [...account.mentionOnlyChannels ?? []],
|
|
426792
426907
|
allow_bots: account.allowBots ?? false
|
|
426793
426908
|
};
|
|
426794
426909
|
},
|
|
@@ -426801,6 +426916,7 @@ var init_account_config4 = __esm(() => {
|
|
|
426801
426916
|
default_permission_mode: account.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
426802
426917
|
transcribe_voice: account.transcribeVoice === true,
|
|
426803
426918
|
listen_mode: account.listenMode === true,
|
|
426919
|
+
mention_only_channels: [...account.mentionOnlyChannels ?? []],
|
|
426804
426920
|
allow_bots: account.allowBots ?? false
|
|
426805
426921
|
};
|
|
426806
426922
|
},
|
|
@@ -426890,7 +427006,7 @@ function isNullableString5(value) {
|
|
|
426890
427006
|
function isBoolean5(value) {
|
|
426891
427007
|
return typeof value === "boolean";
|
|
426892
427008
|
}
|
|
426893
|
-
function
|
|
427009
|
+
function isStringArray6(value) {
|
|
426894
427010
|
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
426895
427011
|
}
|
|
426896
427012
|
function isGroupMode3(value) {
|
|
@@ -426936,22 +427052,22 @@ var init_account_config6 = __esm(() => {
|
|
|
426936
427052
|
return false;
|
|
426937
427053
|
}
|
|
426938
427054
|
}
|
|
426939
|
-
return (config3.agent_id === undefined || isNullableString5(config3.agent_id)) && (config3.self_chat_mode === undefined || isBoolean5(config3.self_chat_mode)) && (config3.group_mode === undefined || isGroupMode3(config3.group_mode)) && (config3.allowed_groups === undefined ||
|
|
427055
|
+
return (config3.agent_id === undefined || isNullableString5(config3.agent_id)) && (config3.self_chat_mode === undefined || isBoolean5(config3.self_chat_mode)) && (config3.group_mode === undefined || isGroupMode3(config3.group_mode)) && (config3.allowed_groups === undefined || isStringArray6(config3.allowed_groups)) && (config3.mention_patterns === undefined || isStringArray6(config3.mention_patterns)) && (config3.transcribe_voice === undefined || isBoolean5(config3.transcribe_voice)) && (config3.download_media === undefined || isBoolean5(config3.download_media)) && (config3.media_max_bytes === undefined || isPositiveNumber2(config3.media_max_bytes)) && (config3.attachment_filter === undefined || isBoolean5(config3.attachment_filter)) && (config3.attachment_mime_types === undefined || isStringArray6(config3.attachment_mime_types)) && (config3.attachment_allowed_recipients === undefined || isStringArray6(config3.attachment_allowed_recipients)) && (config3.attachment_allowed_paths === undefined || isStringArray6(config3.attachment_allowed_paths)) && (config3.attachment_path_recursive === undefined || isBoolean5(config3.attachment_path_recursive)) && (config3.inbound_debounce_ms === undefined || isValidInboundDebounceMs(config3.inbound_debounce_ms)) && (config3.waiting_behavior === undefined || isWaitingBehavior(config3.waiting_behavior)) && (config3.message_prefix === undefined || isString5(config3.message_prefix));
|
|
426940
427056
|
},
|
|
426941
427057
|
toAccountPatch(config3) {
|
|
426942
427058
|
return {
|
|
426943
427059
|
agentId: isNullableString5(config3.agent_id) ? config3.agent_id : undefined,
|
|
426944
427060
|
selfChatMode: isBoolean5(config3.self_chat_mode) ? config3.self_chat_mode : undefined,
|
|
426945
427061
|
groupMode: isGroupMode3(config3.group_mode) ? config3.group_mode : undefined,
|
|
426946
|
-
allowedGroups:
|
|
426947
|
-
mentionPatterns:
|
|
427062
|
+
allowedGroups: isStringArray6(config3.allowed_groups) ? [...config3.allowed_groups] : undefined,
|
|
427063
|
+
mentionPatterns: isStringArray6(config3.mention_patterns) ? [...config3.mention_patterns] : undefined,
|
|
426948
427064
|
transcribeVoice: isBoolean5(config3.transcribe_voice) ? config3.transcribe_voice : undefined,
|
|
426949
427065
|
downloadMedia: isBoolean5(config3.download_media) ? config3.download_media : undefined,
|
|
426950
427066
|
mediaMaxBytes: isPositiveNumber2(config3.media_max_bytes) ? config3.media_max_bytes : undefined,
|
|
426951
427067
|
attachmentFilter: isBoolean5(config3.attachment_filter) ? config3.attachment_filter : undefined,
|
|
426952
|
-
attachmentMimeTypes:
|
|
426953
|
-
attachmentAllowedRecipients:
|
|
426954
|
-
attachmentAllowedPaths:
|
|
427068
|
+
attachmentMimeTypes: isStringArray6(config3.attachment_mime_types) ? [...config3.attachment_mime_types] : undefined,
|
|
427069
|
+
attachmentAllowedRecipients: isStringArray6(config3.attachment_allowed_recipients) ? [...config3.attachment_allowed_recipients] : undefined,
|
|
427070
|
+
attachmentAllowedPaths: isStringArray6(config3.attachment_allowed_paths) ? [...config3.attachment_allowed_paths] : undefined,
|
|
426955
427071
|
attachmentPathRecursive: isBoolean5(config3.attachment_path_recursive) ? config3.attachment_path_recursive : undefined,
|
|
426956
427072
|
inboundDebounceMs: isValidInboundDebounceMs(config3.inbound_debounce_ms) ? Math.trunc(Math.min(config3.inbound_debounce_ms, 1e4)) : undefined,
|
|
426957
427073
|
waitingBehavior: isWaitingBehavior(config3.waiting_behavior) ? config3.waiting_behavior : undefined,
|
|
@@ -427307,6 +427423,7 @@ function createAccountFromPatch(channelId, accountId, patch2) {
|
|
|
427307
427423
|
defaultPermissionMode: normalizedPatch.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
427308
427424
|
transcribeVoice: normalizedPatch.transcribeVoice === true,
|
|
427309
427425
|
listenMode: normalizedPatch.listenMode === true,
|
|
427426
|
+
mentionOnlyChannels: [...normalizedPatch.mentionOnlyChannels ?? []],
|
|
427310
427427
|
allowBots: normalizedPatch.allowBots ?? false,
|
|
427311
427428
|
dmPolicy: normalizedPatch.dmPolicy ?? "open",
|
|
427312
427429
|
allowedUsers: normalizedPatch.allowedUsers ?? [],
|
|
@@ -427423,6 +427540,9 @@ function mergeAccountPatch(existing, patch2) {
|
|
|
427423
427540
|
defaultPermissionMode: normalizedPatch.defaultPermissionMode ?? existing.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
427424
427541
|
transcribeVoice: normalizedPatch.transcribeVoice ?? existing.transcribeVoice ?? false,
|
|
427425
427542
|
listenMode: normalizedPatch.listenMode ?? existing.listenMode ?? false,
|
|
427543
|
+
mentionOnlyChannels: [
|
|
427544
|
+
...normalizedPatch.mentionOnlyChannels ?? existing.mentionOnlyChannels ?? []
|
|
427545
|
+
],
|
|
427426
427546
|
allowBots: normalizedPatch.allowBots ?? existing.allowBots ?? false,
|
|
427427
427547
|
dmPolicy: normalizedPatch.dmPolicy ?? existing.dmPolicy,
|
|
427428
427548
|
allowedUsers: normalizedPatch.allowedUsers ?? existing.allowedUsers,
|
|
@@ -427616,6 +427736,7 @@ function toAccountSnapshot(account) {
|
|
|
427616
427736
|
defaultPermissionMode: account.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
427617
427737
|
transcribeVoice: account.transcribeVoice === true,
|
|
427618
427738
|
listenMode: account.listenMode === true,
|
|
427739
|
+
mentionOnlyChannels: [...account.mentionOnlyChannels ?? []],
|
|
427619
427740
|
allowBots: account.allowBots ?? false,
|
|
427620
427741
|
createdAt: account.createdAt,
|
|
427621
427742
|
updatedAt: account.updatedAt
|
|
@@ -427776,6 +427897,7 @@ function getChannelConfigSnapshot(channelId, accountId) {
|
|
|
427776
427897
|
defaultPermissionMode: account.defaultPermissionMode ?? DEFAULT_SLACK_PERMISSION_MODE,
|
|
427777
427898
|
transcribeVoice: account.transcribeVoice === true,
|
|
427778
427899
|
listenMode: account.listenMode === true,
|
|
427900
|
+
mentionOnlyChannels: [...account.mentionOnlyChannels ?? []],
|
|
427779
427901
|
allowBots: account.allowBots ?? false
|
|
427780
427902
|
};
|
|
427781
427903
|
}
|
|
@@ -428299,6 +428421,7 @@ async function setChannelConfigLive(channelId, patch2, accountId) {
|
|
|
428299
428421
|
threadPolicyByChannel: normalizedPatch.threadPolicyByChannel,
|
|
428300
428422
|
acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction,
|
|
428301
428423
|
listenMode: normalizedPatch.listenMode,
|
|
428424
|
+
mentionOnlyChannels: normalizedPatch.mentionOnlyChannels,
|
|
428302
428425
|
allowBots: normalizedPatch.allowBots,
|
|
428303
428426
|
removeStaleRoutes: normalizedPatch.removeStaleRoutes,
|
|
428304
428427
|
inboundDebounceMs: normalizedPatch.inboundDebounceMs,
|
|
@@ -428336,6 +428459,7 @@ async function setChannelConfigLive(channelId, patch2, accountId) {
|
|
|
428336
428459
|
threadPolicyByChannel: normalizedPatch.threadPolicyByChannel,
|
|
428337
428460
|
acknowledgeMessageReaction: normalizedPatch.acknowledgeMessageReaction,
|
|
428338
428461
|
listenMode: normalizedPatch.listenMode,
|
|
428462
|
+
mentionOnlyChannels: normalizedPatch.mentionOnlyChannels,
|
|
428339
428463
|
allowBots: normalizedPatch.allowBots,
|
|
428340
428464
|
removeStaleRoutes: normalizedPatch.removeStaleRoutes,
|
|
428341
428465
|
inboundDebounceMs: normalizedPatch.inboundDebounceMs,
|
|
@@ -429992,6 +430116,9 @@ function isConnectOAuthProvider(provider) {
|
|
|
429992
430116
|
function isConnectBedrockProvider(provider) {
|
|
429993
430117
|
return provider.byokProvider.providerType === "bedrock" || provider.byokProvider.providerType === "amazon-bedrock";
|
|
429994
430118
|
}
|
|
430119
|
+
function isConnectBaseURLRequired(provider) {
|
|
430120
|
+
return provider.byokProvider.fields?.some((field) => field.key === "baseUrl" && field.required !== false) === true;
|
|
430121
|
+
}
|
|
429995
430122
|
function isConnectApiKeyProvider(provider) {
|
|
429996
430123
|
return !isConnectOAuthProvider(provider) && !isConnectBedrockProvider(provider);
|
|
429997
430124
|
}
|
|
@@ -430049,6 +430176,7 @@ function formatUsage() {
|
|
|
430049
430176
|
" letta connect codex --method device-code",
|
|
430050
430177
|
" letta connect anthropic <api_key>",
|
|
430051
430178
|
" letta connect openai --api-key <api_key>",
|
|
430179
|
+
" letta connect openai-compatible --base-url http://localhost:8000/v1 [--api-key <api_key>]",
|
|
430052
430180
|
" letta connect ollama --base-url http://192.168.1.50:11434/v1",
|
|
430053
430181
|
" letta connect lmstudio --base-url http://127.0.0.1:1234/v1 --timeout 600s",
|
|
430054
430182
|
" letta connect llama-cpp --base-url http://localhost:8080/v1",
|
|
@@ -430262,6 +430390,10 @@ Provider '${providerName}' saved.`);
|
|
|
430262
430390
|
io.stderr(getErrorMessage2(error54));
|
|
430263
430391
|
return 1;
|
|
430264
430392
|
}
|
|
430393
|
+
if (isConnectBaseURLRequired(provider) && !connectionOptions.baseURL?.trim()) {
|
|
430394
|
+
io.stderr(`Missing base URL for ${provider.canonical}. Pass --base-url <url>.`);
|
|
430395
|
+
return 1;
|
|
430396
|
+
}
|
|
430265
430397
|
apiKey ||= defaultConnectApiKey(provider) ?? "";
|
|
430266
430398
|
if (!apiKey && isConnectZaiBaseProvider(provider)) {
|
|
430267
430399
|
io.stdout(`Do you have a Z.ai Coding plan?
|
|
@@ -438839,6 +438971,100 @@ var init_cron = __esm(async () => {
|
|
|
438839
438971
|
await init_scheduler();
|
|
438840
438972
|
});
|
|
438841
438973
|
|
|
438974
|
+
// src/backend/api/environments.ts
|
|
438975
|
+
var exports_environments2 = {};
|
|
438976
|
+
__export(exports_environments2, {
|
|
438977
|
+
sendEnvironmentMessage: () => sendEnvironmentMessage,
|
|
438978
|
+
resolveEnvironmentConnectionId: () => resolveEnvironmentConnectionId,
|
|
438979
|
+
resolveAgentSandboxConnectionId: () => resolveAgentSandboxConnectionId,
|
|
438980
|
+
listEnvironments: () => listEnvironments,
|
|
438981
|
+
isEnvironmentOnline: () => isEnvironmentOnline,
|
|
438982
|
+
getEnvironmentConnection: () => getEnvironmentConnection,
|
|
438983
|
+
describeEnvironment: () => describeEnvironment,
|
|
438984
|
+
createAgentSandbox: () => createAgentSandbox
|
|
438985
|
+
});
|
|
438986
|
+
async function listEnvironments(options3 = {}) {
|
|
438987
|
+
return apiRequest("GET", "/v1/environments", undefined, {
|
|
438988
|
+
query: {
|
|
438989
|
+
limit: options3.limit,
|
|
438990
|
+
after: options3.after,
|
|
438991
|
+
onlineOnly: options3.onlineOnly
|
|
438992
|
+
}
|
|
438993
|
+
});
|
|
438994
|
+
}
|
|
438995
|
+
async function sendEnvironmentMessage(connectionId, body3) {
|
|
438996
|
+
return apiRequest("POST", `/v1/environments/${encodeURIComponent(connectionId)}/messages`, body3);
|
|
438997
|
+
}
|
|
438998
|
+
async function getEnvironmentConnection(deviceId) {
|
|
438999
|
+
return apiRequest("GET", `/v1/environments/${encodeURIComponent(deviceId)}`);
|
|
439000
|
+
}
|
|
439001
|
+
async function createAgentSandbox(agentId) {
|
|
439002
|
+
return apiRequest("POST", `/v1/agents/${encodeURIComponent(agentId)}/sandboxes`, {});
|
|
439003
|
+
}
|
|
439004
|
+
function isEnvironmentOnline(environment2) {
|
|
439005
|
+
return typeof environment2.connectionId === "string" && environment2.connectionId.length > 0 && typeof environment2.lastHeartbeat === "number" && Date.now() - environment2.lastHeartbeat < 120000;
|
|
439006
|
+
}
|
|
439007
|
+
function describeEnvironment(environment2) {
|
|
439008
|
+
const status = isEnvironmentOnline(environment2) ? "online" : "offline";
|
|
439009
|
+
return `${environment2.connectionName} (${environment2.deviceId}, ${status})`;
|
|
439010
|
+
}
|
|
439011
|
+
async function resolveEnvironmentConnectionId(selector) {
|
|
439012
|
+
const trimmed = selector.trim();
|
|
439013
|
+
if (!trimmed) {
|
|
439014
|
+
throw new Error("Environment selector must not be empty");
|
|
439015
|
+
}
|
|
439016
|
+
const response = await listEnvironments({ limit: 100 });
|
|
439017
|
+
const matches2 = response.connections.filter((environment3) => {
|
|
439018
|
+
return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
|
|
439019
|
+
});
|
|
439020
|
+
if (matches2.length === 0) {
|
|
439021
|
+
throw new Error(`Environment "${trimmed}" not found. Run \`letta environments list\` to discover available environments.`);
|
|
439022
|
+
}
|
|
439023
|
+
const onlineMatches = matches2.filter(isEnvironmentOnline);
|
|
439024
|
+
if (onlineMatches.length === 0) {
|
|
439025
|
+
throw new Error(`Environment "${trimmed}" is offline. Matched: ${matches2.map(describeEnvironment).join(", ")}`);
|
|
439026
|
+
}
|
|
439027
|
+
if (onlineMatches.length > 1) {
|
|
439028
|
+
throw new Error(`Environment "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
|
|
439029
|
+
}
|
|
439030
|
+
const environment2 = onlineMatches[0];
|
|
439031
|
+
if (!environment2) {
|
|
439032
|
+
throw new Error(`Environment "${trimmed}" is offline`);
|
|
439033
|
+
}
|
|
439034
|
+
if (!environment2.connectionId) {
|
|
439035
|
+
throw new Error(`Environment "${trimmed}" has no active connection id`);
|
|
439036
|
+
}
|
|
439037
|
+
return { connectionId: environment2.connectionId, environment: environment2 };
|
|
439038
|
+
}
|
|
439039
|
+
async function resolveAgentSandboxConnectionId(agentId, options3 = {}) {
|
|
439040
|
+
const timeoutMs = options3.timeoutMs ?? 3 * 60000;
|
|
439041
|
+
const pollIntervalMs = options3.pollIntervalMs ?? 2000;
|
|
439042
|
+
const sandbox = await createAgentSandbox(agentId);
|
|
439043
|
+
const deviceId = sandbox.deviceId || `sandbox-${agentId}`;
|
|
439044
|
+
const deadline = Date.now() + timeoutMs;
|
|
439045
|
+
let lastEnvironment = null;
|
|
439046
|
+
let lastError = null;
|
|
439047
|
+
while (Date.now() < deadline) {
|
|
439048
|
+
try {
|
|
439049
|
+
const environment2 = await getEnvironmentConnection(deviceId);
|
|
439050
|
+
lastEnvironment = environment2;
|
|
439051
|
+
if (isEnvironmentOnline(environment2) && environment2.connectionId) {
|
|
439052
|
+
return { connectionId: environment2.connectionId, environment: environment2 };
|
|
439053
|
+
}
|
|
439054
|
+
} catch (error54) {
|
|
439055
|
+
lastError = error54;
|
|
439056
|
+
}
|
|
439057
|
+
await new Promise((resolve31) => setTimeout(resolve31, pollIntervalMs));
|
|
439058
|
+
}
|
|
439059
|
+
if (lastEnvironment) {
|
|
439060
|
+
throw new Error(`Timed out waiting for cloud sandbox ${sandbox.connectionName} to come online. Last status: ${describeEnvironment(lastEnvironment)}`);
|
|
439061
|
+
}
|
|
439062
|
+
throw new Error(`Timed out waiting for cloud sandbox ${sandbox.connectionName} to register${lastError instanceof Error ? `: ${lastError.message}` : ""}`);
|
|
439063
|
+
}
|
|
439064
|
+
var init_environments2 = __esm(() => {
|
|
439065
|
+
init_request();
|
|
439066
|
+
});
|
|
439067
|
+
|
|
438842
439068
|
// src/cli/subcommands/cron-runner.ts
|
|
438843
439069
|
function isLocalAgent(agentId) {
|
|
438844
439070
|
return agentId.startsWith("agent-local-");
|
|
@@ -438881,7 +439107,7 @@ function validateTargetDevice(deviceId, environment2) {
|
|
|
438881
439107
|
if (deviceId === SYNTHETIC_CLOUD_DEVICE_ID) {
|
|
438882
439108
|
return {
|
|
438883
439109
|
ok: false,
|
|
438884
|
-
error: `"Cloud" is
|
|
439110
|
+
error: `"Cloud" is not a computer. Pass --runner cloud to run in the agent's Cloud sandbox.`
|
|
438885
439111
|
};
|
|
438886
439112
|
}
|
|
438887
439113
|
if (deviceId === SYNTHETIC_LOCAL_PLACEHOLDER_ID) {
|
|
@@ -438898,6 +439124,32 @@ function validateTargetDevice(deviceId, environment2) {
|
|
|
438898
439124
|
}
|
|
438899
439125
|
return { ok: true };
|
|
438900
439126
|
}
|
|
439127
|
+
async function resolveInferredTargetDevice(deviceId, lookupEnvironment) {
|
|
439128
|
+
if (deviceId.startsWith("sandbox-")) {
|
|
439129
|
+
return { kind: "cloud-sandbox" };
|
|
439130
|
+
}
|
|
439131
|
+
const environment2 = await lookupEnvironment();
|
|
439132
|
+
const basicValidity = validateTargetDevice(deviceId, environment2);
|
|
439133
|
+
if (!basicValidity.ok) {
|
|
439134
|
+
return {
|
|
439135
|
+
kind: "local-fallback",
|
|
439136
|
+
reason: "this computer is not connected to your Letta account"
|
|
439137
|
+
};
|
|
439138
|
+
}
|
|
439139
|
+
if (!environment2) {
|
|
439140
|
+
return {
|
|
439141
|
+
kind: "local-fallback",
|
|
439142
|
+
reason: "this computer is not connected to your Letta account"
|
|
439143
|
+
};
|
|
439144
|
+
}
|
|
439145
|
+
if (!isEnvironmentOnline(environment2)) {
|
|
439146
|
+
return {
|
|
439147
|
+
kind: "local-fallback",
|
|
439148
|
+
reason: "this computer's connection to Letta is not currently online"
|
|
439149
|
+
};
|
|
439150
|
+
}
|
|
439151
|
+
return { kind: "device" };
|
|
439152
|
+
}
|
|
438901
439153
|
function buildCloudScheduleInput(params) {
|
|
438902
439154
|
const notes = [];
|
|
438903
439155
|
let schedule;
|
|
@@ -438928,6 +439180,9 @@ function buildCloudScheduleInput(params) {
|
|
|
438928
439180
|
};
|
|
438929
439181
|
}
|
|
438930
439182
|
var CLOUD_EXECUTION_TARGET = "cloud-sandbox", SYNTHETIC_CLOUD_DEVICE_ID = "__letta_cloud__", SYNTHETIC_LOCAL_PLACEHOLDER_ID = "local", CLOUD_CRON_UTC_NOTE = "Recurring Cloud schedules currently interpret cron expressions in UTC (timezone support is tracked in LET-9815).", CLOUD_DEVICE_FALLBACK_NOTE = "If the target computer is offline when the schedule fires, execution falls back to the agent's cloud sandbox.";
|
|
439183
|
+
var init_cron_runner = __esm(() => {
|
|
439184
|
+
init_environments2();
|
|
439185
|
+
});
|
|
438931
439186
|
|
|
438932
439187
|
// src/cli/subcommands/cron-task-ref.ts
|
|
438933
439188
|
async function ensureSettingsForCloud() {
|
|
@@ -438977,103 +439232,10 @@ function printAmbiguousTaskName(name, matches2) {
|
|
|
438977
439232
|
var init_cron_task_ref = __esm(async () => {
|
|
438978
439233
|
init_schedules2();
|
|
438979
439234
|
init_backend_mode();
|
|
439235
|
+
init_cron_runner();
|
|
438980
439236
|
await init_cron();
|
|
438981
439237
|
});
|
|
438982
439238
|
|
|
438983
|
-
// src/backend/api/environments.ts
|
|
438984
|
-
var exports_environments2 = {};
|
|
438985
|
-
__export(exports_environments2, {
|
|
438986
|
-
sendEnvironmentMessage: () => sendEnvironmentMessage,
|
|
438987
|
-
resolveEnvironmentConnectionId: () => resolveEnvironmentConnectionId,
|
|
438988
|
-
resolveAgentSandboxConnectionId: () => resolveAgentSandboxConnectionId,
|
|
438989
|
-
listEnvironments: () => listEnvironments,
|
|
438990
|
-
isEnvironmentOnline: () => isEnvironmentOnline,
|
|
438991
|
-
getEnvironmentConnection: () => getEnvironmentConnection,
|
|
438992
|
-
describeEnvironment: () => describeEnvironment,
|
|
438993
|
-
createAgentSandbox: () => createAgentSandbox
|
|
438994
|
-
});
|
|
438995
|
-
async function listEnvironments(options3 = {}) {
|
|
438996
|
-
return apiRequest("GET", "/v1/environments", undefined, {
|
|
438997
|
-
query: {
|
|
438998
|
-
limit: options3.limit,
|
|
438999
|
-
after: options3.after,
|
|
439000
|
-
onlineOnly: options3.onlineOnly
|
|
439001
|
-
}
|
|
439002
|
-
});
|
|
439003
|
-
}
|
|
439004
|
-
async function sendEnvironmentMessage(connectionId, body3) {
|
|
439005
|
-
return apiRequest("POST", `/v1/environments/${encodeURIComponent(connectionId)}/messages`, body3);
|
|
439006
|
-
}
|
|
439007
|
-
async function getEnvironmentConnection(deviceId) {
|
|
439008
|
-
return apiRequest("GET", `/v1/environments/${encodeURIComponent(deviceId)}`);
|
|
439009
|
-
}
|
|
439010
|
-
async function createAgentSandbox(agentId) {
|
|
439011
|
-
return apiRequest("POST", `/v1/agents/${encodeURIComponent(agentId)}/sandboxes`, {});
|
|
439012
|
-
}
|
|
439013
|
-
function isEnvironmentOnline(environment2) {
|
|
439014
|
-
return typeof environment2.connectionId === "string" && environment2.connectionId.length > 0 && typeof environment2.lastHeartbeat === "number" && Date.now() - environment2.lastHeartbeat < 120000;
|
|
439015
|
-
}
|
|
439016
|
-
function describeEnvironment(environment2) {
|
|
439017
|
-
const status = isEnvironmentOnline(environment2) ? "online" : "offline";
|
|
439018
|
-
return `${environment2.connectionName} (${environment2.deviceId}, ${status})`;
|
|
439019
|
-
}
|
|
439020
|
-
async function resolveEnvironmentConnectionId(selector) {
|
|
439021
|
-
const trimmed = selector.trim();
|
|
439022
|
-
if (!trimmed) {
|
|
439023
|
-
throw new Error("Environment selector must not be empty");
|
|
439024
|
-
}
|
|
439025
|
-
const response = await listEnvironments({ limit: 100 });
|
|
439026
|
-
const matches2 = response.connections.filter((environment3) => {
|
|
439027
|
-
return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
|
|
439028
|
-
});
|
|
439029
|
-
if (matches2.length === 0) {
|
|
439030
|
-
throw new Error(`Environment "${trimmed}" not found. Run \`letta environments list\` to discover available environments.`);
|
|
439031
|
-
}
|
|
439032
|
-
const onlineMatches = matches2.filter(isEnvironmentOnline);
|
|
439033
|
-
if (onlineMatches.length === 0) {
|
|
439034
|
-
throw new Error(`Environment "${trimmed}" is offline. Matched: ${matches2.map(describeEnvironment).join(", ")}`);
|
|
439035
|
-
}
|
|
439036
|
-
if (onlineMatches.length > 1) {
|
|
439037
|
-
throw new Error(`Environment "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
|
|
439038
|
-
}
|
|
439039
|
-
const environment2 = onlineMatches[0];
|
|
439040
|
-
if (!environment2) {
|
|
439041
|
-
throw new Error(`Environment "${trimmed}" is offline`);
|
|
439042
|
-
}
|
|
439043
|
-
if (!environment2.connectionId) {
|
|
439044
|
-
throw new Error(`Environment "${trimmed}" has no active connection id`);
|
|
439045
|
-
}
|
|
439046
|
-
return { connectionId: environment2.connectionId, environment: environment2 };
|
|
439047
|
-
}
|
|
439048
|
-
async function resolveAgentSandboxConnectionId(agentId, options3 = {}) {
|
|
439049
|
-
const timeoutMs = options3.timeoutMs ?? 3 * 60000;
|
|
439050
|
-
const pollIntervalMs = options3.pollIntervalMs ?? 2000;
|
|
439051
|
-
const sandbox = await createAgentSandbox(agentId);
|
|
439052
|
-
const deviceId = sandbox.deviceId || `sandbox-${agentId}`;
|
|
439053
|
-
const deadline = Date.now() + timeoutMs;
|
|
439054
|
-
let lastEnvironment = null;
|
|
439055
|
-
let lastError = null;
|
|
439056
|
-
while (Date.now() < deadline) {
|
|
439057
|
-
try {
|
|
439058
|
-
const environment2 = await getEnvironmentConnection(deviceId);
|
|
439059
|
-
lastEnvironment = environment2;
|
|
439060
|
-
if (isEnvironmentOnline(environment2) && environment2.connectionId) {
|
|
439061
|
-
return { connectionId: environment2.connectionId, environment: environment2 };
|
|
439062
|
-
}
|
|
439063
|
-
} catch (error54) {
|
|
439064
|
-
lastError = error54;
|
|
439065
|
-
}
|
|
439066
|
-
await new Promise((resolve31) => setTimeout(resolve31, pollIntervalMs));
|
|
439067
|
-
}
|
|
439068
|
-
if (lastEnvironment) {
|
|
439069
|
-
throw new Error(`Timed out waiting for cloud sandbox ${sandbox.connectionName} to come online. Last status: ${describeEnvironment(lastEnvironment)}`);
|
|
439070
|
-
}
|
|
439071
|
-
throw new Error(`Timed out waiting for cloud sandbox ${sandbox.connectionName} to register${lastError instanceof Error ? `: ${lastError.message}` : ""}`);
|
|
439072
|
-
}
|
|
439073
|
-
var init_environments2 = __esm(() => {
|
|
439074
|
-
init_request();
|
|
439075
|
-
});
|
|
439076
|
-
|
|
439077
439239
|
// src/cli/subcommands/cron.ts
|
|
439078
439240
|
import { parseArgs as parseArgs5 } from "node:util";
|
|
439079
439241
|
function printUsage4() {
|
|
@@ -439096,18 +439258,25 @@ Add options:
|
|
|
439096
439258
|
--cron <expr> Raw 5-field cron expression
|
|
439097
439259
|
--agent <id> Agent ID (defaults to LETTA_AGENT_ID)
|
|
439098
439260
|
--conversation <id> Conversation ID (defaults to LETTA_CONVERSATION_ID or "default")
|
|
439099
|
-
--runner <runner> Where the schedule lives and fires:
|
|
439100
|
-
|
|
439101
|
-
|
|
439102
|
-
|
|
439261
|
+
--runner <runner> Where the schedule lives and fires (normally omit:
|
|
439262
|
+
the default keeps the schedule running where it was
|
|
439263
|
+
created):
|
|
439264
|
+
cloud - durable Cloud schedule (default for cloud
|
|
439265
|
+
agents on Cloud-reachable runtimes:
|
|
439266
|
+
external listeners are targeted, managed
|
|
439267
|
+
sandboxes stay untargeted). Explicit
|
|
439268
|
+
--runner cloud always uses the Cloud sandbox
|
|
439103
439269
|
local - this device's scheduler (~/.letta/crons.json);
|
|
439104
439270
|
only fires while a session runs here (default
|
|
439105
|
-
for local-backend agents / self-hosted
|
|
439106
|
-
|
|
439107
|
-
|
|
439108
|
-
|
|
439109
|
-
|
|
439110
|
-
|
|
439271
|
+
for local-backend agents / self-hosted, and
|
|
439272
|
+
the fallback when Cloud scheduling cannot
|
|
439273
|
+
reach this computer)
|
|
439274
|
+
--computer <id> (cloud runner only) Override execution with a
|
|
439275
|
+
connected external environment (deviceId from
|
|
439276
|
+
\`letta environments list\`). Falls back to the Cloud
|
|
439277
|
+
sandbox if the computer is offline at fire time.
|
|
439278
|
+
Managed sandboxes and Desktop-local connections are
|
|
439279
|
+
not currently valid Cloud schedule targets.
|
|
439111
439280
|
|
|
439112
439281
|
List/filter options:
|
|
439113
439282
|
--agent <id> Filter by agent ID
|
|
@@ -439270,13 +439439,15 @@ async function handleAdd(values2) {
|
|
|
439270
439439
|
console.error("Error: no schedule specified.");
|
|
439271
439440
|
return 1;
|
|
439272
439441
|
}
|
|
439273
|
-
|
|
439442
|
+
let targetDeviceId = values2.computer?.trim() || undefined;
|
|
439274
439443
|
const resolved = await getRunnerForAgent(values2.runner, agentId);
|
|
439275
439444
|
if ("error" in resolved) {
|
|
439276
439445
|
console.error(`Error: ${resolved.error}`);
|
|
439277
439446
|
return 1;
|
|
439278
439447
|
}
|
|
439279
|
-
|
|
439448
|
+
let runner = resolved.runner;
|
|
439449
|
+
let localFallbackNote;
|
|
439450
|
+
if (targetDeviceId && runner !== "cloud") {
|
|
439280
439451
|
console.error("Error: --computer requires the cloud runner. Run `letta cron add` on the target computer itself (with --runner local) to schedule there locally.");
|
|
439281
439452
|
return 1;
|
|
439282
439453
|
}
|
|
@@ -439286,8 +439457,17 @@ async function handleAdd(values2) {
|
|
|
439286
439457
|
console.error(`Error: ${validity.error}`);
|
|
439287
439458
|
return 1;
|
|
439288
439459
|
}
|
|
439460
|
+
} else if (runner === "cloud" && values2.runner !== "cloud") {
|
|
439461
|
+
const inferredDeviceId = getRuntimeEnvironmentDeviceId();
|
|
439462
|
+
const resolution = await resolveInferredTargetDevice(inferredDeviceId, () => lookupEnvironmentForTarget(inferredDeviceId));
|
|
439463
|
+
if (resolution.kind === "device") {
|
|
439464
|
+
targetDeviceId = inferredDeviceId;
|
|
439465
|
+
} else if (resolution.kind === "local-fallback") {
|
|
439466
|
+
runner = "local";
|
|
439467
|
+
localFallbackNote = `This schedule is local to this computer (${resolution.reason}): it only fires while a Letta session is running here. For a schedule that fires regardless, pass --runner cloud (runs in the agent's cloud sandbox) or --computer <deviceId> (runs on a connected computer, from \`letta environments list\`).`;
|
|
439468
|
+
}
|
|
439289
439469
|
}
|
|
439290
|
-
if (
|
|
439470
|
+
if (runner === "cloud") {
|
|
439291
439471
|
return handleCloudAdd({
|
|
439292
439472
|
agentId,
|
|
439293
439473
|
conversationId,
|
|
@@ -439331,8 +439511,10 @@ async function handleAdd(values2) {
|
|
|
439331
439511
|
if (note) {
|
|
439332
439512
|
output.note = note;
|
|
439333
439513
|
}
|
|
439334
|
-
|
|
439335
|
-
|
|
439514
|
+
const fallbackWarning = localFallbackNote && recurring ? `${localFallbackNote} Recurring schedules on an unregistered computer stop firing whenever no session is running — strongly consider a durable alternative.` : localFallbackNote;
|
|
439515
|
+
const warnings = [fallbackWarning, result.warning].filter(Boolean);
|
|
439516
|
+
if (warnings.length > 0) {
|
|
439517
|
+
output.warning = warnings.join(" ");
|
|
439336
439518
|
}
|
|
439337
439519
|
console.log(JSON.stringify(output, null, 2));
|
|
439338
439520
|
console.error("Created local schedule: it only fires while a Letta session is running on this device.");
|
|
@@ -439694,9 +439876,11 @@ async function runCronSubcommand(argv) {
|
|
|
439694
439876
|
}
|
|
439695
439877
|
var CRON_OPTIONS;
|
|
439696
439878
|
var init_cron2 = __esm(async () => {
|
|
439879
|
+
init_client2();
|
|
439697
439880
|
init_request();
|
|
439698
439881
|
init_schedules2();
|
|
439699
439882
|
init_backend_mode();
|
|
439883
|
+
init_cron_runner();
|
|
439700
439884
|
await __promiseAll([
|
|
439701
439885
|
init_cron(),
|
|
439702
439886
|
init_cron_task_ref()
|
|
@@ -448016,6 +448200,9 @@ function rememberPendingApprovalBatchIds(runtime, pendingApprovals, batchId) {
|
|
|
448016
448200
|
for (const approval of pendingApprovals) {
|
|
448017
448201
|
if (approval.toolCallId) {
|
|
448018
448202
|
runtime.pendingApprovalBatchByToolCallId.set(approval.toolCallId, batchId);
|
|
448203
|
+
if (approval.messageId) {
|
|
448204
|
+
runtime.approvalMessageIdByToolCallId.set(approval.toolCallId, approval.messageId);
|
|
448205
|
+
}
|
|
448019
448206
|
}
|
|
448020
448207
|
}
|
|
448021
448208
|
}
|
|
@@ -448042,6 +448229,7 @@ function resolveRecoveryBatchId(runtime, pendingApprovals) {
|
|
|
448042
448229
|
function clearPendingApprovalBatchIds(runtime, approvals) {
|
|
448043
448230
|
for (const approval of approvals) {
|
|
448044
448231
|
runtime.pendingApprovalBatchByToolCallId.delete(approval.toolCallId);
|
|
448232
|
+
runtime.approvalMessageIdByToolCallId.delete(approval.toolCallId);
|
|
448045
448233
|
}
|
|
448046
448234
|
}
|
|
448047
448235
|
function isValidApprovalResponseBody(value) {
|
|
@@ -448335,13 +448523,13 @@ var init_channel_service_validation = __esm(() => {
|
|
|
448335
448523
|
function isExperimentId(value) {
|
|
448336
448524
|
return typeof value === "string" && EXPERIMENT_IDS.has(value);
|
|
448337
448525
|
}
|
|
448338
|
-
function
|
|
448526
|
+
function isStringArray7(value) {
|
|
448339
448527
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
448340
448528
|
}
|
|
448341
448529
|
function isClientToolsetConfig(value) {
|
|
448342
448530
|
if (!isObjectRecord2(value))
|
|
448343
448531
|
return false;
|
|
448344
|
-
return (value.base === undefined || typeof value.base === "string" && TOOLSET_PREFERENCES.has(value.base)) && (value.include === undefined ||
|
|
448532
|
+
return (value.base === undefined || typeof value.base === "string" && TOOLSET_PREFERENCES.has(value.base)) && (value.include === undefined || isStringArray7(value.include));
|
|
448345
448533
|
}
|
|
448346
448534
|
function isStringRecord2(value) {
|
|
448347
448535
|
return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((item) => typeof item === "string");
|
|
@@ -448372,7 +448560,7 @@ function isInputCommand(value) {
|
|
|
448372
448560
|
}
|
|
448373
448561
|
const payload = candidate.payload;
|
|
448374
448562
|
if (payload.kind === "create_message") {
|
|
448375
|
-
return Array.isArray(payload.messages) && (payload.image_failure_mode === undefined || payload.image_failure_mode === "strict" || payload.image_failure_mode === "drop") && (payload.client_tool_allowlist === undefined ||
|
|
448563
|
+
return Array.isArray(payload.messages) && (payload.image_failure_mode === undefined || payload.image_failure_mode === "strict" || payload.image_failure_mode === "drop") && (payload.client_tool_allowlist === undefined || isStringArray7(payload.client_tool_allowlist)) && (payload.client_toolset === undefined || isClientToolsetConfig(payload.client_toolset)) && (payload.external_tool_scope_ids === undefined || isStringArray7(payload.external_tool_scope_ids)) && (payload.exclude_interactive_tools === undefined || typeof payload.exclude_interactive_tools === "boolean");
|
|
448376
448564
|
}
|
|
448377
448565
|
if (payload.kind === "approval_response") {
|
|
448378
448566
|
return isValidApprovalResponseBody(payload);
|
|
@@ -448397,9 +448585,9 @@ function legacyEnvironmentMessageToInputCommand(value) {
|
|
|
448397
448585
|
payload: {
|
|
448398
448586
|
kind: "create_message",
|
|
448399
448587
|
messages: candidate.messages,
|
|
448400
|
-
client_tool_allowlist:
|
|
448588
|
+
client_tool_allowlist: isStringArray7(candidate.clientToolAllowlist) ? candidate.clientToolAllowlist : undefined,
|
|
448401
448589
|
client_toolset: isClientToolsetConfig(candidate.clientToolset) ? candidate.clientToolset : undefined,
|
|
448402
|
-
external_tool_scope_ids:
|
|
448590
|
+
external_tool_scope_ids: isStringArray7(candidate.externalToolScopeIds) ? candidate.externalToolScopeIds : undefined
|
|
448403
448591
|
}
|
|
448404
448592
|
};
|
|
448405
448593
|
}
|
|
@@ -448431,7 +448619,7 @@ function getInvalidInputReason(value) {
|
|
|
448431
448619
|
reason: "Protocol violation: input.payload.image_failure_mode must be strict or drop"
|
|
448432
448620
|
};
|
|
448433
448621
|
}
|
|
448434
|
-
if (payload.client_tool_allowlist !== undefined && !
|
|
448622
|
+
if (payload.client_tool_allowlist !== undefined && !isStringArray7(payload.client_tool_allowlist)) {
|
|
448435
448623
|
return {
|
|
448436
448624
|
runtime: candidate.runtime,
|
|
448437
448625
|
reason: "Protocol violation: input.payload.client_tool_allowlist must be string[]"
|
|
@@ -448449,7 +448637,7 @@ function getInvalidInputReason(value) {
|
|
|
448449
448637
|
reason: "Protocol violation: input.payload.exclude_interactive_tools must be boolean"
|
|
448450
448638
|
};
|
|
448451
448639
|
}
|
|
448452
|
-
if (payload.external_tool_scope_ids !== undefined && !
|
|
448640
|
+
if (payload.external_tool_scope_ids !== undefined && !isStringArray7(payload.external_tool_scope_ids)) {
|
|
448453
448641
|
return {
|
|
448454
448642
|
runtime: candidate.runtime,
|
|
448455
448643
|
reason: "Protocol violation: input.payload.external_tool_scope_ids must be string[]"
|
|
@@ -448811,7 +448999,7 @@ function isCreateAgentCommand(value) {
|
|
|
448811
448999
|
if (!value || typeof value !== "object")
|
|
448812
449000
|
return false;
|
|
448813
449001
|
const c = value;
|
|
448814
|
-
return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.tags === undefined ||
|
|
449002
|
+
return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.tags === undefined || isStringArray7(c.tags)) && (c.pin_global === undefined || typeof c.pin_global === "boolean");
|
|
448815
449003
|
}
|
|
448816
449004
|
function isAgentListCommand(value) {
|
|
448817
449005
|
if (!value || typeof value !== "object")
|
|
@@ -451068,6 +451256,7 @@ async function applyModelUpdateForRuntime(params) {
|
|
|
451068
451256
|
conversationId,
|
|
451069
451257
|
overrideModel: model.handle,
|
|
451070
451258
|
overrideProviderType: providerTypeFromModelSettings3(modelSettings) ?? inferProviderTypeFromRegistryHandle(model.handle) ?? null,
|
|
451259
|
+
modContext: createListenerAgentModContext(agentId),
|
|
451071
451260
|
modAdapters,
|
|
451072
451261
|
modEvents: createListenerModEvents(modAdapters)
|
|
451073
451262
|
});
|
|
@@ -451140,6 +451329,7 @@ async function applyToolsetUpdateForRuntime(params) {
|
|
|
451140
451329
|
const preparedToolContext = await prepareToolExecutionContextForScope({
|
|
451141
451330
|
agentId,
|
|
451142
451331
|
conversationId,
|
|
451332
|
+
modContext: createListenerAgentModContext(agentId),
|
|
451143
451333
|
modAdapters,
|
|
451144
451334
|
modEvents: createListenerModEvents(modAdapters)
|
|
451145
451335
|
});
|
|
@@ -452274,7 +452464,7 @@ function emitInterruptToolReturnMessage(socket, runtime, approvals, runId, uuidP
|
|
|
452274
452464
|
emitCanonicalMessageDelta(socket, runtime, {
|
|
452275
452465
|
type: "message",
|
|
452276
452466
|
message_type: "tool_return_message",
|
|
452277
|
-
id: `
|
|
452467
|
+
id: `synthetic-${uuidPrefix}-${crypto.randomUUID()}`,
|
|
452278
452468
|
date: new Date().toISOString(),
|
|
452279
452469
|
run_id: resolvedRunId,
|
|
452280
452470
|
status: toolReturn.status,
|
|
@@ -452298,8 +452488,10 @@ function emitInterruptToolReturnMessage(socket, runtime, approvals, runId, uuidP
|
|
|
452298
452488
|
function emitToolExecutionStartedEvents(socket, runtime, params) {
|
|
452299
452489
|
const toolCalls = params.toolCalls ?? (params.toolCallIds ?? []).map((toolCallId) => ({ toolCallId }));
|
|
452300
452490
|
for (const toolCall of toolCalls) {
|
|
452491
|
+
const messageId2 = runtime.approvalMessageIdByToolCallId.get(toolCall.toolCallId);
|
|
452301
452492
|
const delta2 = {
|
|
452302
452493
|
...createLifecycleMessageBase("client_tool_start", params.runId),
|
|
452494
|
+
...messageId2 ? { id: messageId2 } : {},
|
|
452303
452495
|
tool_call_id: toolCall.toolCallId,
|
|
452304
452496
|
...toolCall.toolName ? { tool_name: toolCall.toolName } : {},
|
|
452305
452497
|
...toolCall.toolArgs ? { tool_args: toolCall.toolArgs } : {}
|
|
@@ -452313,8 +452505,10 @@ function emitToolExecutionStartedEvents(socket, runtime, params) {
|
|
|
452313
452505
|
function emitToolExecutionFinishedEvents(socket, runtime, params) {
|
|
452314
452506
|
const toolReturns = extractInterruptToolReturns(params.approvals);
|
|
452315
452507
|
for (const toolReturn of toolReturns) {
|
|
452508
|
+
const messageId2 = runtime.approvalMessageIdByToolCallId.get(toolReturn.tool_call_id);
|
|
452316
452509
|
const delta2 = {
|
|
452317
452510
|
...createLifecycleMessageBase("client_tool_end", params.runId),
|
|
452511
|
+
...messageId2 ? { id: messageId2 } : {},
|
|
452318
452512
|
tool_call_id: toolReturn.tool_call_id,
|
|
452319
452513
|
status: toolReturn.status
|
|
452320
452514
|
};
|
|
@@ -452326,8 +452520,10 @@ function emitToolExecutionFinishedEvents(socket, runtime, params) {
|
|
|
452326
452520
|
}
|
|
452327
452521
|
function emitToolExecutionAbortedEvents(socket, runtime, params) {
|
|
452328
452522
|
for (const toolCallId of params.toolCallIds) {
|
|
452523
|
+
const messageId2 = runtime.approvalMessageIdByToolCallId.get(toolCallId);
|
|
452329
452524
|
const delta2 = {
|
|
452330
452525
|
...createLifecycleMessageBase("client_tool_end", params.runId),
|
|
452526
|
+
...messageId2 ? { id: messageId2 } : {},
|
|
452331
452527
|
tool_call_id: toolCallId,
|
|
452332
452528
|
status: "error"
|
|
452333
452529
|
};
|
|
@@ -452387,7 +452583,7 @@ function createToolExecutionOutputEmitter(socket, runtime, params) {
|
|
|
452387
452583
|
}
|
|
452388
452584
|
const existing = outputByToolCallId.get(toolCallId);
|
|
452389
452585
|
const outputState = existing ?? {
|
|
452390
|
-
messageId: `
|
|
452586
|
+
messageId: `synthetic-tool-return-stream-${toolCallId}`,
|
|
452391
452587
|
stdout: "",
|
|
452392
452588
|
stderr: "",
|
|
452393
452589
|
dirty: false,
|
|
@@ -452655,13 +452851,24 @@ function getLoopErrorNoticeDecision(params) {
|
|
|
452655
452851
|
apiError
|
|
452656
452852
|
};
|
|
452657
452853
|
}
|
|
452658
|
-
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined
|
|
452854
|
+
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined, {
|
|
452855
|
+
surface: params.surface,
|
|
452856
|
+
unclassifiedFallback: params.unclassifiedFallback
|
|
452857
|
+
});
|
|
452659
452858
|
return {
|
|
452660
452859
|
visibility: "transcript",
|
|
452661
452860
|
message: formattedMessage,
|
|
452662
452861
|
apiError
|
|
452663
452862
|
};
|
|
452664
452863
|
}
|
|
452864
|
+
function getTranscriptLoopErrorMessage(params) {
|
|
452865
|
+
const decision = getLoopErrorNoticeDecision({
|
|
452866
|
+
...params,
|
|
452867
|
+
surface: "plain",
|
|
452868
|
+
unclassifiedFallback: "generic"
|
|
452869
|
+
});
|
|
452870
|
+
return decision.visibility === "transcript" ? decision.message : undefined;
|
|
452871
|
+
}
|
|
452665
452872
|
function emitLoopErrorNotice(socket, runtime, params) {
|
|
452666
452873
|
const decision = getLoopErrorNoticeDecision(params);
|
|
452667
452874
|
if (decision.visibility === "debug_only") {
|
|
@@ -454249,6 +454456,9 @@ class StreamProcessor {
|
|
|
454249
454456
|
toolName: "",
|
|
454250
454457
|
toolArgs: ""
|
|
454251
454458
|
};
|
|
454459
|
+
if ("id" in chunk && typeof chunk.id === "string" && chunk.id) {
|
|
454460
|
+
existing.messageId = chunk.id;
|
|
454461
|
+
}
|
|
454252
454462
|
if (toolCall.name) {
|
|
454253
454463
|
existing.toolName = toolCall.name;
|
|
454254
454464
|
}
|
|
@@ -454268,7 +454478,8 @@ class StreamProcessor {
|
|
|
454268
454478
|
return Array.from(this.pendingApprovals.values()).map((a2) => ({
|
|
454269
454479
|
toolCallId: a2.toolCallId,
|
|
454270
454480
|
toolName: a2.toolName,
|
|
454271
|
-
toolArgs: a2.toolArgs
|
|
454481
|
+
toolArgs: a2.toolArgs,
|
|
454482
|
+
...a2.messageId ? { messageId: a2.messageId } : {}
|
|
454272
454483
|
}));
|
|
454273
454484
|
}
|
|
454274
454485
|
}
|
|
@@ -454545,7 +454756,8 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
454545
454756
|
const approvals = allPending.map((a2) => ({
|
|
454546
454757
|
toolCallId: a2.toolCallId,
|
|
454547
454758
|
toolName: a2.toolName || "",
|
|
454548
|
-
toolArgs: a2.toolArgs || ""
|
|
454759
|
+
toolArgs: a2.toolArgs || "",
|
|
454760
|
+
...a2.messageId ? { messageId: a2.messageId } : {}
|
|
454549
454761
|
}));
|
|
454550
454762
|
const approval = approvals[0] || null;
|
|
454551
454763
|
streamProcessor.pendingApprovals.clear();
|
|
@@ -455231,23 +455443,27 @@ function finalizeHandledRecoveryTurn(runtime, socket, turnLease, params) {
|
|
|
455231
455443
|
}
|
|
455232
455444
|
const terminalStopReason = params.drainResult.stopReason || "error";
|
|
455233
455445
|
const runId = runtime.activeRunId;
|
|
455446
|
+
const noticeParams = {
|
|
455447
|
+
message: `Recovery continuation ended unexpectedly: ${terminalStopReason}`,
|
|
455448
|
+
agentId: params.agentId,
|
|
455449
|
+
conversationId: params.conversationId
|
|
455450
|
+
};
|
|
455234
455451
|
const transition = finishListenerTurn(runtime, turnLease, {
|
|
455235
455452
|
stopReason: terminalStopReason,
|
|
455236
455453
|
socket,
|
|
455237
455454
|
agentId: params.agentId,
|
|
455238
455455
|
conversationId: params.conversationId,
|
|
455239
|
-
turnId: params.turnId
|
|
455456
|
+
turnId: params.turnId,
|
|
455457
|
+
error: getTranscriptLoopErrorMessage(noticeParams)
|
|
455240
455458
|
});
|
|
455241
455459
|
if (!transition.finished) {
|
|
455242
455460
|
return transition;
|
|
455243
455461
|
}
|
|
455244
455462
|
emitLoopErrorNotice(socket, runtime, {
|
|
455245
|
-
|
|
455463
|
+
...noticeParams,
|
|
455246
455464
|
stopReason: terminalStopReason,
|
|
455247
455465
|
isTerminal: true,
|
|
455248
|
-
runId: runId || undefined
|
|
455249
|
-
agentId: params.agentId ?? undefined,
|
|
455250
|
-
conversationId: params.conversationId
|
|
455466
|
+
runId: runId || undefined
|
|
455251
455467
|
});
|
|
455252
455468
|
return transition;
|
|
455253
455469
|
}
|
|
@@ -455508,6 +455724,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
455508
455724
|
conversationId: recovered.conversationId,
|
|
455509
455725
|
workingDirectory,
|
|
455510
455726
|
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId),
|
|
455727
|
+
modContext: createListenerAgentModContext(recovered.agentId),
|
|
455511
455728
|
modAdapters,
|
|
455512
455729
|
modEvents: createListenerModEvents(modAdapters)
|
|
455513
455730
|
});
|
|
@@ -455603,13 +455820,17 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
455603
455820
|
recovered.pendingRequestIds = new Set(recovered.approvalsByRequestId.keys());
|
|
455604
455821
|
recovered.responsesByRequestId.clear();
|
|
455605
455822
|
}
|
|
455823
|
+
const stopReason = recoveryLease.signal.aborted ? "cancelled" : "error";
|
|
455606
455824
|
finishListenerTurn(runtime, recoveryLease, {
|
|
455607
|
-
stopReason
|
|
455825
|
+
stopReason,
|
|
455608
455826
|
socket,
|
|
455609
455827
|
agentId: recovered.agentId,
|
|
455610
455828
|
conversationId: recovered.conversationId,
|
|
455611
455829
|
turnId: `batch-recovered-${requestId}`,
|
|
455612
|
-
error:
|
|
455830
|
+
error: stopReason === "error" ? getTranscriptLoopErrorMessage({
|
|
455831
|
+
error: error54,
|
|
455832
|
+
message: error54 instanceof Error ? error54.message : String(error54)
|
|
455833
|
+
}) : undefined
|
|
455613
455834
|
});
|
|
455614
455835
|
throw error54;
|
|
455615
455836
|
}
|
|
@@ -455917,6 +456138,7 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
455917
456138
|
conversationId: recoveryConversationId,
|
|
455918
456139
|
workingDirectory: recoveryWorkingDirectory,
|
|
455919
456140
|
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, runtime.agentId, runtime.conversationId),
|
|
456141
|
+
modContext: createListenerAgentModContext(runtime.agentId),
|
|
455920
456142
|
modAdapters,
|
|
455921
456143
|
modEvents: createListenerModEvents(modAdapters)
|
|
455922
456144
|
});
|
|
@@ -459107,7 +459329,7 @@ async function emitListenerTurnStart(options3) {
|
|
|
459107
459329
|
sessionId: options3.conversationId,
|
|
459108
459330
|
workingDirectory: options3.workingDirectory,
|
|
459109
459331
|
permissionMode: options3.permissionMode ?? null,
|
|
459110
|
-
agent: options3.cachedAgent ??
|
|
459332
|
+
agent: options3.cachedAgent ?? { id: options3.agentId }
|
|
459111
459333
|
});
|
|
459112
459334
|
const event2 = {
|
|
459113
459335
|
agentId: options3.agentId,
|
|
@@ -459134,7 +459356,7 @@ async function emitListenerTurnEnd(options3) {
|
|
|
459134
459356
|
sessionId: options3.conversationId,
|
|
459135
459357
|
workingDirectory: options3.workingDirectory,
|
|
459136
459358
|
permissionMode: options3.permissionMode ?? null,
|
|
459137
|
-
agent: options3.cachedAgent ??
|
|
459359
|
+
agent: options3.cachedAgent ?? { id: options3.agentId }
|
|
459138
459360
|
});
|
|
459139
459361
|
const event2 = {
|
|
459140
459362
|
agentId: options3.agentId,
|
|
@@ -460227,8 +460449,10 @@ async function prepareListenerTurn(params) {
|
|
|
460227
460449
|
inboundUserTranscriptLines = buildInboundUserTranscriptLines(currentInput);
|
|
460228
460450
|
}
|
|
460229
460451
|
const modAdapters = await ensureListenerModAdaptersForAgent(runtime.listener, agentId);
|
|
460452
|
+
const environmentDeviceId = connectionId ? runtime.listener.connections.get(connectionId)?.options.deviceId : undefined;
|
|
460230
460453
|
const preparedToolContext = await prepareToolExecutionContextForScope({
|
|
460231
460454
|
connectionId,
|
|
460455
|
+
environmentDeviceId,
|
|
460232
460456
|
agentId,
|
|
460233
460457
|
conversationId,
|
|
460234
460458
|
clientToolset: msg.clientToolset,
|
|
@@ -460239,6 +460463,7 @@ async function prepareListenerTurn(params) {
|
|
|
460239
460463
|
permissionModeState,
|
|
460240
460464
|
skillSources: runtime.skillSources,
|
|
460241
460465
|
cachedAgent,
|
|
460466
|
+
modContext: createListenerAgentModContext(agentId),
|
|
460242
460467
|
modAdapters,
|
|
460243
460468
|
modEvents: createListenerModEvents(modAdapters)
|
|
460244
460469
|
});
|
|
@@ -460359,7 +460584,8 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
460359
460584
|
if (!agentId) {
|
|
460360
460585
|
finishTurn({
|
|
460361
460586
|
stopReason: "error",
|
|
460362
|
-
conversationId
|
|
460587
|
+
conversationId,
|
|
460588
|
+
error: getTranscriptLoopErrorMessage({ message: "Missing agent ID" })
|
|
460363
460589
|
});
|
|
460364
460590
|
return;
|
|
460365
460591
|
}
|
|
@@ -460732,24 +460958,29 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
460732
460958
|
}
|
|
460733
460959
|
const errorMessage2 = errorDetail2 || `Unexpected stop reason: ${stopReason}`;
|
|
460734
460960
|
const terminalRunId = runId || runtime.activeRunId || runErrorInfo2?.run_id;
|
|
460961
|
+
const noticeParams = {
|
|
460962
|
+
message: errorMessage2,
|
|
460963
|
+
agentId,
|
|
460964
|
+
conversationId,
|
|
460965
|
+
runErrorInfo: runErrorInfo2 ?? undefined,
|
|
460966
|
+
cancelRequested: turnAbortSignal.aborted,
|
|
460967
|
+
abortSignal: turnAbortSignal
|
|
460968
|
+
};
|
|
460969
|
+
const terminalError = getTranscriptLoopErrorMessage(noticeParams);
|
|
460735
460970
|
const transition = finishTurn({
|
|
460736
460971
|
stopReason: effectiveStopReason,
|
|
460737
460972
|
agentId,
|
|
460738
|
-
conversationId
|
|
460973
|
+
conversationId,
|
|
460974
|
+
error: terminalError
|
|
460739
460975
|
});
|
|
460740
460976
|
if (!transition.finished) {
|
|
460741
460977
|
break;
|
|
460742
460978
|
}
|
|
460743
460979
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
460744
|
-
|
|
460980
|
+
...noticeParams,
|
|
460745
460981
|
stopReason: effectiveStopReason,
|
|
460746
460982
|
isTerminal: true,
|
|
460747
|
-
runId: terminalRunId
|
|
460748
|
-
agentId,
|
|
460749
|
-
conversationId,
|
|
460750
|
-
runErrorInfo: runErrorInfo2 ?? undefined,
|
|
460751
|
-
cancelRequested: turnAbortSignal.aborted,
|
|
460752
|
-
abortSignal: turnAbortSignal
|
|
460983
|
+
runId: terminalRunId
|
|
460753
460984
|
});
|
|
460754
460985
|
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
460755
460986
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
@@ -460776,10 +461007,14 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
460776
461007
|
});
|
|
460777
461008
|
if (approvalResult.kind === "error") {
|
|
460778
461009
|
const terminalRunId = runId || runtime.activeRunId;
|
|
461010
|
+
const terminalError = getTranscriptLoopErrorMessage({
|
|
461011
|
+
message: approvalResult.message
|
|
461012
|
+
});
|
|
460779
461013
|
const transition = finishTurn({
|
|
460780
461014
|
stopReason: "error",
|
|
460781
461015
|
agentId,
|
|
460782
|
-
conversationId
|
|
461016
|
+
conversationId,
|
|
461017
|
+
error: terminalError
|
|
460783
461018
|
});
|
|
460784
461019
|
if (!transition.finished) {
|
|
460785
461020
|
return;
|
|
@@ -460877,24 +461112,29 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
460877
461112
|
}
|
|
460878
461113
|
const errorMessage2 = error54 instanceof Error ? error54.message : String(error54);
|
|
460879
461114
|
const terminalRunId = runtime.activeRunId;
|
|
461115
|
+
const noticeParams = {
|
|
461116
|
+
message: errorMessage2,
|
|
461117
|
+
agentId,
|
|
461118
|
+
conversationId,
|
|
461119
|
+
error: error54,
|
|
461120
|
+
cancelRequested: turnAbortSignal.aborted,
|
|
461121
|
+
abortSignal: turnAbortSignal
|
|
461122
|
+
};
|
|
461123
|
+
const terminalError = getTranscriptLoopErrorMessage(noticeParams);
|
|
460880
461124
|
const transition = finishTurn({
|
|
460881
461125
|
stopReason: "error",
|
|
460882
461126
|
agentId: agentId || null,
|
|
460883
|
-
conversationId
|
|
461127
|
+
conversationId,
|
|
461128
|
+
error: terminalError
|
|
460884
461129
|
});
|
|
460885
461130
|
if (!transition.finished) {
|
|
460886
461131
|
return;
|
|
460887
461132
|
}
|
|
460888
461133
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
460889
|
-
|
|
461134
|
+
...noticeParams,
|
|
460890
461135
|
stopReason: "error",
|
|
460891
461136
|
isTerminal: true,
|
|
460892
|
-
runId: terminalRunId
|
|
460893
|
-
agentId: agentId || undefined,
|
|
460894
|
-
conversationId,
|
|
460895
|
-
error: error54,
|
|
460896
|
-
cancelRequested: turnAbortSignal.aborted,
|
|
460897
|
-
abortSignal: turnAbortSignal
|
|
461137
|
+
runId: terminalRunId
|
|
460898
461138
|
});
|
|
460899
461139
|
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
460900
461140
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
@@ -460914,7 +461154,8 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
460914
461154
|
socket,
|
|
460915
461155
|
runId: runtime.activeRunId || msgRunIds[msgRunIds.length - 1],
|
|
460916
461156
|
agentId: agentId || null,
|
|
460917
|
-
conversationId
|
|
461157
|
+
conversationId,
|
|
461158
|
+
error: turnAbortSignal.aborted ? undefined : getTranscriptLoopErrorMessage({ message: "Unexpected turn failure" })
|
|
460918
461159
|
});
|
|
460919
461160
|
}
|
|
460920
461161
|
if (runtime.activeConnectionId === connectionId) {
|
|
@@ -466115,6 +466356,7 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
|
|
|
466115
466356
|
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
466116
466357
|
return;
|
|
466117
466358
|
}
|
|
466359
|
+
installExternalToolBridge(runtime);
|
|
466118
466360
|
const shouldStartHeartbeat = options3.startHeartbeat !== false;
|
|
466119
466361
|
const cronSchedulerDisabledByEnv = process.env.LETTA_DISABLE_CRON_SCHEDULER === "1";
|
|
466120
466362
|
const shouldStartCronScheduler = options3.startCronScheduler !== false && !cronSchedulerDisabledByEnv;
|
|
@@ -469394,6 +469636,9 @@ async function resolveListenerStartupMode(channelNames, channelsRequested = chan
|
|
|
469394
469636
|
if (channelsRequested) {
|
|
469395
469637
|
return { kind: "local-channels", serverUrl, backend: "self-hosted" };
|
|
469396
469638
|
}
|
|
469639
|
+
if (process.env.IGNORE_SELF_HOSTED_LISTENER_ERROR === "1") {
|
|
469640
|
+
return { kind: "remote", serverUrl };
|
|
469641
|
+
}
|
|
469397
469642
|
return { kind: "unsupported-self-hosted", serverUrl };
|
|
469398
469643
|
}
|
|
469399
469644
|
function getScopedChannelRestoreAgentScope() {
|
|
@@ -469542,7 +469787,7 @@ async function runListenSubcommand(argv) {
|
|
|
469542
469787
|
try {
|
|
469543
469788
|
const deviceId = settingsManager.getOrCreateDeviceId();
|
|
469544
469789
|
const startupMode = await resolveListenerStartupMode(channelNames, channelNames.length > 0 || restoreEnabledChannels);
|
|
469545
|
-
if (startupMode.kind === "unsupported-self-hosted"
|
|
469790
|
+
if (startupMode.kind === "unsupported-self-hosted") {
|
|
469546
469791
|
console.error(`Self-hosted listener registration is not available for ${startupMode.serverUrl}.`);
|
|
469547
469792
|
console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote environments.");
|
|
469548
469793
|
await flushListenerTelemetryEnd("listener_self_hosted_no_channels");
|
|
@@ -491886,7 +492131,7 @@ var init_mcp_client = __esm(() => {
|
|
|
491886
492131
|
init_streamableHttp();
|
|
491887
492132
|
DEFAULT_CLIENT_INFO = {
|
|
491888
492133
|
name: "letta-code",
|
|
491889
|
-
version: "0.30.
|
|
492134
|
+
version: "0.30.7"
|
|
491890
492135
|
};
|
|
491891
492136
|
});
|
|
491892
492137
|
|
|
@@ -523799,6 +524044,7 @@ function formatConnectUsage() {
|
|
|
523799
524044
|
" /connect codex",
|
|
523800
524045
|
" /connect anthropic <api_key>",
|
|
523801
524046
|
" /connect openai <api_key>",
|
|
524047
|
+
" /connect openai-compatible --base-url http://localhost:8000/v1 [--api-key <api_key>]",
|
|
523802
524048
|
" /connect lmstudio --base-url http://127.0.0.1:1234/v1 --timeout 600s",
|
|
523803
524049
|
" /connect bedrock iam --access-key <id> --secret-key <key> --region <region>",
|
|
523804
524050
|
" /connect bedrock profile --profile <name> --region <region>"
|
|
@@ -523876,7 +524122,7 @@ function formatApiKeyUsage(provider) {
|
|
|
523876
524122
|
`Usage: /connect ${provider.canonical} [api_key]`,
|
|
523877
524123
|
"",
|
|
523878
524124
|
`Connect to ${provider.byokProvider.displayName}. API key is optional for this local provider.`,
|
|
523879
|
-
"Optional: --base-url <url> --timeout <ms|duration|false>"
|
|
524125
|
+
isConnectBaseURLRequired(provider) ? "Required: --base-url <url>. Optional: --timeout <ms|duration|false>" : "Optional: --base-url <url> --timeout <ms|duration|false>"
|
|
523880
524126
|
].join(`
|
|
523881
524127
|
`);
|
|
523882
524128
|
}
|
|
@@ -524172,6 +524418,12 @@ Usage: /connect chatgpt [--name <provider-name>]`, false);
|
|
|
524172
524418
|
if (parsed.error) {
|
|
524173
524419
|
addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `${parsed.error}
|
|
524174
524420
|
|
|
524421
|
+
${formatApiKeyUsage(provider)}`, false);
|
|
524422
|
+
return;
|
|
524423
|
+
}
|
|
524424
|
+
if (isConnectBaseURLRequired(provider) && !parsed.baseURL?.trim()) {
|
|
524425
|
+
addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Missing required field: --base-url <url>.
|
|
524426
|
+
|
|
524175
524427
|
${formatApiKeyUsage(provider)}`, false);
|
|
524176
524428
|
return;
|
|
524177
524429
|
}
|
|
@@ -555619,9 +555871,8 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
555619
555871
|
const command = positionals[2];
|
|
555620
555872
|
if (values2.help) {
|
|
555621
555873
|
printHelp();
|
|
555622
|
-
|
|
555623
|
-
|
|
555624
|
-
await new Promise((resolve40) => setTimeout(resolve40, helpDelayMs));
|
|
555874
|
+
if (process.env.LETTA_TEST_WAIT_FOR_STARTUP_AUTO_UPDATE === "1") {
|
|
555875
|
+
await autoUpdatePromise;
|
|
555625
555876
|
}
|
|
555626
555877
|
process.exit(0);
|
|
555627
555878
|
}
|
|
@@ -558987,4 +559238,4 @@ function registerBunOAuthFlows() {
|
|
|
558987
559238
|
registerBunOAuthFlows();
|
|
558988
559239
|
await init_src5().then(() => exports_src2);
|
|
558989
559240
|
|
|
558990
|
-
//# debugId=
|
|
559241
|
+
//# debugId=4343FD443B24C00264756E2164756E21
|