@letta-ai/letta-code 0.30.8 → 0.30.10
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/tools/manager.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/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/dist/types/websocket/listener/types.d.ts +1 -0
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +367 -97
- package/package.json +1 -1
- package/scripts/dev.cjs +1 -2
- package/scripts/source-file-size-baseline.json +10 -9
- 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.10",
|
|
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,
|
|
@@ -352398,13 +352446,7 @@ async function resolveBaseToolNamesForModel(modelIdentifier, options3) {
|
|
|
352398
352446
|
baseToolNames = TOOL_NAMES;
|
|
352399
352447
|
}
|
|
352400
352448
|
if (options3?.include && options3.include.length > 0) {
|
|
352401
|
-
|
|
352402
|
-
for (const name of options3.include) {
|
|
352403
|
-
if (!seen.has(name)) {
|
|
352404
|
-
baseToolNames.push(name);
|
|
352405
|
-
seen.add(name);
|
|
352406
|
-
}
|
|
352407
|
-
}
|
|
352449
|
+
baseToolNames = [...new Set([...baseToolNames, ...options3.include])];
|
|
352408
352450
|
}
|
|
352409
352451
|
if (options3?.exclude && options3.exclude.length > 0) {
|
|
352410
352452
|
const excludeSet = new Set(options3.exclude);
|
|
@@ -353572,6 +353614,18 @@ function resolveIncludedToolNames(toolNames) {
|
|
|
353572
353614
|
return internalName;
|
|
353573
353615
|
});
|
|
353574
353616
|
}
|
|
353617
|
+
function resolveAllowlistedToolNames(allowlist) {
|
|
353618
|
+
if (!allowlist)
|
|
353619
|
+
return [];
|
|
353620
|
+
const toolNames = [];
|
|
353621
|
+
for (const allowedName of allowlist) {
|
|
353622
|
+
const internalName = getInternalToolName(allowedName);
|
|
353623
|
+
if (Object.hasOwn(TOOL_DEFINITIONS, internalName)) {
|
|
353624
|
+
toolNames.push(internalName);
|
|
353625
|
+
}
|
|
353626
|
+
}
|
|
353627
|
+
return toolNames;
|
|
353628
|
+
}
|
|
353575
353629
|
function appendUniqueToolNames(baseToolNames, includedToolNames) {
|
|
353576
353630
|
const result = [...baseToolNames];
|
|
353577
353631
|
const seen = new Set(result);
|
|
@@ -353663,7 +353717,7 @@ async function prepareToolExecutionContextForResolvedTarget(params) {
|
|
|
353663
353717
|
} = params;
|
|
353664
353718
|
const effectiveModel = modelIdentifier && modelIdentifier.length > 0 ? resolveModel(modelIdentifier) ?? modelIdentifier : null;
|
|
353665
353719
|
const effectiveToolsetPreference = clientToolset?.base ?? toolsetPreference;
|
|
353666
|
-
const includedToolNames = resolveIncludedToolNames(clientToolset?.include);
|
|
353720
|
+
const includedToolNames = appendUniqueToolNames(resolveIncludedToolNames(clientToolset?.include), resolveAllowlistedToolNames(clientToolAllowlist));
|
|
353667
353721
|
if (effectiveToolsetPreference === "auto") {
|
|
353668
353722
|
const derivedToolset = effectiveModel ? deriveToolsetFromModel(effectiveModel, providerType) : "default";
|
|
353669
353723
|
const scopedModContext2 = buildModInvocationContext({
|
|
@@ -353742,6 +353796,7 @@ async function prepareToolExecutionContextForScope(params) {
|
|
|
353742
353796
|
externalToolScopeIds,
|
|
353743
353797
|
workingDirectory,
|
|
353744
353798
|
permissionModeState,
|
|
353799
|
+
skillsDirectory,
|
|
353745
353800
|
skillSources,
|
|
353746
353801
|
cachedAgent,
|
|
353747
353802
|
modContext,
|
|
@@ -353796,6 +353851,7 @@ async function prepareToolExecutionContextForScope(params) {
|
|
|
353796
353851
|
agentName: agent2.name ?? null,
|
|
353797
353852
|
conversationId: scopedConversationId,
|
|
353798
353853
|
workingDirectory,
|
|
353854
|
+
...skillsDirectory !== undefined ? { skillsDirectory } : {},
|
|
353799
353855
|
...skillSources !== undefined ? { skillSources } : {}
|
|
353800
353856
|
}
|
|
353801
353857
|
});
|
|
@@ -356516,6 +356572,9 @@ function updateLocalConversationRecord(current, body, updatedAt) {
|
|
|
356516
356572
|
if (typeof bodyRecord.summary === "string" || bodyRecord.summary === null) {
|
|
356517
356573
|
next.summary = bodyRecord.summary;
|
|
356518
356574
|
}
|
|
356575
|
+
if (isStringArray2(bodyRecord.tags)) {
|
|
356576
|
+
next.tags = bodyRecord.tags;
|
|
356577
|
+
}
|
|
356519
356578
|
return next;
|
|
356520
356579
|
}
|
|
356521
356580
|
function normalizeAgentRecord(value, defaultAgentModel) {
|
|
@@ -412081,35 +412140,35 @@ function buildSlackConversationSummary(msg) {
|
|
|
412081
412140
|
if (msg.chatType === "direct") {
|
|
412082
412141
|
if (msg.threadId?.trim()) {
|
|
412083
412142
|
const preview2 = truncateChannelSummaryPreview(msg.text);
|
|
412084
|
-
return preview2 ? `
|
|
412143
|
+
return preview2 ? `DM thread with ${msg.senderName?.trim() || msg.senderId}: ${preview2}` : `DM thread with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412085
412144
|
}
|
|
412086
|
-
return `
|
|
412145
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412087
412146
|
}
|
|
412088
412147
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412089
412148
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412090
412149
|
if (preview)
|
|
412091
|
-
return `
|
|
412092
|
-
return `
|
|
412150
|
+
return `Thread${channelLabel}: ${preview}`;
|
|
412151
|
+
return `Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
412093
412152
|
}
|
|
412094
412153
|
function buildDiscordConversationSummary(msg) {
|
|
412095
412154
|
if (msg.chatType === "direct") {
|
|
412096
|
-
return `
|
|
412155
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412097
412156
|
}
|
|
412098
412157
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412099
412158
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412100
412159
|
if (preview)
|
|
412101
|
-
return `
|
|
412102
|
-
return `
|
|
412160
|
+
return `Thread${channelLabel}: ${preview}`;
|
|
412161
|
+
return `Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
412103
412162
|
}
|
|
412104
412163
|
function buildTelegramConversationSummary(msg) {
|
|
412105
412164
|
if (msg.chatType === "direct") {
|
|
412106
|
-
return `
|
|
412165
|
+
return `DM with ${msg.senderName?.trim() || msg.senderId}`;
|
|
412107
412166
|
}
|
|
412108
412167
|
const preview = truncateChannelSummaryPreview(msg.text);
|
|
412109
412168
|
const channelLabel = msg.chatLabel && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
412110
412169
|
if (preview)
|
|
412111
|
-
return `
|
|
412112
|
-
return `
|
|
412170
|
+
return `Topic${channelLabel}: ${preview}`;
|
|
412171
|
+
return `Topic${channelLabel || ` ${msg.chatId}`}`;
|
|
412113
412172
|
}
|
|
412114
412173
|
function buildWhatsAppConversationSummary(msg) {
|
|
412115
412174
|
if (msg.chatType === "direct") {
|
|
@@ -447354,7 +447413,7 @@ function isRuntimeStartCommand(value) {
|
|
|
447354
447413
|
if (!value || typeof value !== "object")
|
|
447355
447414
|
return false;
|
|
447356
447415
|
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));
|
|
447416
|
+
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
447417
|
}
|
|
447359
447418
|
function isTerminalSpawnCommand(value) {
|
|
447360
447419
|
if (!value || typeof value !== "object")
|
|
@@ -450433,6 +450492,34 @@ async function resolveRuntimeStartConversation(parsed, agent2, created) {
|
|
|
450433
450492
|
created.conversation = true;
|
|
450434
450493
|
return conversation;
|
|
450435
450494
|
}
|
|
450495
|
+
function removeMatchingSourcePrefix(summary, sourceTags) {
|
|
450496
|
+
if (typeof summary !== "string")
|
|
450497
|
+
return summary;
|
|
450498
|
+
const match4 = summary.match(/^\s*\[([^\]]+)\]\s*/);
|
|
450499
|
+
if (!match4)
|
|
450500
|
+
return summary;
|
|
450501
|
+
const prefix = match4[1]?.trim().toLowerCase();
|
|
450502
|
+
const matchesSourceTag = sourceTags.some((tag) => LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG[tag] === prefix);
|
|
450503
|
+
return matchesSourceTag ? summary.slice(match4[0].length) : summary;
|
|
450504
|
+
}
|
|
450505
|
+
async function applyRuntimeStartConversationSourceTags(parsed, conversation) {
|
|
450506
|
+
const sourceTags = parsed.conversation_source_tags;
|
|
450507
|
+
if (conversation.id === "default" || !sourceTags?.length) {
|
|
450508
|
+
return conversation;
|
|
450509
|
+
}
|
|
450510
|
+
const currentTags = Reflect.get(conversation, "tags");
|
|
450511
|
+
const existingTags = Array.isArray(currentTags) ? currentTags.filter((tag) => typeof tag === "string") : [];
|
|
450512
|
+
const missingTags = sourceTags.filter((tag) => !existingTags.includes(tag));
|
|
450513
|
+
const summary = removeMatchingSourcePrefix(conversation.summary, sourceTags);
|
|
450514
|
+
const summaryChanged = summary !== conversation.summary;
|
|
450515
|
+
if (missingTags.length === 0 && !summaryChanged) {
|
|
450516
|
+
return conversation;
|
|
450517
|
+
}
|
|
450518
|
+
return getBackend().updateConversation(conversation.id, {
|
|
450519
|
+
...missingTags.length > 0 ? { tags: [...new Set([...existingTags, ...missingTags])] } : {},
|
|
450520
|
+
...summaryChanged ? { summary } : {}
|
|
450521
|
+
});
|
|
450522
|
+
}
|
|
450436
450523
|
async function applyRuntimeStartState(parsed, context3, scope, scopedRuntime) {
|
|
450437
450524
|
if (parsed.skill_sources === undefined && parsed.preserve_skill_sources !== true) {
|
|
450438
450525
|
scopedRuntime.skillSources = undefined;
|
|
@@ -450473,6 +450560,7 @@ async function handleRuntimeStartCommand(parsed, context3) {
|
|
|
450473
450560
|
validateRuntimeStartShape(parsed);
|
|
450474
450561
|
agent2 = await resolveRuntimeStartAgent(parsed, created);
|
|
450475
450562
|
conversation = await resolveRuntimeStartConversation(parsed, agent2, created);
|
|
450563
|
+
conversation = await applyRuntimeStartConversationSourceTags(parsed, conversation);
|
|
450476
450564
|
runtimeScope = buildRuntimeScope(agent2, conversation);
|
|
450477
450565
|
const { connectionId } = context3;
|
|
450478
450566
|
const assertConnectionOpen = () => {
|
|
@@ -450527,6 +450615,7 @@ function handleRuntimeStartProtocolCommand(parsed, context3) {
|
|
|
450527
450615
|
});
|
|
450528
450616
|
return true;
|
|
450529
450617
|
}
|
|
450618
|
+
var LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG;
|
|
450530
450619
|
var init_runtime_start = __esm(async () => {
|
|
450531
450620
|
init_create5();
|
|
450532
450621
|
init_create_agent_request();
|
|
@@ -450541,6 +450630,12 @@ var init_runtime_start = __esm(async () => {
|
|
|
450541
450630
|
init_external_tools(),
|
|
450542
450631
|
init_protocol_inbound()
|
|
450543
450632
|
]);
|
|
450633
|
+
LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG = {
|
|
450634
|
+
"channel:discord": "discord",
|
|
450635
|
+
"channel:slack": "slack",
|
|
450636
|
+
"channel:telegram": "telegram",
|
|
450637
|
+
"origin:schedule": "schedule"
|
|
450638
|
+
};
|
|
450544
450639
|
});
|
|
450545
450640
|
|
|
450546
450641
|
// src/websocket/listener/commands/settings.ts
|
|
@@ -451373,10 +451468,10 @@ function getRecoverableStatusNoticeVisibility(kind) {
|
|
|
451373
451468
|
return "transcript";
|
|
451374
451469
|
}
|
|
451375
451470
|
}
|
|
451376
|
-
function getRecoverableRetryNoticeVisibility(kind
|
|
451471
|
+
function getRecoverableRetryNoticeVisibility(kind) {
|
|
451377
451472
|
switch (kind) {
|
|
451378
451473
|
case "transient_provider_retry":
|
|
451379
|
-
return
|
|
451474
|
+
return "transcript";
|
|
451380
451475
|
default:
|
|
451381
451476
|
return "transcript";
|
|
451382
451477
|
}
|
|
@@ -451526,7 +451621,7 @@ function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
|
451526
451621
|
});
|
|
451527
451622
|
}
|
|
451528
451623
|
function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
451529
|
-
const visibility = getRecoverableRetryNoticeVisibility(params.kind
|
|
451624
|
+
const visibility = getRecoverableRetryNoticeVisibility(params.kind);
|
|
451530
451625
|
if (visibility === "debug_only") {
|
|
451531
451626
|
debugLog("recovery", `Debug-only retry notice (${params.kind}, attempt ${params.attempt}/${params.maxAttempts}): ${params.message}`);
|
|
451532
451627
|
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
@@ -453218,6 +453313,50 @@ var init_stream_resume = __esm(() => {
|
|
|
453218
453313
|
init_client2();
|
|
453219
453314
|
});
|
|
453220
453315
|
|
|
453316
|
+
// src/cli/helpers/stream-terminal-eof-guard.ts
|
|
453317
|
+
function getTerminalEofGraceMs() {
|
|
453318
|
+
const raw2 = process.env.LETTA_STREAM_TERMINAL_EOF_GRACE_MS;
|
|
453319
|
+
if (raw2) {
|
|
453320
|
+
const parsed = Number(raw2);
|
|
453321
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
453322
|
+
return parsed;
|
|
453323
|
+
}
|
|
453324
|
+
}
|
|
453325
|
+
return DEFAULT_TERMINAL_EOF_GRACE_MS;
|
|
453326
|
+
}
|
|
453327
|
+
function createTerminalEofGuard(context3) {
|
|
453328
|
+
let timer = null;
|
|
453329
|
+
let fired = false;
|
|
453330
|
+
return {
|
|
453331
|
+
arm: () => {
|
|
453332
|
+
if (timer) {
|
|
453333
|
+
clearTimeout(timer);
|
|
453334
|
+
}
|
|
453335
|
+
const graceMs = getTerminalEofGraceMs();
|
|
453336
|
+
timer = setTimeout(() => {
|
|
453337
|
+
fired = true;
|
|
453338
|
+
debugWarn("drainStream", "Terminal-EOF guard fired: stop_reason=%s received but stream did not end within %dms - aborting HTTP read", context3.getStopReason(), graceMs);
|
|
453339
|
+
telemetry.trackError("stream_terminal_eof_guard_fired", `Stream received stop_reason=${context3.getStopReason()} but HTTP body did not end within ${graceMs}ms`, "stream_drain", {
|
|
453340
|
+
runId: context3.getRunId() ?? undefined
|
|
453341
|
+
});
|
|
453342
|
+
context3.abortHttpRead();
|
|
453343
|
+
}, graceMs);
|
|
453344
|
+
},
|
|
453345
|
+
clear: () => {
|
|
453346
|
+
if (timer) {
|
|
453347
|
+
clearTimeout(timer);
|
|
453348
|
+
timer = null;
|
|
453349
|
+
}
|
|
453350
|
+
},
|
|
453351
|
+
fired: () => fired
|
|
453352
|
+
};
|
|
453353
|
+
}
|
|
453354
|
+
var DEFAULT_TERMINAL_EOF_GRACE_MS = 2000;
|
|
453355
|
+
var init_stream_terminal_eof_guard = __esm(() => {
|
|
453356
|
+
init_telemetry();
|
|
453357
|
+
init_debug();
|
|
453358
|
+
});
|
|
453359
|
+
|
|
453221
453360
|
// src/cli/helpers/stream.ts
|
|
453222
453361
|
function summarizeStreamForDebug(stream12) {
|
|
453223
453362
|
if (!stream12 || typeof stream12 !== "object") {
|
|
@@ -453283,6 +453422,11 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453283
453422
|
let fallbackError = null;
|
|
453284
453423
|
let lastChunkDebugSummary = "none";
|
|
453285
453424
|
let abortedViaListener = false;
|
|
453425
|
+
const terminalEofGuard = createTerminalEofGuard({
|
|
453426
|
+
getStopReason: () => streamProcessor.stopReason,
|
|
453427
|
+
getRunId: () => streamProcessor.lastRunId,
|
|
453428
|
+
abortHttpRead: () => abortStreamController(stream12, "terminal_eof_guard")
|
|
453429
|
+
});
|
|
453286
453430
|
const startAbortGen = buffers.abortGeneration || 0;
|
|
453287
453431
|
const abortHandler = () => {
|
|
453288
453432
|
abortedViaListener = true;
|
|
@@ -453323,6 +453467,9 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453323
453467
|
logTiming(`TTFT: ${formatDuration(ttft)} (from POST to first content)`);
|
|
453324
453468
|
}
|
|
453325
453469
|
const { shouldOutput, errorInfo, updatedApproval } = streamProcessor.processChunk(chunk);
|
|
453470
|
+
if (streamProcessor.stopReason !== null) {
|
|
453471
|
+
terminalEofGuard.arm();
|
|
453472
|
+
}
|
|
453326
453473
|
try {
|
|
453327
453474
|
chunkLog.append(chunk);
|
|
453328
453475
|
} catch {}
|
|
@@ -453397,6 +453544,7 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453397
453544
|
}
|
|
453398
453545
|
queueMicrotask(refresh);
|
|
453399
453546
|
} finally {
|
|
453547
|
+
terminalEofGuard.clear();
|
|
453400
453548
|
try {
|
|
453401
453549
|
chunkLog.flush();
|
|
453402
453550
|
} catch {}
|
|
@@ -453409,6 +453557,11 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453409
453557
|
if (!stopReason && streamProcessor.stopReason) {
|
|
453410
453558
|
stopReason = streamProcessor.stopReason;
|
|
453411
453559
|
}
|
|
453560
|
+
if (terminalEofGuard.fired()) {
|
|
453561
|
+
upsertStatusLine(buffers, `terminal-eof-${startTime}`, [
|
|
453562
|
+
"Stream did not close after completing, continued without waiting"
|
|
453563
|
+
]);
|
|
453564
|
+
}
|
|
453412
453565
|
if (abortedViaListener && !stopReason) {
|
|
453413
453566
|
stopReason = "cancelled";
|
|
453414
453567
|
markIncompleteToolsAsCancelled(buffers, true, "user_interrupt");
|
|
@@ -453462,7 +453615,8 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
453462
453615
|
lastRunId: streamProcessor.lastRunId,
|
|
453463
453616
|
lastSeqId: streamProcessor.lastSeqId,
|
|
453464
453617
|
apiDurationMs,
|
|
453465
|
-
fallbackError
|
|
453618
|
+
fallbackError,
|
|
453619
|
+
terminalEofGuardFired: terminalEofGuard.fired()
|
|
453466
453620
|
};
|
|
453467
453621
|
}
|
|
453468
453622
|
async function drainStreamWithResume(stream12, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, resumePolicy) {
|
|
@@ -453655,6 +453809,7 @@ var init_stream = __esm(async () => {
|
|
|
453655
453809
|
init_tui_perf();
|
|
453656
453810
|
init_chunk_log();
|
|
453657
453811
|
init_stream_resume();
|
|
453812
|
+
init_stream_terminal_eof_guard();
|
|
453658
453813
|
await __promiseAll([
|
|
453659
453814
|
init_message(),
|
|
453660
453815
|
init_accumulator()
|
|
@@ -453835,6 +453990,62 @@ var init_approval_suggestions = __esm(async () => {
|
|
|
453835
453990
|
]);
|
|
453836
453991
|
});
|
|
453837
453992
|
|
|
453993
|
+
// src/websocket/listener/cloud-retry-message.ts
|
|
453994
|
+
function isRecord12(value) {
|
|
453995
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
453996
|
+
}
|
|
453997
|
+
function optionalString4(value) {
|
|
453998
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
453999
|
+
}
|
|
454000
|
+
function parseCloudRetryMessage(value) {
|
|
454001
|
+
if (!isRecord12(value) || value.message_type !== "retry_message") {
|
|
454002
|
+
return null;
|
|
454003
|
+
}
|
|
454004
|
+
const attempt = value.attempt;
|
|
454005
|
+
const maxAttempts = value.max_attempts;
|
|
454006
|
+
const delayMs = value.delay_ms;
|
|
454007
|
+
const retryKind = value.retry_kind;
|
|
454008
|
+
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) {
|
|
454009
|
+
return null;
|
|
454010
|
+
}
|
|
454011
|
+
return {
|
|
454012
|
+
message: value.message,
|
|
454013
|
+
retryKind,
|
|
454014
|
+
attempt,
|
|
454015
|
+
maxAttempts,
|
|
454016
|
+
delayMs,
|
|
454017
|
+
provider: value.provider,
|
|
454018
|
+
fromTransport: optionalString4(value.from_transport),
|
|
454019
|
+
toTransport: optionalString4(value.to_transport),
|
|
454020
|
+
errorCode: optionalString4(value.error_code),
|
|
454021
|
+
runId: optionalString4(value.run_id),
|
|
454022
|
+
stepId: optionalString4(value.step_id)
|
|
454023
|
+
};
|
|
454024
|
+
}
|
|
454025
|
+
function normalizeCloudRetryWireMessage(value) {
|
|
454026
|
+
const retry3 = parseCloudRetryMessage(value);
|
|
454027
|
+
if (!retry3) {
|
|
454028
|
+
return null;
|
|
454029
|
+
}
|
|
454030
|
+
return {
|
|
454031
|
+
...createLifecycleMessageBase("retry", retry3.runId),
|
|
454032
|
+
message: retry3.message,
|
|
454033
|
+
reason: "llm_api_error",
|
|
454034
|
+
attempt: retry3.attempt,
|
|
454035
|
+
max_attempts: retry3.maxAttempts,
|
|
454036
|
+
delay_ms: retry3.delayMs,
|
|
454037
|
+
retry_kind: retry3.retryKind,
|
|
454038
|
+
provider: retry3.provider,
|
|
454039
|
+
from_transport: retry3.fromTransport,
|
|
454040
|
+
to_transport: retry3.toTransport,
|
|
454041
|
+
error_code: retry3.errorCode,
|
|
454042
|
+
step_id: retry3.stepId
|
|
454043
|
+
};
|
|
454044
|
+
}
|
|
454045
|
+
var init_cloud_retry_message = __esm(async () => {
|
|
454046
|
+
await init_protocol_outbound();
|
|
454047
|
+
});
|
|
454048
|
+
|
|
453838
454049
|
// src/websocket/listener/turn-input-state.ts
|
|
453839
454050
|
function ensureTurnInputMessageOtids(messages) {
|
|
453840
454051
|
let didChange = false;
|
|
@@ -454111,7 +454322,7 @@ async function drainRecoveryStreamWithEmission(recoveryStream, socket, runtime,
|
|
|
454111
454322
|
});
|
|
454112
454323
|
}
|
|
454113
454324
|
if (shouldOutput) {
|
|
454114
|
-
const normalizedChunk = normalizeToolReturnWireMessage(chunk);
|
|
454325
|
+
const normalizedChunk = normalizeCloudRetryWireMessage(chunk) ?? normalizeToolReturnWireMessage(chunk);
|
|
454115
454326
|
if (normalizedChunk) {
|
|
454116
454327
|
emitCanonicalMessageDelta(socket, runtime, {
|
|
454117
454328
|
...normalizedChunk,
|
|
@@ -454558,6 +454769,7 @@ var init_recovery = __esm(async () => {
|
|
|
454558
454769
|
init_stream(),
|
|
454559
454770
|
init_toolset(),
|
|
454560
454771
|
init_approval_suggestions(),
|
|
454772
|
+
init_cloud_retry_message(),
|
|
454561
454773
|
init_continuation_input(),
|
|
454562
454774
|
init_interrupts(),
|
|
454563
454775
|
init_mod_adapter2(),
|
|
@@ -454610,16 +454822,17 @@ var init_approval_recovery = __esm(() => {
|
|
|
454610
454822
|
});
|
|
454611
454823
|
|
|
454612
454824
|
// src/websocket/listener/provider-fallback.ts
|
|
454613
|
-
function createProviderFallbackState(agent2) {
|
|
454825
|
+
function createProviderFallbackState(agent2, overrideModel) {
|
|
454614
454826
|
const llmConfig = agent2?.llm_config;
|
|
454615
454827
|
const model = llmConfig?.model;
|
|
454616
454828
|
if (!model) {
|
|
454617
|
-
return { sourceModelId: null, attempted: false };
|
|
454829
|
+
return { sourceModelId: null, attempted: false, overrideModel };
|
|
454618
454830
|
}
|
|
454619
454831
|
const modelInfo = getModelInfoForLlmConfig(model, llmConfig) ?? getModelInfo(model);
|
|
454620
454832
|
return {
|
|
454621
454833
|
sourceModelId: modelInfo?.id ?? model,
|
|
454622
|
-
attempted: false
|
|
454834
|
+
attempted: false,
|
|
454835
|
+
overrideModel
|
|
454623
454836
|
};
|
|
454624
454837
|
}
|
|
454625
454838
|
function maybeApplyProviderFallback(state, attempt) {
|
|
@@ -458040,17 +458253,18 @@ async function emitListenerTurnStart(options3) {
|
|
|
458040
458253
|
conversationId: options3.conversationId,
|
|
458041
458254
|
input: options3.input
|
|
458042
458255
|
};
|
|
458043
|
-
await createListenerModEvents(modAdapters).emit("turn_start", event2, context3);
|
|
458256
|
+
const emission = await createListenerModEvents(modAdapters).emit("turn_start", event2, context3);
|
|
458044
458257
|
const cancel = getTurnStartCancel(event2);
|
|
458045
458258
|
if (cancel) {
|
|
458046
458259
|
return { cancelled: true, reason: cancel.reason };
|
|
458047
458260
|
}
|
|
458048
458261
|
return {
|
|
458049
458262
|
cancelled: false,
|
|
458263
|
+
handlerCount: emission.handlerCount,
|
|
458050
458264
|
input: isTurnInputArray(event2.input) ? event2.input : options3.input
|
|
458051
458265
|
};
|
|
458052
458266
|
} catch {
|
|
458053
|
-
return { cancelled: false, input: options3.input };
|
|
458267
|
+
return { cancelled: false, handlerCount: 0, input: options3.input };
|
|
458054
458268
|
}
|
|
458055
458269
|
}
|
|
458056
458270
|
async function emitListenerTurnEnd(options3) {
|
|
@@ -459137,13 +459351,20 @@ async function prepareListenerTurn(params) {
|
|
|
459137
459351
|
workingDirectory,
|
|
459138
459352
|
permissionMode: permissionModeState.mode,
|
|
459139
459353
|
cachedAgent
|
|
459140
|
-
}) : { cancelled: false, input: messagesToSend };
|
|
459354
|
+
}) : { cancelled: false, handlerCount: 0, input: messagesToSend };
|
|
459141
459355
|
if (isInterrupted()) {
|
|
459142
459356
|
return { kind: "interrupted" };
|
|
459143
459357
|
}
|
|
459144
459358
|
if (turnStartEmission.cancelled) {
|
|
459145
459359
|
return { kind: "cancelled", reason: turnStartEmission.reason };
|
|
459146
459360
|
}
|
|
459361
|
+
let overrideModel;
|
|
459362
|
+
if (turnStartEmission.handlerCount > 0) {
|
|
459363
|
+
try {
|
|
459364
|
+
const conversation = await getBackend().retrieveConversation(conversationId);
|
|
459365
|
+
overrideModel = conversation.model ?? undefined;
|
|
459366
|
+
} catch {}
|
|
459367
|
+
}
|
|
459147
459368
|
const currentInput = ensureTurnInputMessageOtids(turnStartEmission.input);
|
|
459148
459369
|
const turnInput = createTurnInputState(currentInput, getInboundImageFailureModes({
|
|
459149
459370
|
imageFailureMode: msg.imageFailureMode,
|
|
@@ -459153,7 +459374,8 @@ async function prepareListenerTurn(params) {
|
|
|
459153
459374
|
inboundUserTranscriptLines = buildInboundUserTranscriptLines(currentInput);
|
|
459154
459375
|
}
|
|
459155
459376
|
const modAdapters = await ensureListenerModAdaptersForAgent(runtime.listener, agentId);
|
|
459156
|
-
const
|
|
459377
|
+
const listenerOptions = connectionId ? runtime.listener.connections.get(connectionId)?.options : runtime.listener.connections.values().next().value?.options;
|
|
459378
|
+
const environmentDeviceId = listenerOptions?.deviceId;
|
|
459157
459379
|
const preparedToolContext = await prepareToolExecutionContextForScope({
|
|
459158
459380
|
connectionId,
|
|
459159
459381
|
environmentDeviceId,
|
|
@@ -459165,6 +459387,7 @@ async function prepareListenerTurn(params) {
|
|
|
459165
459387
|
externalToolScopeIds: msg.externalToolScopeIds,
|
|
459166
459388
|
workingDirectory,
|
|
459167
459389
|
permissionModeState,
|
|
459390
|
+
skillsDirectory: listenerOptions?.skillsDirectory,
|
|
459168
459391
|
skillSources: runtime.skillSources,
|
|
459169
459392
|
cachedAgent,
|
|
459170
459393
|
modContext: createListenerAgentModContext(agentId),
|
|
@@ -459185,7 +459408,8 @@ async function prepareListenerTurn(params) {
|
|
|
459185
459408
|
pendingNormalizationInterruptedToolCallIds: [
|
|
459186
459409
|
...queuedInterruptedToolCallIds
|
|
459187
459410
|
],
|
|
459188
|
-
preparedToolContext
|
|
459411
|
+
preparedToolContext,
|
|
459412
|
+
...overrideModel ? { overrideModel } : {}
|
|
459189
459413
|
};
|
|
459190
459414
|
}
|
|
459191
459415
|
var init_turn_setup = __esm(async () => {
|
|
@@ -459338,7 +459562,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459338
459562
|
}
|
|
459339
459563
|
let turnInput = setup.turnInput;
|
|
459340
459564
|
const inboundUserTranscriptLines = setup.inboundUserTranscriptLines;
|
|
459341
|
-
const providerFallback = createProviderFallbackState(setup.getCachedAgent());
|
|
459565
|
+
const providerFallback = createProviderFallbackState(setup.getCachedAgent(), setup.overrideModel);
|
|
459342
459566
|
let pendingNormalizationInterruptedToolCallIds = setup.pendingNormalizationInterruptedToolCallIds;
|
|
459343
459567
|
const preparedToolContext = setup.preparedToolContext;
|
|
459344
459568
|
const buildSendOptions = () => ({
|
|
@@ -459430,7 +459654,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459430
459654
|
}
|
|
459431
459655
|
}
|
|
459432
459656
|
if (shouldOutput) {
|
|
459433
|
-
const normalizedChunk = normalizeToolReturnWireMessage(chunk);
|
|
459657
|
+
const normalizedChunk = normalizeCloudRetryWireMessage(chunk) ?? normalizeToolReturnWireMessage(chunk);
|
|
459434
459658
|
if (normalizedChunk) {
|
|
459435
459659
|
emitCanonicalMessageDelta(socket, runtime, {
|
|
459436
459660
|
...normalizedChunk,
|
|
@@ -459446,8 +459670,14 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
459446
459670
|
const stopReason = result.stopReason;
|
|
459447
459671
|
const approvals = result.approvals || [];
|
|
459448
459672
|
const fallbackError = result.fallbackError ?? null;
|
|
459449
|
-
if (
|
|
459450
|
-
|
|
459673
|
+
if (result.terminalEofGuardFired) {
|
|
459674
|
+
emitStatusDelta(socket, runtime, {
|
|
459675
|
+
message: "Stream did not close after completing, continued without waiting",
|
|
459676
|
+
level: "warning",
|
|
459677
|
+
runId: runId || runtime.activeRunId,
|
|
459678
|
+
agentId,
|
|
459679
|
+
conversationId
|
|
459680
|
+
});
|
|
459451
459681
|
}
|
|
459452
459682
|
if (finishIfInterrupted(runId || runtime.activeRunId)) {
|
|
459453
459683
|
break;
|
|
@@ -459900,6 +460130,7 @@ var init_turn = __esm(async () => {
|
|
|
459900
460130
|
init_message(),
|
|
459901
460131
|
init_accumulator(),
|
|
459902
460132
|
init_stream(),
|
|
460133
|
+
init_cloud_retry_message(),
|
|
459903
460134
|
init_interrupts(),
|
|
459904
460135
|
init_protocol_outbound(),
|
|
459905
460136
|
init_recoverable_notices(),
|
|
@@ -461503,7 +461734,18 @@ function createMissedPongWatchdog(maxUnansweredPings) {
|
|
|
461503
461734
|
}
|
|
461504
461735
|
};
|
|
461505
461736
|
}
|
|
461506
|
-
function
|
|
461737
|
+
function getCurrentStreamTransport(runtime, controlTransport) {
|
|
461738
|
+
for (const connection of runtime.connections.values()) {
|
|
461739
|
+
if (connection.writer !== controlTransport)
|
|
461740
|
+
continue;
|
|
461741
|
+
const streamTransport = connection.streamWriter;
|
|
461742
|
+
if (streamTransport && streamTransport !== controlTransport) {
|
|
461743
|
+
return streamTransport;
|
|
461744
|
+
}
|
|
461745
|
+
}
|
|
461746
|
+
return null;
|
|
461747
|
+
}
|
|
461748
|
+
function startConnectionHeartbeat(runtime, transport, onStale, sendPing, options3 = {}) {
|
|
461507
461749
|
runtime.lastPongAt = Date.now();
|
|
461508
461750
|
const maxUnansweredPings = Math.max(1, Math.ceil(LISTENER_PONG_TIMEOUT_MS / LISTENER_HEARTBEAT_INTERVAL_MS));
|
|
461509
461751
|
const watchdog = createMissedPongWatchdog(maxUnansweredPings);
|
|
@@ -461513,10 +461755,14 @@ function startConnectionHeartbeat(runtime, transport, onStale, sendPing) {
|
|
|
461513
461755
|
return;
|
|
461514
461756
|
}
|
|
461515
461757
|
const sentAt = Date.now();
|
|
461516
|
-
if (sendPing()) {
|
|
461758
|
+
if (sendPing(transport)) {
|
|
461517
461759
|
watchdog.recordPing(sentAt);
|
|
461518
461760
|
}
|
|
461519
|
-
|
|
461761
|
+
const streamTransport = getCurrentStreamTransport(runtime, transport);
|
|
461762
|
+
if (streamTransport) {
|
|
461763
|
+
sendPing(streamTransport);
|
|
461764
|
+
}
|
|
461765
|
+
}, options3.intervalMs ?? LISTENER_HEARTBEAT_INTERVAL_MS);
|
|
461520
461766
|
}
|
|
461521
461767
|
var init_heartbeat = __esm(() => {
|
|
461522
461768
|
init_constants3();
|
|
@@ -463963,7 +464209,7 @@ function dispatchInboundMessageWhenReady(params) {
|
|
|
463963
464209
|
emitListenerStatus(listener, options3.onStatusChange, options3.connectionId);
|
|
463964
464210
|
rememberAcceptedInputDisposition(runtime, clientMessageId, "started");
|
|
463965
464211
|
acknowledgeInput({ accepted: true, disposition: "started" });
|
|
463966
|
-
await processIncomingMessage(incoming,
|
|
464212
|
+
await processIncomingMessage(incoming, getOrCreateProcessTransport(listener), runtime, options3.onStatusChange, options3.connectionId);
|
|
463967
464213
|
emitListenerStatus(listener, options3.onStatusChange, options3.connectionId);
|
|
463968
464214
|
if (runtime.queueRuntime.length > 0 || runtime.queuePumpScheduled || runtime.queuePumpActive) {
|
|
463969
464215
|
scheduleQueuePump(runtime, socket, options3, processQueuedTurn);
|
|
@@ -463980,12 +464226,13 @@ function dispatchInboundMessageWhenReady(params) {
|
|
|
463980
464226
|
}
|
|
463981
464227
|
var MAX_ACCEPTED_INPUT_DISPOSITIONS = 4096;
|
|
463982
464228
|
var init_inbound_dispatch = __esm(async () => {
|
|
464229
|
+
init_connection();
|
|
463983
464230
|
init_runtime();
|
|
463984
464231
|
await init_queue();
|
|
463985
464232
|
});
|
|
463986
464233
|
|
|
463987
464234
|
// src/websocket/listener/protocol-logging.ts
|
|
463988
|
-
function
|
|
464235
|
+
function isRecord13(value) {
|
|
463989
464236
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
463990
464237
|
}
|
|
463991
464238
|
function formatLogValue(value) {
|
|
@@ -464009,14 +464256,14 @@ function pushField(fields, key2, value, label = key2) {
|
|
|
464009
464256
|
fields.push(`${label}=${formatted}`);
|
|
464010
464257
|
}
|
|
464011
464258
|
function summarizeInputPayload(payload) {
|
|
464012
|
-
if (!
|
|
464259
|
+
if (!isRecord13(payload))
|
|
464013
464260
|
return [];
|
|
464014
464261
|
const fields = [];
|
|
464015
464262
|
pushField(fields, "kind", payload.kind);
|
|
464016
464263
|
if (payload.kind === "create_message") {
|
|
464017
464264
|
pushField(fields, "messages", payload.messages);
|
|
464018
464265
|
pushField(fields, "client_tool_allowlist", payload.client_tool_allowlist);
|
|
464019
|
-
if (
|
|
464266
|
+
if (isRecord13(payload.client_toolset)) {
|
|
464020
464267
|
pushField(fields, "client_toolset.base", payload.client_toolset.base);
|
|
464021
464268
|
pushField(fields, "client_toolset.include", payload.client_toolset.include);
|
|
464022
464269
|
}
|
|
@@ -464033,9 +464280,9 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
464033
464280
|
const fields = [];
|
|
464034
464281
|
pushField(fields, "agent_id", command.agent_id, "agent");
|
|
464035
464282
|
pushField(fields, "conversation_id", command.conversation_id, "conversation");
|
|
464036
|
-
if (
|
|
464283
|
+
if (isRecord13(command.create_agent))
|
|
464037
464284
|
fields.push("create_agent=true");
|
|
464038
|
-
if (
|
|
464285
|
+
if (isRecord13(command.create_conversation)) {
|
|
464039
464286
|
fields.push("create_conversation=true");
|
|
464040
464287
|
}
|
|
464041
464288
|
pushField(fields, "cwd", command.cwd);
|
|
@@ -464044,17 +464291,17 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
464044
464291
|
return fields;
|
|
464045
464292
|
}
|
|
464046
464293
|
function summarizeV2Command(parsed) {
|
|
464047
|
-
if (!
|
|
464294
|
+
if (!isRecord13(parsed) || typeof parsed.type !== "string")
|
|
464048
464295
|
return "unknown";
|
|
464049
464296
|
const fields = [];
|
|
464050
|
-
const runtime =
|
|
464297
|
+
const runtime = isRecord13(parsed.runtime) ? parsed.runtime : null;
|
|
464051
464298
|
if (runtime) {
|
|
464052
464299
|
fields.push(`runtime=${runtime.agent_id ?? "<unknown>"}/${runtime.conversation_id ?? "<unknown>"}`);
|
|
464053
464300
|
}
|
|
464054
464301
|
pushField(fields, "request_id", parsed.request_id);
|
|
464055
464302
|
if (parsed.type === "input") {
|
|
464056
464303
|
fields.push(...summarizeInputPayload(parsed.payload));
|
|
464057
|
-
} else if (parsed.type === "change_device_state" &&
|
|
464304
|
+
} else if (parsed.type === "change_device_state" && isRecord13(parsed.payload)) {
|
|
464058
464305
|
pushField(fields, "mode", parsed.payload.mode);
|
|
464059
464306
|
pushField(fields, "cwd", parsed.payload.cwd);
|
|
464060
464307
|
pushField(fields, "agent_id", parsed.payload.agent_id);
|
|
@@ -464064,7 +464311,7 @@ function summarizeV2Command(parsed) {
|
|
|
464064
464311
|
} else if (parsed.type === "runtime_external_tools_update" && Array.isArray(parsed.updates)) {
|
|
464065
464312
|
fields.push(`updates=${parsed.updates.length}`);
|
|
464066
464313
|
fields.push(`runtimes=${parsed.updates.reduce((count, update2) => {
|
|
464067
|
-
return count + (
|
|
464314
|
+
return count + (isRecord13(update2) && Array.isArray(update2.runtimes) ? update2.runtimes.length : 0);
|
|
464068
464315
|
}, 0)}`);
|
|
464069
464316
|
} else {
|
|
464070
464317
|
for (const key2 of [
|
|
@@ -465096,8 +465343,8 @@ async function startConnectedListenerRuntime(runtime, transport, opts, processQu
|
|
|
465096
465343
|
startConnectionHeartbeat(runtime, transport, () => {
|
|
465097
465344
|
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
465345
|
runtime.socket?.terminate();
|
|
465099
|
-
}, () => {
|
|
465100
|
-
return safeTransportSend(
|
|
465346
|
+
}, (heartbeatTransport) => {
|
|
465347
|
+
return safeTransportSend(heartbeatTransport, { type: "ping" }, "listener_ping_send_failed", "listener_heartbeat");
|
|
465101
465348
|
});
|
|
465102
465349
|
}
|
|
465103
465350
|
if (options3.startProcessServices === false)
|
|
@@ -466127,7 +466374,7 @@ function decodeJwtClaims(token2, sharedSecret) {
|
|
|
466127
466374
|
} catch {
|
|
466128
466375
|
return { error: unauthorized("invalid websocket jwt") };
|
|
466129
466376
|
}
|
|
466130
|
-
if (!
|
|
466377
|
+
if (!isRecord14(header) || header.alg !== "HS256") {
|
|
466131
466378
|
return { error: unauthorized("invalid websocket jwt") };
|
|
466132
466379
|
}
|
|
466133
466380
|
const expectedSignature = createHmac("sha256", sharedSecret).update(`${encodedHeader}.${encodedClaims}`).digest();
|
|
@@ -466165,7 +466412,7 @@ function audienceMatches(actual, expectedAudience) {
|
|
|
466165
466412
|
return false;
|
|
466166
466413
|
}
|
|
466167
466414
|
function isJwtClaims(value) {
|
|
466168
|
-
if (!
|
|
466415
|
+
if (!isRecord14(value) || !Number.isSafeInteger(value.exp)) {
|
|
466169
466416
|
return false;
|
|
466170
466417
|
}
|
|
466171
466418
|
if (value.nbf !== undefined && !Number.isSafeInteger(value.nbf)) {
|
|
@@ -466185,7 +466432,7 @@ function isJwtClaims(value) {
|
|
|
466185
466432
|
}
|
|
466186
466433
|
return true;
|
|
466187
466434
|
}
|
|
466188
|
-
function
|
|
466435
|
+
function isRecord14(value) {
|
|
466189
466436
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
466190
466437
|
}
|
|
466191
466438
|
function base64UrlDecode(value) {
|
|
@@ -468375,13 +468622,14 @@ function shouldAcquireStandaloneListenerLock() {
|
|
|
468375
468622
|
return shouldAcquireManualListenerLock(getSpawnerListenerInstanceId(), process.env.LETTA_DESKTOP_MODE === "1");
|
|
468376
468623
|
}
|
|
468377
468624
|
function printListenUsage() {
|
|
468378
|
-
console.log(`Usage: letta server [--env-name <name>] [--channels <list>] [--debug]
|
|
468625
|
+
console.log(`Usage: letta server [--env-name <name>] [--channels <list>] [--skills <path>] [--debug]
|
|
468379
468626
|
`);
|
|
468380
468627
|
console.log(`Register this letta-code instance to receive messages from Letta Cloud.
|
|
468381
468628
|
`);
|
|
468382
468629
|
console.log("Options:");
|
|
468383
468630
|
console.log(" --env-name <name> Friendly name for this environment (uses hostname if not provided)");
|
|
468384
468631
|
console.log(" --channels <list> Comma-separated channel names to enable (e.g. telegram)");
|
|
468632
|
+
console.log(" --skills <path> Use this directory for environment-provided skills");
|
|
468385
468633
|
console.log(" --install-channel-runtimes Install missing runtime deps for the selected channels before startup");
|
|
468386
468634
|
console.log(" --debug Plain-text mode: log all WebSocket events instead of interactive UI");
|
|
468387
468635
|
console.log(` -h, --help Show this help message
|
|
@@ -468415,6 +468663,7 @@ async function runListenSubcommand(argv) {
|
|
|
468415
468663
|
return 1;
|
|
468416
468664
|
}
|
|
468417
468665
|
const debugMode = !!values2.debug;
|
|
468666
|
+
const skillsDirectory = values2.skills ?? process.env.LETTA_SKILLS_DIRECTORY;
|
|
468418
468667
|
if (values2.help) {
|
|
468419
468668
|
printListenUsage();
|
|
468420
468669
|
return 0;
|
|
@@ -468730,6 +468979,7 @@ async function runListenSubcommand(argv) {
|
|
|
468730
468979
|
supportsSplitStatusChannels: nextSupportsSplitStatusChannels,
|
|
468731
468980
|
deviceId,
|
|
468732
468981
|
connectionName,
|
|
468982
|
+
skillsDirectory,
|
|
468733
468983
|
onWsEvent: shouldLogWsEvents ? wsEventLogger : undefined,
|
|
468734
468984
|
onStatusChange: (status) => {
|
|
468735
468985
|
sessionLog.log(`status: ${status}`);
|
|
@@ -468795,6 +469045,7 @@ async function runListenSubcommand(argv) {
|
|
|
468795
469045
|
supportsSplitStatusChannels: nextSupportsSplitStatusChannels,
|
|
468796
469046
|
deviceId,
|
|
468797
469047
|
connectionName,
|
|
469048
|
+
skillsDirectory,
|
|
468798
469049
|
onWsEvent: shouldLogWsEvents ? wsEventLogger : undefined,
|
|
468799
469050
|
onStatusChange: (status) => {
|
|
468800
469051
|
sessionLog.log(`status: ${status}`);
|
|
@@ -468887,6 +469138,7 @@ var init_listen = __esm(async () => {
|
|
|
468887
469138
|
LISTEN_OPTIONS = {
|
|
468888
469139
|
"env-name": { type: "string" },
|
|
468889
469140
|
channels: { type: "string" },
|
|
469141
|
+
skills: { type: "string" },
|
|
468890
469142
|
"install-channel-runtimes": { type: "boolean" },
|
|
468891
469143
|
help: { type: "boolean", short: "h" },
|
|
468892
469144
|
debug: { type: "boolean" }
|
|
@@ -470434,7 +470686,7 @@ import {
|
|
|
470434
470686
|
} from "node:fs";
|
|
470435
470687
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
470436
470688
|
import path41 from "node:path";
|
|
470437
|
-
function
|
|
470689
|
+
function isRecord15(value) {
|
|
470438
470690
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
470439
470691
|
}
|
|
470440
470692
|
function isPathInsideOrEqual2(childPath, parentPath) {
|
|
@@ -470450,7 +470702,7 @@ function readPackageJson(packageJsonPath) {
|
|
|
470450
470702
|
} catch (error54) {
|
|
470451
470703
|
throw new Error(`Could not read package.json: ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
470452
470704
|
}
|
|
470453
|
-
if (!
|
|
470705
|
+
if (!isRecord15(parsed)) {
|
|
470454
470706
|
throw new Error("package.json must be an object");
|
|
470455
470707
|
}
|
|
470456
470708
|
return parsed;
|
|
@@ -470460,7 +470712,7 @@ function formatRepository(repository) {
|
|
|
470460
470712
|
const trimmed2 = repository.trim();
|
|
470461
470713
|
return trimmed2 || undefined;
|
|
470462
470714
|
}
|
|
470463
|
-
if (!
|
|
470715
|
+
if (!isRecord15(repository))
|
|
470464
470716
|
return;
|
|
470465
470717
|
const url2 = repository.url;
|
|
470466
470718
|
if (typeof url2 !== "string")
|
|
@@ -470990,7 +471242,7 @@ function hasRuntimeDependencies(packageJson) {
|
|
|
470990
471242
|
if (!packageJson)
|
|
470991
471243
|
return false;
|
|
470992
471244
|
const dependencies4 = packageJson.dependencies;
|
|
470993
|
-
return
|
|
471245
|
+
return isRecord15(dependencies4) && Object.keys(dependencies4).length > 0;
|
|
470994
471246
|
}
|
|
470995
471247
|
function readPackageJsonIfExists(packageDirectory) {
|
|
470996
471248
|
const packageJsonPath = path41.join(packageDirectory, "package.json");
|
|
@@ -477806,6 +478058,9 @@ function uniqueSources(sources) {
|
|
|
477806
478058
|
byKey.set(sourceKey(source2), source2);
|
|
477807
478059
|
return [...byKey.values()];
|
|
477808
478060
|
}
|
|
478061
|
+
function channelTagsForSources(sources) {
|
|
478062
|
+
return [...new Set(sources.map((source2) => `channel:${source2.channel}`))];
|
|
478063
|
+
}
|
|
477809
478064
|
function stopReasonFromDelta(message) {
|
|
477810
478065
|
const delta2 = message.delta;
|
|
477811
478066
|
return delta2.message_type === "stop_reason" && "stop_reason" in delta2 && typeof delta2.stop_reason === "string" ? delta2.stop_reason : null;
|
|
@@ -478047,9 +478302,11 @@ class ChannelGateway {
|
|
|
478047
478302
|
}
|
|
478048
478303
|
async performRuntimeRegistration(state, delivery) {
|
|
478049
478304
|
const tool2 = await this.hooks.buildExternalTool(delivery.runtime, delivery.sources);
|
|
478305
|
+
const conversationTags = channelTagsForSources(delivery.sources);
|
|
478050
478306
|
const signature = JSON.stringify({
|
|
478051
478307
|
mode: delivery.defaultPermissionMode ?? null,
|
|
478052
|
-
tool: tool2
|
|
478308
|
+
tool: tool2,
|
|
478309
|
+
conversationTags
|
|
478053
478310
|
});
|
|
478054
478311
|
if (state.registrationSignature === signature && state.registration) {
|
|
478055
478312
|
return state.registration;
|
|
@@ -478057,6 +478314,7 @@ class ChannelGateway {
|
|
|
478057
478314
|
const registration = this.client.runtimeStart({
|
|
478058
478315
|
agent_id: delivery.runtime.agent_id,
|
|
478059
478316
|
conversation_id: delivery.runtime.conversation_id,
|
|
478317
|
+
...conversationTags.length > 0 ? { conversation_source_tags: conversationTags } : {},
|
|
478060
478318
|
...delivery.defaultPermissionMode ? { mode: delivery.defaultPermissionMode } : {},
|
|
478061
478319
|
recover_approvals: true,
|
|
478062
478320
|
force_device_status: false,
|
|
@@ -492188,7 +492446,7 @@ async function connectMcpServer(config3, options3 = {}) {
|
|
|
492188
492446
|
return {
|
|
492189
492447
|
content: Array.isArray(result.content) ? result.content : [],
|
|
492190
492448
|
...result.isError === true ? { isError: true } : {},
|
|
492191
|
-
...
|
|
492449
|
+
...isRecord16(result.structuredContent) ? { structuredContent: result.structuredContent } : {}
|
|
492192
492450
|
};
|
|
492193
492451
|
},
|
|
492194
492452
|
close: async () => {
|
|
@@ -492261,11 +492519,11 @@ function mergeHeaders4(init, headers) {
|
|
|
492261
492519
|
};
|
|
492262
492520
|
}
|
|
492263
492521
|
function normalizeInputSchema(value) {
|
|
492264
|
-
if (
|
|
492522
|
+
if (isRecord16(value) && value.type === "object")
|
|
492265
492523
|
return value;
|
|
492266
492524
|
return { type: "object", properties: {} };
|
|
492267
492525
|
}
|
|
492268
|
-
function
|
|
492526
|
+
function isRecord16(value) {
|
|
492269
492527
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
492270
492528
|
}
|
|
492271
492529
|
var DEFAULT_CLIENT_INFO;
|
|
@@ -492277,7 +492535,7 @@ var init_mcp_client = __esm(() => {
|
|
|
492277
492535
|
init_streamableHttp();
|
|
492278
492536
|
DEFAULT_CLIENT_INFO = {
|
|
492279
492537
|
name: "letta-code",
|
|
492280
|
-
version: "0.30.
|
|
492538
|
+
version: "0.30.10"
|
|
492281
492539
|
};
|
|
492282
492540
|
});
|
|
492283
492541
|
|
|
@@ -492673,7 +492931,7 @@ function toExternalToolResult(result) {
|
|
|
492673
492931
|
};
|
|
492674
492932
|
}
|
|
492675
492933
|
function normalizeContent2(item) {
|
|
492676
|
-
if (
|
|
492934
|
+
if (isRecord17(item)) {
|
|
492677
492935
|
if (item.type === "text" && typeof item.text === "string") {
|
|
492678
492936
|
return { type: "text", text: item.text };
|
|
492679
492937
|
}
|
|
@@ -492687,7 +492945,7 @@ function normalizeContent2(item) {
|
|
|
492687
492945
|
}
|
|
492688
492946
|
return { type: "text", text: JSON.stringify(item) };
|
|
492689
492947
|
}
|
|
492690
|
-
function
|
|
492948
|
+
function isRecord17(value) {
|
|
492691
492949
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
492692
492950
|
}
|
|
492693
492951
|
var CLIENT_MCP_RUNTIME_KEY;
|
|
@@ -495437,6 +495695,15 @@ ${loadedContents.join(`
|
|
|
495437
495695
|
const lastReasoning = reversed.find((line) => line.kind === "reasoning" && ("text" in line) && typeof line.text === "string" && line.text.trim().length > 0);
|
|
495438
495696
|
const lastToolResult = reversed.find((line) => line.kind === "tool_call" && ("resultText" in line) && typeof line.resultText === "string" && (line.resultText ?? "").trim().length > 0);
|
|
495439
495697
|
const resultText = lastAssistant?.text || lastReasoning?.text || lastToolResult?.resultText || "No assistant response found";
|
|
495698
|
+
if (!lastAssistant && (lastReasoning || lastToolResult)) {
|
|
495699
|
+
trackEndTurnNoAssistant({
|
|
495700
|
+
fallbackKind: lastReasoning ? "reasoning" : "tool_call",
|
|
495701
|
+
modelHandle: agent2.llm_config?.model ?? model,
|
|
495702
|
+
runId: lastKnownRunId ?? undefined,
|
|
495703
|
+
isSubagent,
|
|
495704
|
+
subagentType: systemPromptPreset ?? agent2.tags?.find((t2) => t2.startsWith("type:"))?.slice(5)
|
|
495705
|
+
});
|
|
495706
|
+
}
|
|
495440
495707
|
const stats = sessionStats.getSnapshot();
|
|
495441
495708
|
const usage = {
|
|
495442
495709
|
prompt_tokens: stats.usage.promptTokens,
|
|
@@ -500356,8 +500623,9 @@ function useLocalModAdapter(context3, options3 = {}) {
|
|
|
500356
500623
|
...agentModsDirectory ? { agentModsDirectory } : {},
|
|
500357
500624
|
disabled,
|
|
500358
500625
|
getBackend,
|
|
500359
|
-
getClient
|
|
500360
|
-
|
|
500626
|
+
getClient,
|
|
500627
|
+
onNotification: options3.onNotification
|
|
500628
|
+
}), [agentModsDirectory, disabled, options3.onNotification]);
|
|
500361
500629
|
const snapshot = import_react43.useSyncExternalStore(adapter.subscribe, adapter.getSnapshot, adapter.getSnapshot);
|
|
500362
500630
|
import_react43.useEffect(() => {
|
|
500363
500631
|
adapter.reload();
|
|
@@ -552980,6 +553248,7 @@ function App2({
|
|
|
552980
553248
|
}, [isExecutingTool]);
|
|
552981
553249
|
const refreshDerivedRef = import_react120.useRef(null);
|
|
552982
553250
|
const appendTaskNotificationEvents = import_react120.useCallback((summaries) => appendTaskNotificationEventsToBuffer(summaries, buffersRef.current, () => uid("event"), () => refreshDerivedRef.current?.()), []);
|
|
553251
|
+
const appendModNotification = import_react120.useCallback((message) => appendTaskNotificationEvents([message]), [appendTaskNotificationEvents]);
|
|
552983
553252
|
const consumeQueuedMessages = import_react120.useCallback(() => {
|
|
552984
553253
|
const len = tuiQueueRef.current?.length ?? 0;
|
|
552985
553254
|
if (len === 0)
|
|
@@ -553399,7 +553668,8 @@ function App2({
|
|
|
553399
553668
|
const agentModsDirectory = modContext.memfs.enabled && modContext.memfs.memoryDir ? join92(modContext.memfs.memoryDir, "mods") : null;
|
|
553400
553669
|
const modAdapter = useLocalModAdapter(modContext, {
|
|
553401
553670
|
agentModsDirectory,
|
|
553402
|
-
disabled: modsDisabled
|
|
553671
|
+
disabled: modsDisabled,
|
|
553672
|
+
onNotification: appendModNotification
|
|
553403
553673
|
});
|
|
553404
553674
|
import_react120.useEffect(() => {
|
|
553405
553675
|
modAdapterRef.current = modAdapter;
|
|
@@ -559380,4 +559650,4 @@ function registerBunOAuthFlows() {
|
|
|
559380
559650
|
registerBunOAuthFlows();
|
|
559381
559651
|
await init_src5().then(() => exports_src2);
|
|
559382
559652
|
|
|
559383
|
-
//# debugId=
|
|
559653
|
+
//# debugId=BC797C70CE06CED564756E2164756E21
|