@letta-ai/letta-code 0.30.8 → 0.30.9
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/gateway-core.js +8 -2
- package/dist/gateway-core.js.map +3 -3
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/message.d.ts.map +1 -1
- package/dist/types/backend/local/local-store.d.ts.map +1 -1
- package/dist/types/channels/gateway-core.d.ts.map +1 -1
- package/dist/types/cli/helpers/accumulator.d.ts +1 -0
- package/dist/types/cli/helpers/accumulator.d.ts.map +1 -1
- package/dist/types/cli/helpers/stream-terminal-eof-guard.d.ts +14 -0
- package/dist/types/cli/helpers/stream-terminal-eof-guard.d.ts.map +1 -0
- package/dist/types/cli/helpers/stream.d.ts +1 -0
- package/dist/types/cli/helpers/stream.d.ts.map +1 -1
- package/dist/types/mods/mod-engine.d.ts +3 -7
- package/dist/types/mods/mod-engine.d.ts.map +1 -1
- package/dist/types/telemetry/error-reporting.d.ts +7 -0
- package/dist/types/telemetry/error-reporting.d.ts.map +1 -1
- package/dist/types/telemetry/index.d.ts +10 -0
- package/dist/types/telemetry/index.d.ts.map +1 -1
- package/dist/types/tools/impl/shell-runner.d.ts.map +1 -1
- package/dist/types/types/protocol_v2.d.ts +8 -9
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/dist/types/utils/secrets.d.ts.map +1 -1
- package/letta.js +342 -87
- package/package.json +1 -1
- package/scripts/dev.cjs +1 -2
- package/scripts/source-file-size-baseline.json +9 -8
- package/scripts/test-home-preload.ts +66 -0
- package/skills/creating-mods/references/ui.md +11 -1
package/letta.js
CHANGED
|
@@ -3306,6 +3306,16 @@ function trackBoundaryError(options) {
|
|
|
3306
3306
|
recentChunks: options.recentChunks
|
|
3307
3307
|
});
|
|
3308
3308
|
}
|
|
3309
|
+
function trackEndTurnNoAssistant(params) {
|
|
3310
|
+
telemetry.trackError("end_turn_no_assistant", `end_turn fell back to ${params.fallbackKind}`, "headless_result_extraction", {
|
|
3311
|
+
modelId: params.modelHandle,
|
|
3312
|
+
runId: params.runId,
|
|
3313
|
+
isSubagent: params.isSubagent,
|
|
3314
|
+
subagentType: params.subagentType,
|
|
3315
|
+
modelHandle: params.modelHandle,
|
|
3316
|
+
fallbackKind: params.fallbackKind
|
|
3317
|
+
});
|
|
3318
|
+
}
|
|
3309
3319
|
var init_error_reporting = __esm(() => {
|
|
3310
3320
|
init_telemetry();
|
|
3311
3321
|
});
|
|
@@ -4084,6 +4094,10 @@ async function writeJsonFile(path2, data, options) {
|
|
|
4084
4094
|
var init_fs = () => {};
|
|
4085
4095
|
|
|
4086
4096
|
// src/utils/secrets.ts
|
|
4097
|
+
function scopeServiceName(name) {
|
|
4098
|
+
const testPrefix = process.env.LETTA_TEST_SECRETS_SERVICE_PREFIX?.trim();
|
|
4099
|
+
return testPrefix ? `${testPrefix}:${name}` : name;
|
|
4100
|
+
}
|
|
4087
4101
|
function getErrorMessage(error) {
|
|
4088
4102
|
return error instanceof Error ? error.message : String(error);
|
|
4089
4103
|
}
|
|
@@ -4245,7 +4259,7 @@ async function isKeychainAvailable() {
|
|
|
4245
4259
|
return false;
|
|
4246
4260
|
}
|
|
4247
4261
|
}
|
|
4248
|
-
var secrets, secretsAvailable = false, SERVICE_NAME
|
|
4262
|
+
var secrets, secretsAvailable = false, SERVICE_NAME, API_KEY_NAME = "letta-api-key", REFRESH_TOKEN_NAME = "letta-refresh-token", warnedSecretReadFailures, secretGetOverrideForTests = null;
|
|
4249
4263
|
var init_secrets = __esm(() => {
|
|
4250
4264
|
init_debug();
|
|
4251
4265
|
try {
|
|
@@ -4254,6 +4268,7 @@ var init_secrets = __esm(() => {
|
|
|
4254
4268
|
} catch {
|
|
4255
4269
|
secretsAvailable = false;
|
|
4256
4270
|
}
|
|
4271
|
+
SERVICE_NAME = scopeServiceName("letta-code");
|
|
4257
4272
|
warnedSecretReadFailures = new Set;
|
|
4258
4273
|
});
|
|
4259
4274
|
|
|
@@ -5461,7 +5476,7 @@ var package_default;
|
|
|
5461
5476
|
var init_package = __esm(() => {
|
|
5462
5477
|
package_default = {
|
|
5463
5478
|
name: "@letta-ai/letta-code",
|
|
5464
|
-
version: "0.30.
|
|
5479
|
+
version: "0.30.9",
|
|
5465
5480
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5466
5481
|
type: "module",
|
|
5467
5482
|
packageManager: "bun@1.3.0",
|
|
@@ -6441,7 +6456,13 @@ class TelemetryManager {
|
|
|
6441
6456
|
model_id: options?.modelId,
|
|
6442
6457
|
run_id: options?.runId,
|
|
6443
6458
|
recent_chunks: options?.recentChunks,
|
|
6444
|
-
debug_log_tail: debugLogFile.getTail()
|
|
6459
|
+
debug_log_tail: debugLogFile.getTail(),
|
|
6460
|
+
is_subagent: options?.isSubagent,
|
|
6461
|
+
subagent_type: options?.subagentType,
|
|
6462
|
+
model_handle: options?.modelHandle,
|
|
6463
|
+
fallback_kind: options?.fallbackKind,
|
|
6464
|
+
platform: process.platform,
|
|
6465
|
+
version: getVersion()
|
|
6445
6466
|
};
|
|
6446
6467
|
this.track("error", data);
|
|
6447
6468
|
}
|
|
@@ -154249,14 +154270,29 @@ function spawnWithLauncher(launcher, options3) {
|
|
|
154249
154270
|
stdio: ["ignore", "pipe", "pipe"],
|
|
154250
154271
|
detached: process.platform !== "win32"
|
|
154251
154272
|
});
|
|
154252
|
-
const
|
|
154273
|
+
const killProcessTree = (signal) => {
|
|
154253
154274
|
if (childProcess.pid) {
|
|
154275
|
+
if (process.platform === "win32") {
|
|
154276
|
+
const taskkill = spawn2("taskkill.exe", ["/pid", String(childProcess.pid), "/t", "/f"], {
|
|
154277
|
+
stdio: "ignore",
|
|
154278
|
+
windowsHide: true
|
|
154279
|
+
});
|
|
154280
|
+
taskkill.once("error", () => {
|
|
154281
|
+
try {
|
|
154282
|
+
childProcess.kill("SIGKILL");
|
|
154283
|
+
} catch {}
|
|
154284
|
+
});
|
|
154285
|
+
taskkill.once("close", (code2) => {
|
|
154286
|
+
if (code2 === 0)
|
|
154287
|
+
return;
|
|
154288
|
+
try {
|
|
154289
|
+
childProcess.kill("SIGKILL");
|
|
154290
|
+
} catch {}
|
|
154291
|
+
});
|
|
154292
|
+
return;
|
|
154293
|
+
}
|
|
154254
154294
|
try {
|
|
154255
|
-
|
|
154256
|
-
process.kill(-childProcess.pid, signal);
|
|
154257
|
-
} else {
|
|
154258
|
-
childProcess.kill(signal);
|
|
154259
|
-
}
|
|
154295
|
+
process.kill(-childProcess.pid, signal);
|
|
154260
154296
|
} catch {
|
|
154261
154297
|
try {
|
|
154262
154298
|
childProcess.kill(signal);
|
|
@@ -154268,20 +154304,28 @@ function spawnWithLauncher(launcher, options3) {
|
|
|
154268
154304
|
const stderrChunks = [];
|
|
154269
154305
|
let timedOut = false;
|
|
154270
154306
|
let killTimer = null;
|
|
154271
|
-
|
|
154272
|
-
|
|
154273
|
-
|
|
154274
|
-
|
|
154275
|
-
|
|
154276
|
-
|
|
154307
|
+
let completed = false;
|
|
154308
|
+
const terminateProcess = () => {
|
|
154309
|
+
if (process.platform === "win32") {
|
|
154310
|
+
killProcessTree("SIGKILL");
|
|
154311
|
+
return;
|
|
154312
|
+
}
|
|
154313
|
+
killProcessTree("SIGTERM");
|
|
154277
154314
|
if (!killTimer) {
|
|
154278
154315
|
killTimer = setTimeout(() => {
|
|
154279
|
-
if (
|
|
154280
|
-
|
|
154316
|
+
if (!completed) {
|
|
154317
|
+
killProcessTree("SIGKILL");
|
|
154281
154318
|
}
|
|
154282
|
-
},
|
|
154319
|
+
}, FORCE_KILL_GRACE_MS);
|
|
154283
154320
|
}
|
|
154284
154321
|
};
|
|
154322
|
+
const timeoutId = options3.timeoutMs ? setTimeout(() => {
|
|
154323
|
+
timedOut = true;
|
|
154324
|
+
terminateProcess();
|
|
154325
|
+
}, options3.timeoutMs) : null;
|
|
154326
|
+
const abortHandler = () => {
|
|
154327
|
+
terminateProcess();
|
|
154328
|
+
};
|
|
154285
154329
|
if (options3.signal) {
|
|
154286
154330
|
options3.signal.addEventListener("abort", abortHandler, { once: true });
|
|
154287
154331
|
}
|
|
@@ -154294,6 +154338,7 @@ function spawnWithLauncher(launcher, options3) {
|
|
|
154294
154338
|
options3.onOutput?.(chunk.toString("utf8"), "stderr");
|
|
154295
154339
|
});
|
|
154296
154340
|
childProcess.on("error", (err) => {
|
|
154341
|
+
completed = true;
|
|
154297
154342
|
if (timeoutId)
|
|
154298
154343
|
clearTimeout(timeoutId);
|
|
154299
154344
|
if (killTimer) {
|
|
@@ -154306,6 +154351,7 @@ function spawnWithLauncher(launcher, options3) {
|
|
|
154306
154351
|
reject(buildSpawnError(err, executable, options3.cwd));
|
|
154307
154352
|
});
|
|
154308
154353
|
childProcess.on("close", (code2) => {
|
|
154354
|
+
completed = true;
|
|
154309
154355
|
if (timeoutId)
|
|
154310
154356
|
clearTimeout(timeoutId);
|
|
154311
154357
|
if (killTimer) {
|
|
@@ -154340,7 +154386,7 @@ function spawnWithLauncher(launcher, options3) {
|
|
|
154340
154386
|
});
|
|
154341
154387
|
});
|
|
154342
154388
|
}
|
|
154343
|
-
var ShellExecutionError,
|
|
154389
|
+
var ShellExecutionError, FORCE_KILL_GRACE_MS = 2000;
|
|
154344
154390
|
var init_shell_runner = __esm(() => {
|
|
154345
154391
|
init_usable_directory();
|
|
154346
154392
|
init_worktree_ownership();
|
|
@@ -157771,9 +157817,6 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
|
|
|
157771
157817
|
}
|
|
157772
157818
|
}
|
|
157773
157819
|
const extraHeaders = {};
|
|
157774
|
-
if (process.env.LETTA_RESPONSES_WS === "1") {
|
|
157775
|
-
extraHeaders["X-Experimental-OpenAI-Responses-Websocket"] = "true";
|
|
157776
|
-
}
|
|
157777
157820
|
if (previousResponseId) {
|
|
157778
157821
|
extraHeaders[RESPONSE_STATE_HEADER] = encodeResponseStateHeader({
|
|
157779
157822
|
v: 1,
|
|
@@ -328456,7 +328499,7 @@ function createNoopModPanelHandle() {
|
|
|
328456
328499
|
update() {}
|
|
328457
328500
|
};
|
|
328458
328501
|
}
|
|
328459
|
-
function createLettaModApi(registry2, owner, capabilities, getClient2, onChange, onDiagnostic, builtinCommandIds, reservedToolNames, signal) {
|
|
328502
|
+
function createLettaModApi(registry2, owner, capabilities, getClient2, onChange, onDiagnostic, onNotification, builtinCommandIds, reservedToolNames, signal) {
|
|
328460
328503
|
const isLive = () => isOwnerLive(registry2, owner);
|
|
328461
328504
|
const guardLive = (capability) => {
|
|
328462
328505
|
if (isLive())
|
|
@@ -328766,11 +328809,16 @@ function createLettaModApi(registry2, owner, capabilities, getClient2, onChange,
|
|
|
328766
328809
|
},
|
|
328767
328810
|
unregister: unregisterPermission
|
|
328768
328811
|
},
|
|
328769
|
-
diagnostics: {
|
|
328770
|
-
report: reportDiagnostic
|
|
328771
|
-
},
|
|
328812
|
+
diagnostics: { report: reportDiagnostic },
|
|
328772
328813
|
ui: {
|
|
328773
328814
|
closePanel,
|
|
328815
|
+
notify(message) {
|
|
328816
|
+
if (!capabilities.ui.panels || !message.trim())
|
|
328817
|
+
return;
|
|
328818
|
+
if (!guardLive({ id: "notify", kind: "panel" }))
|
|
328819
|
+
return;
|
|
328820
|
+
onNotification?.(message.trim());
|
|
328821
|
+
},
|
|
328774
328822
|
openPanel(panel) {
|
|
328775
328823
|
if (!capabilities.ui.panels) {
|
|
328776
328824
|
return createNoopModPanelHandle();
|
|
@@ -328893,7 +328941,7 @@ async function loadLocalMods(options3) {
|
|
|
328893
328941
|
if (typeof factory !== "function") {
|
|
328894
328942
|
throw new Error("Mod must export a default function or activate() function");
|
|
328895
328943
|
}
|
|
328896
|
-
const dispose = await factory(createLettaModApi(registry2, owner, capabilities, getConfiguredClient, onChange, options3.onDiagnostic, builtinCommandIds, reservedToolNames, abortController.signal));
|
|
328944
|
+
const dispose = await factory(createLettaModApi(registry2, owner, capabilities, getConfiguredClient, onChange, options3.onDiagnostic, options3.onNotification, builtinCommandIds, reservedToolNames, abortController.signal));
|
|
328897
328945
|
if (typeof dispose === "function") {
|
|
328898
328946
|
registry2.disposers.push({
|
|
328899
328947
|
abortController,
|
|
@@ -356516,6 +356564,9 @@ function updateLocalConversationRecord(current, body, updatedAt) {
|
|
|
356516
356564
|
if (typeof bodyRecord.summary === "string" || bodyRecord.summary === null) {
|
|
356517
356565
|
next.summary = bodyRecord.summary;
|
|
356518
356566
|
}
|
|
356567
|
+
if (isStringArray2(bodyRecord.tags)) {
|
|
356568
|
+
next.tags = bodyRecord.tags;
|
|
356569
|
+
}
|
|
356519
356570
|
return next;
|
|
356520
356571
|
}
|
|
356521
356572
|
function normalizeAgentRecord(value, defaultAgentModel) {
|
|
@@ -412081,35 +412132,35 @@ function buildSlackConversationSummary(msg) {
|
|
|
412081
412132
|
if (msg.chatType === "direct") {
|
|
412082
412133
|
if (msg.threadId?.trim()) {
|
|
412083
412134
|
const preview2 = truncateChannelSummaryPreview(msg.text);
|
|
412084
|
-
return preview2 ? `
|
|
412135
|
+
return preview2 ? `DM thread with ${msg.senderName?.trim() || msg.senderId}: ${preview2}` : `DM thread with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412085
412136
|
}
|
|
412086
|
-
return `
|
|
412137
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412087
412138
|
}
|
|
412088
412139
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412089
412140
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412090
412141
|
if (preview)
|
|
412091
|
-
return `
|
|
412092
|
-
return `
|
|
412142
|
+
return `Thread${channelLabel}: ${preview}`;
|
|
412143
|
+
return `Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
412093
412144
|
}
|
|
412094
412145
|
function buildDiscordConversationSummary(msg) {
|
|
412095
412146
|
if (msg.chatType === "direct") {
|
|
412096
|
-
return `
|
|
412147
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412097
412148
|
}
|
|
412098
412149
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412099
412150
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412100
412151
|
if (preview)
|
|
412101
|
-
return `
|
|
412102
|
-
return `
|
|
412152
|
+
return `Thread${channelLabel}: ${preview}`;
|
|
412153
|
+
return `Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
412103
412154
|
}
|
|
412104
412155
|
function buildTelegramConversationSummary(msg) {
|
|
412105
412156
|
if (msg.chatType === "direct") {
|
|
412106
|
-
return `
|
|
412157
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412107
412158
|
}
|
|
412108
412159
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412109
412160
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412110
412161
|
if (preview)
|
|
412111
|
-
return `
|
|
412112
|
-
return `
|
|
412162
|
+
return `Topic${channelLabel}: ${preview}`;
|
|
412163
|
+
return `Topic${channelLabel || ` ${msg.chatId}`}`;
|
|
412113
412164
|
}
|
|
412114
412165
|
function buildWhatsAppConversationSummary(msg) {
|
|
412115
412166
|
if (msg.chatType === "direct") {
|
|
@@ -447354,7 +447405,7 @@ function isRuntimeStartCommand(value) {
|
|
|
447354
447405
|
if (!value || typeof value !== "object")
|
|
447355
447406
|
return false;
|
|
447356
447407
|
const c = value;
|
|
447357
|
-
return c.type === "runtime_start" && typeof c.request_id === "string" && (c.agent_id === undefined || typeof c.agent_id === "string") && (c.create_agent === undefined || isRuntimeStartCreateAgentOptions(c.create_agent)) && (c.conversation_id === undefined || typeof c.conversation_id === "string") && (c.create_conversation === undefined || isRuntimeStartCreateConversationOptions(c.create_conversation)) && (c.cwd === undefined || c.cwd === null || typeof c.cwd === "string") && (c.mode === undefined || isDevicePermissionMode(c.mode)) && (c.skill_sources === undefined || isSkillSourceArray(c.skill_sources)) && (c.preserve_skill_sources === undefined || typeof c.preserve_skill_sources === "boolean") && (c.client_info === undefined || isRuntimeStartClientInfo(c.client_info)) && (c.recover_approvals === undefined || typeof c.recover_approvals === "boolean") && (c.force_device_status === undefined || typeof c.force_device_status === "boolean") && (c.wait_for_replay === undefined || typeof c.wait_for_replay === "boolean") && (c.external_tools === undefined || Array.isArray(c.external_tools) && c.external_tools.every(isRuntimeStartExternalToolsGroup));
|
|
447408
|
+
return c.type === "runtime_start" && typeof c.request_id === "string" && (c.agent_id === undefined || typeof c.agent_id === "string") && (c.create_agent === undefined || isRuntimeStartCreateAgentOptions(c.create_agent)) && (c.conversation_id === undefined || typeof c.conversation_id === "string") && (c.create_conversation === undefined || isRuntimeStartCreateConversationOptions(c.create_conversation)) && (c.conversation_source_tags === undefined || isStringArray7(c.conversation_source_tags)) && (c.cwd === undefined || c.cwd === null || typeof c.cwd === "string") && (c.mode === undefined || isDevicePermissionMode(c.mode)) && (c.skill_sources === undefined || isSkillSourceArray(c.skill_sources)) && (c.preserve_skill_sources === undefined || typeof c.preserve_skill_sources === "boolean") && (c.client_info === undefined || isRuntimeStartClientInfo(c.client_info)) && (c.recover_approvals === undefined || typeof c.recover_approvals === "boolean") && (c.force_device_status === undefined || typeof c.force_device_status === "boolean") && (c.wait_for_replay === undefined || typeof c.wait_for_replay === "boolean") && (c.external_tools === undefined || Array.isArray(c.external_tools) && c.external_tools.every(isRuntimeStartExternalToolsGroup));
|
|
447358
447409
|
}
|
|
447359
447410
|
function isTerminalSpawnCommand(value) {
|
|
447360
447411
|
if (!value || typeof value !== "object")
|
|
@@ -450433,6 +450484,34 @@ async function resolveRuntimeStartConversation(parsed, agent2, created) {
|
|
|
450433
450484
|
created.conversation = true;
|
|
450434
450485
|
return conversation;
|
|
450435
450486
|
}
|
|
450487
|
+
function removeMatchingSourcePrefix(summary, sourceTags) {
|
|
450488
|
+
if (typeof summary !== "string")
|
|
450489
|
+
return summary;
|
|
450490
|
+
const match4 = summary.match(/^\s*\[([^\]]+)\]\s*/);
|
|
450491
|
+
if (!match4)
|
|
450492
|
+
return summary;
|
|
450493
|
+
const prefix = match4[1]?.trim().toLowerCase();
|
|
450494
|
+
const matchesSourceTag = sourceTags.some((tag) => LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG[tag] === prefix);
|
|
450495
|
+
return matchesSourceTag ? summary.slice(match4[0].length) : summary;
|
|
450496
|
+
}
|
|
450497
|
+
async function applyRuntimeStartConversationSourceTags(parsed, conversation) {
|
|
450498
|
+
const sourceTags = parsed.conversation_source_tags;
|
|
450499
|
+
if (conversation.id === "default" || !sourceTags?.length) {
|
|
450500
|
+
return conversation;
|
|
450501
|
+
}
|
|
450502
|
+
const currentTags = Reflect.get(conversation, "tags");
|
|
450503
|
+
const existingTags = Array.isArray(currentTags) ? currentTags.filter((tag) => typeof tag === "string") : [];
|
|
450504
|
+
const missingTags = sourceTags.filter((tag) => !existingTags.includes(tag));
|
|
450505
|
+
const summary = removeMatchingSourcePrefix(conversation.summary, sourceTags);
|
|
450506
|
+
const summaryChanged = summary !== conversation.summary;
|
|
450507
|
+
if (missingTags.length === 0 && !summaryChanged) {
|
|
450508
|
+
return conversation;
|
|
450509
|
+
}
|
|
450510
|
+
return getBackend().updateConversation(conversation.id, {
|
|
450511
|
+
...missingTags.length > 0 ? { tags: [...new Set([...existingTags, ...missingTags])] } : {},
|
|
450512
|
+
...summaryChanged ? { summary } : {}
|
|
450513
|
+
});
|
|
450514
|
+
}
|
|
450436
450515
|
async function applyRuntimeStartState(parsed, context3, scope, scopedRuntime) {
|
|
450437
450516
|
if (parsed.skill_sources === undefined && parsed.preserve_skill_sources !== true) {
|
|
450438
450517
|
scopedRuntime.skillSources = undefined;
|
|
@@ -450473,6 +450552,7 @@ async function handleRuntimeStartCommand(parsed, context3) {
|
|
|
450473
450552
|
validateRuntimeStartShape(parsed);
|
|
450474
450553
|
agent2 = await resolveRuntimeStartAgent(parsed, created);
|
|
450475
450554
|
conversation = await resolveRuntimeStartConversation(parsed, agent2, created);
|
|
450555
|
+
conversation = await applyRuntimeStartConversationSourceTags(parsed, conversation);
|
|
450476
450556
|
runtimeScope = buildRuntimeScope(agent2, conversation);
|
|
450477
450557
|
const { connectionId } = context3;
|
|
450478
450558
|
const assertConnectionOpen = () => {
|
|
@@ -450527,6 +450607,7 @@ function handleRuntimeStartProtocolCommand(parsed, context3) {
|
|
|
450527
450607
|
});
|
|
450528
450608
|
return true;
|
|
450529
450609
|
}
|
|
450610
|
+
var LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG;
|
|
450530
450611
|
var init_runtime_start = __esm(async () => {
|
|
450531
450612
|
init_create5();
|
|
450532
450613
|
init_create_agent_request();
|
|
@@ -450541,6 +450622,12 @@ var init_runtime_start = __esm(async () => {
|
|
|
450541
450622
|
init_external_tools(),
|
|
450542
450623
|
init_protocol_inbound()
|
|
450543
450624
|
]);
|
|
450625
|
+
LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG = {
|
|
450626
|
+
"channel:discord": "discord",
|
|
450627
|
+
"channel:slack": "slack",
|
|
450628
|
+
"channel:telegram": "telegram",
|
|
450629
|
+
"origin:schedule": "schedule"
|
|
450630
|
+
};
|
|
450544
450631
|
});
|
|
450545
450632
|
|
|
450546
450633
|
// src/websocket/listener/commands/settings.ts
|
|
@@ -451373,10 +451460,10 @@ function getRecoverableStatusNoticeVisibility(kind) {
|
|
|
451373
451460
|
return "transcript";
|
|
451374
451461
|
}
|
|
451375
451462
|
}
|
|
451376
|
-
function getRecoverableRetryNoticeVisibility(kind
|
|
451463
|
+
function getRecoverableRetryNoticeVisibility(kind) {
|
|
451377
451464
|
switch (kind) {
|
|
451378
451465
|
case "transient_provider_retry":
|
|
451379
|
-
return
|
|
451466
|
+
return "transcript";
|
|
451380
451467
|
default:
|
|
451381
451468
|
return "transcript";
|
|
451382
451469
|
}
|
|
@@ -451526,7 +451613,7 @@ function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
|
451526
451613
|
});
|
|
451527
451614
|
}
|
|
451528
451615
|
function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
451529
|
-
const visibility = getRecoverableRetryNoticeVisibility(params.kind
|
|
451616
|
+
const visibility = getRecoverableRetryNoticeVisibility(params.kind);
|
|
451530
451617
|
if (visibility === "debug_only") {
|
|
451531
451618
|
debugLog("recovery", `Debug-only retry notice (${params.kind}, attempt ${params.attempt}/${params.maxAttempts}): ${params.message}`);
|
|
451532
451619
|
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
@@ -453218,6 +453305,50 @@ var init_stream_resume = __esm(() => {
|
|
|
453218
453305
|
init_client2();
|
|
453219
453306
|
});
|
|
453220
453307
|
|
|
453308
|
+
// src/cli/helpers/stream-terminal-eof-guard.ts
|
|
453309
|
+
function getTerminalEofGraceMs() {
|
|
453310
|
+
const raw2 = process.env.LETTA_STREAM_TERMINAL_EOF_GRACE_MS;
|
|
453311
|
+
if (raw2) {
|
|
453312
|
+
const parsed = Number(raw2);
|
|
453313
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
453314
|
+
return parsed;
|
|
453315
|
+
}
|
|
453316
|
+
}
|
|
453317
|
+
return DEFAULT_TERMINAL_EOF_GRACE_MS;
|
|
453318
|
+
}
|
|
453319
|
+
function createTerminalEofGuard(context3) {
|
|
453320
|
+
let timer = null;
|
|
453321
|
+
let fired = false;
|
|
453322
|
+
return {
|
|
453323
|
+
arm: () => {
|
|
453324
|
+
if (timer) {
|
|
453325
|
+
clearTimeout(timer);
|
|
453326
|
+
}
|
|
453327
|
+
const graceMs = getTerminalEofGraceMs();
|
|
453328
|
+
timer = setTimeout(() => {
|
|
453329
|
+
fired = true;
|
|
453330
|
+
debugWarn("drainStream", "Terminal-EOF guard fired: stop_reason=%s received but stream did not end within %dms - aborting HTTP read", context3.getStopReason(), graceMs);
|
|
453331
|
+
telemetry.trackError("stream_terminal_eof_guard_fired", `Stream received stop_reason=${context3.getStopReason()} but HTTP body did not end within ${graceMs}ms`, "stream_drain", {
|
|
453332
|
+
runId: context3.getRunId() ?? undefined
|
|
453333
|
+
});
|
|
453334
|
+
context3.abortHttpRead();
|
|
453335
|
+
}, graceMs);
|
|
453336
|
+
},
|
|
453337
|
+
clear: () => {
|
|
453338
|
+
if (timer) {
|
|
453339
|
+
clearTimeout(timer);
|
|
453340
|
+
timer = null;
|
|
453341
|
+
}
|
|
453342
|
+
},
|
|
453343
|
+
fired: () => fired
|
|
453344
|
+
};
|
|
453345
|
+
}
|
|
453346
|
+
var DEFAULT_TERMINAL_EOF_GRACE_MS = 2000;
|
|
453347
|
+
var init_stream_terminal_eof_guard = __esm(() => {
|
|
453348
|
+
init_telemetry();
|
|
453349
|
+
init_debug();
|
|
453350
|
+
});
|
|
453351
|
+
|
|
453221
453352
|
// src/cli/helpers/stream.ts
|
|
453222
453353
|
function summarizeStreamForDebug(stream12) {
|
|
453223
453354
|
if (!stream12 || typeof stream12 !== "object") {
|
|
@@ -453283,6 +453414,11 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453283
453414
|
let fallbackError = null;
|
|
453284
453415
|
let lastChunkDebugSummary = "none";
|
|
453285
453416
|
let abortedViaListener = false;
|
|
453417
|
+
const terminalEofGuard = createTerminalEofGuard({
|
|
453418
|
+
getStopReason: () => streamProcessor.stopReason,
|
|
453419
|
+
getRunId: () => streamProcessor.lastRunId,
|
|
453420
|
+
abortHttpRead: () => abortStreamController(stream12, "terminal_eof_guard")
|
|
453421
|
+
});
|
|
453286
453422
|
const startAbortGen = buffers.abortGeneration || 0;
|
|
453287
453423
|
const abortHandler = () => {
|
|
453288
453424
|
abortedViaListener = true;
|
|
@@ -453323,6 +453459,9 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453323
453459
|
logTiming(`TTFT: ${formatDuration(ttft)} (from POST to first content)`);
|
|
453324
453460
|
}
|
|
453325
453461
|
const { shouldOutput, errorInfo, updatedApproval } = streamProcessor.processChunk(chunk);
|
|
453462
|
+
if (streamProcessor.stopReason !== null) {
|
|
453463
|
+
terminalEofGuard.arm();
|
|
453464
|
+
}
|
|
453326
453465
|
try {
|
|
453327
453466
|
chunkLog.append(chunk);
|
|
453328
453467
|
} catch {}
|
|
@@ -453397,6 +453536,7 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453397
453536
|
}
|
|
453398
453537
|
queueMicrotask(refresh);
|
|
453399
453538
|
} finally {
|
|
453539
|
+
terminalEofGuard.clear();
|
|
453400
453540
|
try {
|
|
453401
453541
|
chunkLog.flush();
|
|
453402
453542
|
} catch {}
|
|
@@ -453409,6 +453549,11 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453409
453549
|
if (!stopReason && streamProcessor.stopReason) {
|
|
453410
453550
|
stopReason = streamProcessor.stopReason;
|
|
453411
453551
|
}
|
|
453552
|
+
if (terminalEofGuard.fired()) {
|
|
453553
|
+
upsertStatusLine(buffers, `terminal-eof-${startTime}`, [
|
|
453554
|
+
"Stream did not close after completing, continued without waiting"
|
|
453555
|
+
]);
|
|
453556
|
+
}
|
|
453412
453557
|
if (abortedViaListener && !stopReason) {
|
|
453413
453558
|
stopReason = "cancelled";
|
|
453414
453559
|
markIncompleteToolsAsCancelled(buffers, true, "user_interrupt");
|
|
@@ -453462,7 +453607,8 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453462
453607
|
lastRunId: streamProcessor.lastRunId,
|
|
453463
453608
|
lastSeqId: streamProcessor.lastSeqId,
|
|
453464
453609
|
apiDurationMs,
|
|
453465
|
-
fallbackError
|
|
453610
|
+
fallbackError,
|
|
453611
|
+
terminalEofGuardFired: terminalEofGuard.fired()
|
|
453466
453612
|
};
|
|
453467
453613
|
}
|
|
453468
453614
|
async function drainStreamWithResume(stream12, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, resumePolicy) {
|
|
@@ -453655,6 +453801,7 @@ var init_stream = __esm(async () => {
|
|
|
453655
453801
|
init_tui_perf();
|
|
453656
453802
|
init_chunk_log();
|
|
453657
453803
|
init_stream_resume();
|
|
453804
|
+
init_stream_terminal_eof_guard();
|
|
453658
453805
|
await __promiseAll([
|
|
453659
453806
|
init_message(),
|
|
453660
453807
|
init_accumulator()
|
|
@@ -453835,6 +453982,62 @@ var init_approval_suggestions = __esm(async () => {
|
|
|
453835
453982
|
]);
|
|
453836
453983
|
});
|
|
453837
453984
|
|
|
453985
|
+
// src/websocket/listener/cloud-retry-message.ts
|
|
453986
|
+
function isRecord12(value) {
|
|
453987
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
453988
|
+
}
|
|
453989
|
+
function optionalString4(value) {
|
|
453990
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
453991
|
+
}
|
|
453992
|
+
function parseCloudRetryMessage(value) {
|
|
453993
|
+
if (!isRecord12(value) || value.message_type !== "retry_message") {
|
|
453994
|
+
return null;
|
|
453995
|
+
}
|
|
453996
|
+
const attempt = value.attempt;
|
|
453997
|
+
const maxAttempts = value.max_attempts;
|
|
453998
|
+
const delayMs = value.delay_ms;
|
|
453999
|
+
const retryKind = value.retry_kind;
|
|
454000
|
+
if (typeof value.message !== "string" || value.message.length === 0 || retryKind !== "provider_retry" && retryKind !== "transport_fallback" || typeof attempt !== "number" || !Number.isInteger(attempt) || attempt < 1 || typeof maxAttempts !== "number" || !Number.isInteger(maxAttempts) || maxAttempts < attempt || typeof delayMs !== "number" || !Number.isFinite(delayMs) || delayMs < 0 || typeof value.provider !== "string" || value.provider.length === 0) {
|
|
454001
|
+
return null;
|
|
454002
|
+
}
|
|
454003
|
+
return {
|
|
454004
|
+
message: value.message,
|
|
454005
|
+
retryKind,
|
|
454006
|
+
attempt,
|
|
454007
|
+
maxAttempts,
|
|
454008
|
+
delayMs,
|
|
454009
|
+
provider: value.provider,
|
|
454010
|
+
fromTransport: optionalString4(value.from_transport),
|
|
454011
|
+
toTransport: optionalString4(value.to_transport),
|
|
454012
|
+
errorCode: optionalString4(value.error_code),
|
|
454013
|
+
runId: optionalString4(value.run_id),
|
|
454014
|
+
stepId: optionalString4(value.step_id)
|
|
454015
|
+
};
|
|
454016
|
+
}
|
|
454017
|
+
function normalizeCloudRetryWireMessage(value) {
|
|
454018
|
+
const retry3 = parseCloudRetryMessage(value);
|
|
454019
|
+
if (!retry3) {
|
|
454020
|
+
return null;
|
|
454021
|
+
}
|
|
454022
|
+
return {
|
|
454023
|
+
...createLifecycleMessageBase("retry", retry3.runId),
|
|
454024
|
+
message: retry3.message,
|
|
454025
|
+
reason: "llm_api_error",
|
|
454026
|
+
attempt: retry3.attempt,
|
|
454027
|
+
max_attempts: retry3.maxAttempts,
|
|
454028
|
+
delay_ms: retry3.delayMs,
|
|
454029
|
+
retry_kind: retry3.retryKind,
|
|
454030
|
+
provider: retry3.provider,
|
|
454031
|
+
from_transport: retry3.fromTransport,
|
|
454032
|
+
to_transport: retry3.toTransport,
|
|
454033
|
+
error_code: retry3.errorCode,
|
|
454034
|
+
step_id: retry3.stepId
|
|
454035
|
+
};
|
|
454036
|
+
}
|
|
454037
|
+
var init_cloud_retry_message = __esm(async () => {
|
|
454038
|
+
await init_protocol_outbound();
|
|
454039
|
+
});
|
|
454040
|
+
|
|
453838
454041
|
// src/websocket/listener/turn-input-state.ts
|
|
453839
454042
|
function ensureTurnInputMessageOtids(messages) {
|
|
453840
454043
|
let didChange = false;
|
|
@@ -454111,7 +454314,7 @@ async function drainRecoveryStreamWithEmission(recoveryStream, socket, runtime,
|
|
|
454111
454314
|
});
|
|
454112
454315
|
}
|
|
454113
454316
|
if (shouldOutput) {
|
|
454114
|
-
const normalizedChunk = normalizeToolReturnWireMessage(chunk);
|
|
454317
|
+
const normalizedChunk = normalizeCloudRetryWireMessage(chunk) ?? normalizeToolReturnWireMessage(chunk);
|
|
454115
454318
|
if (normalizedChunk) {
|
|
454116
454319
|
emitCanonicalMessageDelta(socket, runtime, {
|
|
454117
454320
|
...normalizedChunk,
|
|
@@ -454558,6 +454761,7 @@ var init_recovery = __esm(async () => {
|
|
|
454558
454761
|
init_stream(),
|
|
454559
454762
|
init_toolset(),
|
|
454560
454763
|
init_approval_suggestions(),
|
|
454764
|
+
init_cloud_retry_message(),
|
|
454561
454765
|
init_continuation_input(),
|
|
454562
454766
|
init_interrupts(),
|
|
454563
454767
|
init_mod_adapter2(),
|
|
@@ -454610,16 +454814,17 @@ var init_approval_recovery = __esm(() => {
|
|
|
454610
454814
|
});
|
|
454611
454815
|
|
|
454612
454816
|
// src/websocket/listener/provider-fallback.ts
|
|
454613
|
-
function createProviderFallbackState(agent2) {
|
|
454817
|
+
function createProviderFallbackState(agent2, overrideModel) {
|
|
454614
454818
|
const llmConfig = agent2?.llm_config;
|
|
454615
454819
|
const model = llmConfig?.model;
|
|
454616
454820
|
if (!model) {
|
|
454617
|
-
return { sourceModelId: null, attempted: false };
|
|
454821
|
+
return { sourceModelId: null, attempted: false, overrideModel };
|
|
454618
454822
|
}
|
|
454619
454823
|
const modelInfo = getModelInfoForLlmConfig(model, llmConfig) ?? getModelInfo(model);
|
|
454620
454824
|
return {
|
|
454621
454825
|
sourceModelId: modelInfo?.id ?? model,
|
|
454622
|
-
attempted: false
|
|
454826
|
+
attempted: false,
|
|
454827
|
+
overrideModel
|
|
454623
454828
|
};
|
|
454624
454829
|
}
|
|
454625
454830
|
function maybeApplyProviderFallback(state, attempt) {
|
|
@@ -458040,17 +458245,18 @@ async function emitListenerTurnStart(options3) {
|
|
|
458040
458245
|
conversationId: options3.conversationId,
|
|
458041
458246
|
input: options3.input
|
|
458042
458247
|
};
|
|
458043
|
-
await createListenerModEvents(modAdapters).emit("turn_start", event2, context3);
|
|
458248
|
+
const emission = await createListenerModEvents(modAdapters).emit("turn_start", event2, context3);
|
|
458044
458249
|
const cancel = getTurnStartCancel(event2);
|
|
458045
458250
|
if (cancel) {
|
|
458046
458251
|
return { cancelled: true, reason: cancel.reason };
|
|
458047
458252
|
}
|
|
458048
458253
|
return {
|
|
458049
458254
|
cancelled: false,
|
|
458255
|
+
handlerCount: emission.handlerCount,
|
|
458050
458256
|
input: isTurnInputArray(event2.input) ? event2.input : options3.input
|
|
458051
458257
|
};
|
|
458052
458258
|
} catch {
|
|
458053
|
-
return { cancelled: false, input: options3.input };
|
|
458259
|
+
return { cancelled: false, handlerCount: 0, input: options3.input };
|
|
458054
458260
|
}
|
|
458055
458261
|
}
|
|
458056
458262
|
async function emitListenerTurnEnd(options3) {
|
|
@@ -459137,13 +459343,20 @@ async function prepareListenerTurn(params) {
|
|
|
459137
459343
|
workingDirectory,
|
|
459138
459344
|
permissionMode: permissionModeState.mode,
|
|
459139
459345
|
cachedAgent
|
|
459140
|
-
}) : { cancelled: false, input: messagesToSend };
|
|
459346
|
+
}) : { cancelled: false, handlerCount: 0, input: messagesToSend };
|
|
459141
459347
|
if (isInterrupted()) {
|
|
459142
459348
|
return { kind: "interrupted" };
|
|
459143
459349
|
}
|
|
459144
459350
|
if (turnStartEmission.cancelled) {
|
|
459145
459351
|
return { kind: "cancelled", reason: turnStartEmission.reason };
|
|
459146
459352
|
}
|
|
459353
|
+
let overrideModel;
|
|
459354
|
+
if (turnStartEmission.handlerCount > 0) {
|
|
459355
|
+
try {
|
|
459356
|
+
const conversation = await getBackend().retrieveConversation(conversationId);
|
|
459357
|
+
overrideModel = conversation.model ?? undefined;
|
|
459358
|
+
} catch {}
|
|
459359
|
+
}
|
|
459147
459360
|
const currentInput = ensureTurnInputMessageOtids(turnStartEmission.input);
|
|
459148
459361
|
const turnInput = createTurnInputState(currentInput, getInboundImageFailureModes({
|
|
459149
459362
|
imageFailureMode: msg.imageFailureMode,
|
|
@@ -459185,7 +459398,8 @@ async function prepareListenerTurn(params) {
|
|
|
459185
459398
|
pendingNormalizationInterruptedToolCallIds: [
|
|
459186
459399
|
...queuedInterruptedToolCallIds
|
|
459187
459400
|
],
|
|
459188
|
-
preparedToolContext
|
|
459401
|
+
preparedToolContext,
|
|
459402
|
+
...overrideModel ? { overrideModel } : {}
|
|
459189
459403
|
};
|
|
459190
459404
|
}
|
|
459191
459405
|
var init_turn_setup = __esm(async () => {
|
|
@@ -459338,7 +459552,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459338
459552
|
}
|
|
459339
459553
|
let turnInput = setup.turnInput;
|
|
459340
459554
|
const inboundUserTranscriptLines = setup.inboundUserTranscriptLines;
|
|
459341
|
-
const providerFallback = createProviderFallbackState(setup.getCachedAgent());
|
|
459555
|
+
const providerFallback = createProviderFallbackState(setup.getCachedAgent(), setup.overrideModel);
|
|
459342
459556
|
let pendingNormalizationInterruptedToolCallIds = setup.pendingNormalizationInterruptedToolCallIds;
|
|
459343
459557
|
const preparedToolContext = setup.preparedToolContext;
|
|
459344
459558
|
const buildSendOptions = () => ({
|
|
@@ -459430,7 +459644,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459430
459644
|
}
|
|
459431
459645
|
}
|
|
459432
459646
|
if (shouldOutput) {
|
|
459433
|
-
const normalizedChunk = normalizeToolReturnWireMessage(chunk);
|
|
459647
|
+
const normalizedChunk = normalizeCloudRetryWireMessage(chunk) ?? normalizeToolReturnWireMessage(chunk);
|
|
459434
459648
|
if (normalizedChunk) {
|
|
459435
459649
|
emitCanonicalMessageDelta(socket, runtime, {
|
|
459436
459650
|
...normalizedChunk,
|
|
@@ -459446,8 +459660,14 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459446
459660
|
const stopReason = result.stopReason;
|
|
459447
459661
|
const approvals = result.approvals || [];
|
|
459448
459662
|
const fallbackError = result.fallbackError ?? null;
|
|
459449
|
-
if (
|
|
459450
|
-
|
|
459663
|
+
if (result.terminalEofGuardFired) {
|
|
459664
|
+
emitStatusDelta(socket, runtime, {
|
|
459665
|
+
message: "Stream did not close after completing, continued without waiting",
|
|
459666
|
+
level: "warning",
|
|
459667
|
+
runId: runId || runtime.activeRunId,
|
|
459668
|
+
agentId,
|
|
459669
|
+
conversationId
|
|
459670
|
+
});
|
|
459451
459671
|
}
|
|
459452
459672
|
if (finishIfInterrupted(runId || runtime.activeRunId)) {
|
|
459453
459673
|
break;
|
|
@@ -459900,6 +460120,7 @@ var init_turn = __esm(async () => {
|
|
|
459900
460120
|
init_message(),
|
|
459901
460121
|
init_accumulator(),
|
|
459902
460122
|
init_stream(),
|
|
460123
|
+
init_cloud_retry_message(),
|
|
459903
460124
|
init_interrupts(),
|
|
459904
460125
|
init_protocol_outbound(),
|
|
459905
460126
|
init_recoverable_notices(),
|
|
@@ -461503,7 +461724,18 @@ function createMissedPongWatchdog(maxUnansweredPings) {
|
|
|
461503
461724
|
}
|
|
461504
461725
|
};
|
|
461505
461726
|
}
|
|
461506
|
-
function
|
|
461727
|
+
function getCurrentStreamTransport(runtime, controlTransport) {
|
|
461728
|
+
for (const connection of runtime.connections.values()) {
|
|
461729
|
+
if (connection.writer !== controlTransport)
|
|
461730
|
+
continue;
|
|
461731
|
+
const streamTransport = connection.streamWriter;
|
|
461732
|
+
if (streamTransport && streamTransport !== controlTransport) {
|
|
461733
|
+
return streamTransport;
|
|
461734
|
+
}
|
|
461735
|
+
}
|
|
461736
|
+
return null;
|
|
461737
|
+
}
|
|
461738
|
+
function startConnectionHeartbeat(runtime, transport, onStale, sendPing, options3 = {}) {
|
|
461507
461739
|
runtime.lastPongAt = Date.now();
|
|
461508
461740
|
const maxUnansweredPings = Math.max(1, Math.ceil(LISTENER_PONG_TIMEOUT_MS / LISTENER_HEARTBEAT_INTERVAL_MS));
|
|
461509
461741
|
const watchdog = createMissedPongWatchdog(maxUnansweredPings);
|
|
@@ -461513,10 +461745,14 @@ function startConnectionHeartbeat(runtime, transport, onStale, sendPing) {
|
|
|
461513
461745
|
return;
|
|
461514
461746
|
}
|
|
461515
461747
|
const sentAt = Date.now();
|
|
461516
|
-
if (sendPing()) {
|
|
461748
|
+
if (sendPing(transport)) {
|
|
461517
461749
|
watchdog.recordPing(sentAt);
|
|
461518
461750
|
}
|
|
461519
|
-
|
|
461751
|
+
const streamTransport = getCurrentStreamTransport(runtime, transport);
|
|
461752
|
+
if (streamTransport) {
|
|
461753
|
+
sendPing(streamTransport);
|
|
461754
|
+
}
|
|
461755
|
+
}, options3.intervalMs ?? LISTENER_HEARTBEAT_INTERVAL_MS);
|
|
461520
461756
|
}
|
|
461521
461757
|
var init_heartbeat = __esm(() => {
|
|
461522
461758
|
init_constants3();
|
|
@@ -463963,7 +464199,7 @@ function dispatchInboundMessageWhenReady(params) {
|
|
|
463963
464199
|
emitListenerStatus(listener, options3.onStatusChange, options3.connectionId);
|
|
463964
464200
|
rememberAcceptedInputDisposition(runtime, clientMessageId, "started");
|
|
463965
464201
|
acknowledgeInput({ accepted: true, disposition: "started" });
|
|
463966
|
-
await processIncomingMessage(incoming,
|
|
464202
|
+
await processIncomingMessage(incoming, getOrCreateProcessTransport(listener), runtime, options3.onStatusChange, options3.connectionId);
|
|
463967
464203
|
emitListenerStatus(listener, options3.onStatusChange, options3.connectionId);
|
|
463968
464204
|
if (runtime.queueRuntime.length > 0 || runtime.queuePumpScheduled || runtime.queuePumpActive) {
|
|
463969
464205
|
scheduleQueuePump(runtime, socket, options3, processQueuedTurn);
|
|
@@ -463980,12 +464216,13 @@ function dispatchInboundMessageWhenReady(params) {
|
|
|
463980
464216
|
}
|
|
463981
464217
|
var MAX_ACCEPTED_INPUT_DISPOSITIONS = 4096;
|
|
463982
464218
|
var init_inbound_dispatch = __esm(async () => {
|
|
464219
|
+
init_connection();
|
|
463983
464220
|
init_runtime();
|
|
463984
464221
|
await init_queue();
|
|
463985
464222
|
});
|
|
463986
464223
|
|
|
463987
464224
|
// src/websocket/listener/protocol-logging.ts
|
|
463988
|
-
function
|
|
464225
|
+
function isRecord13(value) {
|
|
463989
464226
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
463990
464227
|
}
|
|
463991
464228
|
function formatLogValue(value) {
|
|
@@ -464009,14 +464246,14 @@ function pushField(fields, key2, value, label = key2) {
|
|
|
464009
464246
|
fields.push(`${label}=${formatted}`);
|
|
464010
464247
|
}
|
|
464011
464248
|
function summarizeInputPayload(payload) {
|
|
464012
|
-
if (!
|
|
464249
|
+
if (!isRecord13(payload))
|
|
464013
464250
|
return [];
|
|
464014
464251
|
const fields = [];
|
|
464015
464252
|
pushField(fields, "kind", payload.kind);
|
|
464016
464253
|
if (payload.kind === "create_message") {
|
|
464017
464254
|
pushField(fields, "messages", payload.messages);
|
|
464018
464255
|
pushField(fields, "client_tool_allowlist", payload.client_tool_allowlist);
|
|
464019
|
-
if (
|
|
464256
|
+
if (isRecord13(payload.client_toolset)) {
|
|
464020
464257
|
pushField(fields, "client_toolset.base", payload.client_toolset.base);
|
|
464021
464258
|
pushField(fields, "client_toolset.include", payload.client_toolset.include);
|
|
464022
464259
|
}
|
|
@@ -464033,9 +464270,9 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
464033
464270
|
const fields = [];
|
|
464034
464271
|
pushField(fields, "agent_id", command.agent_id, "agent");
|
|
464035
464272
|
pushField(fields, "conversation_id", command.conversation_id, "conversation");
|
|
464036
|
-
if (
|
|
464273
|
+
if (isRecord13(command.create_agent))
|
|
464037
464274
|
fields.push("create_agent=true");
|
|
464038
|
-
if (
|
|
464275
|
+
if (isRecord13(command.create_conversation)) {
|
|
464039
464276
|
fields.push("create_conversation=true");
|
|
464040
464277
|
}
|
|
464041
464278
|
pushField(fields, "cwd", command.cwd);
|
|
@@ -464044,17 +464281,17 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
464044
464281
|
return fields;
|
|
464045
464282
|
}
|
|
464046
464283
|
function summarizeV2Command(parsed) {
|
|
464047
|
-
if (!
|
|
464284
|
+
if (!isRecord13(parsed) || typeof parsed.type !== "string")
|
|
464048
464285
|
return "unknown";
|
|
464049
464286
|
const fields = [];
|
|
464050
|
-
const runtime =
|
|
464287
|
+
const runtime = isRecord13(parsed.runtime) ? parsed.runtime : null;
|
|
464051
464288
|
if (runtime) {
|
|
464052
464289
|
fields.push(`runtime=${runtime.agent_id ?? "<unknown>"}/${runtime.conversation_id ?? "<unknown>"}`);
|
|
464053
464290
|
}
|
|
464054
464291
|
pushField(fields, "request_id", parsed.request_id);
|
|
464055
464292
|
if (parsed.type === "input") {
|
|
464056
464293
|
fields.push(...summarizeInputPayload(parsed.payload));
|
|
464057
|
-
} else if (parsed.type === "change_device_state" &&
|
|
464294
|
+
} else if (parsed.type === "change_device_state" && isRecord13(parsed.payload)) {
|
|
464058
464295
|
pushField(fields, "mode", parsed.payload.mode);
|
|
464059
464296
|
pushField(fields, "cwd", parsed.payload.cwd);
|
|
464060
464297
|
pushField(fields, "agent_id", parsed.payload.agent_id);
|
|
@@ -464064,7 +464301,7 @@ function summarizeV2Command(parsed) {
|
|
|
464064
464301
|
} else if (parsed.type === "runtime_external_tools_update" && Array.isArray(parsed.updates)) {
|
|
464065
464302
|
fields.push(`updates=${parsed.updates.length}`);
|
|
464066
464303
|
fields.push(`runtimes=${parsed.updates.reduce((count, update2) => {
|
|
464067
|
-
return count + (
|
|
464304
|
+
return count + (isRecord13(update2) && Array.isArray(update2.runtimes) ? update2.runtimes.length : 0);
|
|
464068
464305
|
}, 0)}`);
|
|
464069
464306
|
} else {
|
|
464070
464307
|
for (const key2 of [
|
|
@@ -465096,8 +465333,8 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
|
|
|
465096
465333
|
startConnectionHeartbeat(runtime, transport, () => {
|
|
465097
465334
|
trackListenerError4("listener_pong_timeout", new Error(`No relay pong within ${LISTENER_PONG_TIMEOUT_MS}ms; terminating half-open socket to force reconnect`), "listener_heartbeat");
|
|
465098
465335
|
runtime.socket?.terminate();
|
|
465099
|
-
}, () => {
|
|
465100
|
-
return safeTransportSend(
|
|
465336
|
+
}, (heartbeatTransport) => {
|
|
465337
|
+
return safeTransportSend(heartbeatTransport, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
|
|
465101
465338
|
});
|
|
465102
465339
|
}
|
|
465103
465340
|
if (options3.startProcessServices === false)
|
|
@@ -466127,7 +466364,7 @@ function decodeJwtClaims(token2, sharedSecret) {
|
|
|
466127
466364
|
} catch {
|
|
466128
466365
|
return { error: unauthorized("invalid websocket jwt") };
|
|
466129
466366
|
}
|
|
466130
|
-
if (!
|
|
466367
|
+
if (!isRecord14(header) || header.alg !== "HS256") {
|
|
466131
466368
|
return { error: unauthorized("invalid websocket jwt") };
|
|
466132
466369
|
}
|
|
466133
466370
|
const expectedSignature = createHmac("sha256", sharedSecret).update(`${encodedHeader}.${encodedClaims}`).digest();
|
|
@@ -466165,7 +466402,7 @@ function audienceMatches(actual, expectedAudience) {
|
|
|
466165
466402
|
return false;
|
|
466166
466403
|
}
|
|
466167
466404
|
function isJwtClaims(value) {
|
|
466168
|
-
if (!
|
|
466405
|
+
if (!isRecord14(value) || !Number.isSafeInteger(value.exp)) {
|
|
466169
466406
|
return false;
|
|
466170
466407
|
}
|
|
466171
466408
|
if (value.nbf !== undefined && !Number.isSafeInteger(value.nbf)) {
|
|
@@ -466185,7 +466422,7 @@ function isJwtClaims(value) {
|
|
|
466185
466422
|
}
|
|
466186
466423
|
return true;
|
|
466187
466424
|
}
|
|
466188
|
-
function
|
|
466425
|
+
function isRecord14(value) {
|
|
466189
466426
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
466190
466427
|
}
|
|
466191
466428
|
function base64UrlDecode(value) {
|
|
@@ -470434,7 +470671,7 @@ import {
|
|
|
470434
470671
|
} from "node:fs";
|
|
470435
470672
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
470436
470673
|
import path41 from "node:path";
|
|
470437
|
-
function
|
|
470674
|
+
function isRecord15(value) {
|
|
470438
470675
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
470439
470676
|
}
|
|
470440
470677
|
function isPathInsideOrEqual2(childPath, parentPath) {
|
|
@@ -470450,7 +470687,7 @@ function readPackageJson(packageJsonPath) {
|
|
|
470450
470687
|
} catch (error54) {
|
|
470451
470688
|
throw new Error(`Could not read package.json: ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
470452
470689
|
}
|
|
470453
|
-
if (!
|
|
470690
|
+
if (!isRecord15(parsed)) {
|
|
470454
470691
|
throw new Error("package.json must be an object");
|
|
470455
470692
|
}
|
|
470456
470693
|
return parsed;
|
|
@@ -470460,7 +470697,7 @@ function formatRepository(repository) {
|
|
|
470460
470697
|
const trimmed2 = repository.trim();
|
|
470461
470698
|
return trimmed2 || undefined;
|
|
470462
470699
|
}
|
|
470463
|
-
if (!
|
|
470700
|
+
if (!isRecord15(repository))
|
|
470464
470701
|
return;
|
|
470465
470702
|
const url2 = repository.url;
|
|
470466
470703
|
if (typeof url2 !== "string")
|
|
@@ -470990,7 +471227,7 @@ function hasRuntimeDependencies(packageJson) {
|
|
|
470990
471227
|
if (!packageJson)
|
|
470991
471228
|
return false;
|
|
470992
471229
|
const dependencies4 = packageJson.dependencies;
|
|
470993
|
-
return
|
|
471230
|
+
return isRecord15(dependencies4) && Object.keys(dependencies4).length > 0;
|
|
470994
471231
|
}
|
|
470995
471232
|
function readPackageJsonIfExists(packageDirectory) {
|
|
470996
471233
|
const packageJsonPath = path41.join(packageDirectory, "package.json");
|
|
@@ -477806,6 +478043,9 @@ function uniqueSources(sources) {
|
|
|
477806
478043
|
byKey.set(sourceKey(source2), source2);
|
|
477807
478044
|
return [...byKey.values()];
|
|
477808
478045
|
}
|
|
478046
|
+
function channelTagsForSources(sources) {
|
|
478047
|
+
return [...new Set(sources.map((source2) => `channel:${source2.channel}`))];
|
|
478048
|
+
}
|
|
477809
478049
|
function stopReasonFromDelta(message) {
|
|
477810
478050
|
const delta2 = message.delta;
|
|
477811
478051
|
return delta2.message_type === "stop_reason" && "stop_reason" in delta2 && typeof delta2.stop_reason === "string" ? delta2.stop_reason : null;
|
|
@@ -478047,9 +478287,11 @@ class ChannelGateway {
|
|
|
478047
478287
|
}
|
|
478048
478288
|
async performRuntimeRegistration(state, delivery) {
|
|
478049
478289
|
const tool2 = await this.hooks.buildExternalTool(delivery.runtime, delivery.sources);
|
|
478290
|
+
const conversationTags = channelTagsForSources(delivery.sources);
|
|
478050
478291
|
const signature = JSON.stringify({
|
|
478051
478292
|
mode: delivery.defaultPermissionMode ?? null,
|
|
478052
|
-
tool: tool2
|
|
478293
|
+
tool: tool2,
|
|
478294
|
+
conversationTags
|
|
478053
478295
|
});
|
|
478054
478296
|
if (state.registrationSignature === signature && state.registration) {
|
|
478055
478297
|
return state.registration;
|
|
@@ -478057,6 +478299,7 @@ class ChannelGateway {
|
|
|
478057
478299
|
const registration = this.client.runtimeStart({
|
|
478058
478300
|
agent_id: delivery.runtime.agent_id,
|
|
478059
478301
|
conversation_id: delivery.runtime.conversation_id,
|
|
478302
|
+
...conversationTags.length > 0 ? { conversation_source_tags: conversationTags } : {},
|
|
478060
478303
|
...delivery.defaultPermissionMode ? { mode: delivery.defaultPermissionMode } : {},
|
|
478061
478304
|
recover_approvals: true,
|
|
478062
478305
|
force_device_status: false,
|
|
@@ -492188,7 +492431,7 @@ async function connectMcpServer(config3, options3 = {}) {
|
|
|
492188
492431
|
return {
|
|
492189
492432
|
content: Array.isArray(result.content) ? result.content : [],
|
|
492190
492433
|
...result.isError === true ? { isError: true } : {},
|
|
492191
|
-
...
|
|
492434
|
+
...isRecord16(result.structuredContent) ? { structuredContent: result.structuredContent } : {}
|
|
492192
492435
|
};
|
|
492193
492436
|
},
|
|
492194
492437
|
close: async () => {
|
|
@@ -492261,11 +492504,11 @@ function mergeHeaders4(init, headers) {
|
|
|
492261
492504
|
};
|
|
492262
492505
|
}
|
|
492263
492506
|
function normalizeInputSchema(value) {
|
|
492264
|
-
if (
|
|
492507
|
+
if (isRecord16(value) && value.type === "object")
|
|
492265
492508
|
return value;
|
|
492266
492509
|
return { type: "object", properties: {} };
|
|
492267
492510
|
}
|
|
492268
|
-
function
|
|
492511
|
+
function isRecord16(value) {
|
|
492269
492512
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
492270
492513
|
}
|
|
492271
492514
|
var DEFAULT_CLIENT_INFO;
|
|
@@ -492277,7 +492520,7 @@ var init_mcp_client = __esm(() => {
|
|
|
492277
492520
|
init_streamableHttp();
|
|
492278
492521
|
DEFAULT_CLIENT_INFO = {
|
|
492279
492522
|
name: "letta-code",
|
|
492280
|
-
version: "0.30.
|
|
492523
|
+
version: "0.30.9"
|
|
492281
492524
|
};
|
|
492282
492525
|
});
|
|
492283
492526
|
|
|
@@ -492673,7 +492916,7 @@ function toExternalToolResult(result) {
|
|
|
492673
492916
|
};
|
|
492674
492917
|
}
|
|
492675
492918
|
function normalizeContent2(item) {
|
|
492676
|
-
if (
|
|
492919
|
+
if (isRecord17(item)) {
|
|
492677
492920
|
if (item.type === "text" && typeof item.text === "string") {
|
|
492678
492921
|
return { type: "text", text: item.text };
|
|
492679
492922
|
}
|
|
@@ -492687,7 +492930,7 @@ function normalizeContent2(item) {
|
|
|
492687
492930
|
}
|
|
492688
492931
|
return { type: "text", text: JSON.stringify(item) };
|
|
492689
492932
|
}
|
|
492690
|
-
function
|
|
492933
|
+
function isRecord17(value) {
|
|
492691
492934
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
492692
492935
|
}
|
|
492693
492936
|
var CLIENT_MCP_RUNTIME_KEY;
|
|
@@ -495437,6 +495680,15 @@ ${loadedContents.join(`
|
|
|
495437
495680
|
const lastReasoning = reversed.find((line) => line.kind === "reasoning" && ("text" in line) && typeof line.text === "string" && line.text.trim().length > 0);
|
|
495438
495681
|
const lastToolResult = reversed.find((line) => line.kind === "tool_call" && ("resultText" in line) && typeof line.resultText === "string" && (line.resultText ?? "").trim().length > 0);
|
|
495439
495682
|
const resultText = lastAssistant?.text || lastReasoning?.text || lastToolResult?.resultText || "No assistant response found";
|
|
495683
|
+
if (!lastAssistant && (lastReasoning || lastToolResult)) {
|
|
495684
|
+
trackEndTurnNoAssistant({
|
|
495685
|
+
fallbackKind: lastReasoning ? "reasoning" : "tool_call",
|
|
495686
|
+
modelHandle: agent2.llm_config?.model ?? model,
|
|
495687
|
+
runId: lastKnownRunId ?? undefined,
|
|
495688
|
+
isSubagent,
|
|
495689
|
+
subagentType: systemPromptPreset ?? agent2.tags?.find((t2) => t2.startsWith("type:"))?.slice(5)
|
|
495690
|
+
});
|
|
495691
|
+
}
|
|
495440
495692
|
const stats = sessionStats.getSnapshot();
|
|
495441
495693
|
const usage = {
|
|
495442
495694
|
prompt_tokens: stats.usage.promptTokens,
|
|
@@ -500356,8 +500608,9 @@ function useLocalModAdapter(context3, options3 = {}) {
|
|
|
500356
500608
|
...agentModsDirectory ? { agentModsDirectory } : {},
|
|
500357
500609
|
disabled,
|
|
500358
500610
|
getBackend,
|
|
500359
|
-
getClient
|
|
500360
|
-
|
|
500611
|
+
getClient,
|
|
500612
|
+
onNotification: options3.onNotification
|
|
500613
|
+
}), [agentModsDirectory, disabled, options3.onNotification]);
|
|
500361
500614
|
const snapshot = import_react43.useSyncExternalStore(adapter.subscribe, adapter.getSnapshot, adapter.getSnapshot);
|
|
500362
500615
|
import_react43.useEffect(() => {
|
|
500363
500616
|
adapter.reload();
|
|
@@ -552980,6 +553233,7 @@ function App2({
|
|
|
552980
553233
|
}, [isExecutingTool]);
|
|
552981
553234
|
const refreshDerivedRef = import_react120.useRef(null);
|
|
552982
553235
|
const appendTaskNotificationEvents = import_react120.useCallback((summaries) => appendTaskNotificationEventsToBuffer(summaries, buffersRef.current, () => uid("event"), () => refreshDerivedRef.current?.()), []);
|
|
553236
|
+
const appendModNotification = import_react120.useCallback((message) => appendTaskNotificationEvents([message]), [appendTaskNotificationEvents]);
|
|
552983
553237
|
const consumeQueuedMessages = import_react120.useCallback(() => {
|
|
552984
553238
|
const len = tuiQueueRef.current?.length ?? 0;
|
|
552985
553239
|
if (len === 0)
|
|
@@ -553399,7 +553653,8 @@ function App2({
|
|
|
553399
553653
|
const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join92(modContext.memfs.memoryDir, "mods") : null;
|
|
553400
553654
|
const modAdapter = useLocalModAdapter(modContext, {
|
|
553401
553655
|
agentModsDirectory,
|
|
553402
|
-
disabled: modsDisabled
|
|
553656
|
+
disabled: modsDisabled,
|
|
553657
|
+
onNotification: appendModNotification
|
|
553403
553658
|
});
|
|
553404
553659
|
import_react120.useEffect(() => {
|
|
553405
553660
|
modAdapterRef.current = modAdapter;
|
|
@@ -559380,4 +559635,4 @@ function registerBunOAuthFlows() {
|
|
|
559380
559635
|
registerBunOAuthFlows();
|
|
559381
559636
|
await init_src5().then(() => exports_src2);
|
|
559382
559637
|
|
|
559383
|
-
//# debugId=
|
|
559638
|
+
//# debugId=5CF69A1BB16338C364756E2164756E21
|