@letta-ai/letta-code 0.24.2 → 0.24.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +679 -172
- package/package.json +1 -1
- package/skills/migrating-memory/SKILL.md +15 -9
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.24.
|
|
3272
|
+
version: "0.24.4",
|
|
3273
3273
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3274
3274
|
type: "module",
|
|
3275
3275
|
bin: {
|
|
@@ -51442,7 +51442,8 @@ var init_readOnlyShell = __esm(() => {
|
|
|
51442
51442
|
"sleep"
|
|
51443
51443
|
]);
|
|
51444
51444
|
SAFE_LETTA_COMMANDS = {
|
|
51445
|
-
|
|
51445
|
+
memory: new Set(["status", "help", "backups", "export", "tokens"]),
|
|
51446
|
+
memfs: new Set(["status", "help", "backups", "export", "tokens"]),
|
|
51446
51447
|
agents: new Set(["list", "help"]),
|
|
51447
51448
|
messages: new Set(["search", "list", "help"]),
|
|
51448
51449
|
blocks: new Set(["list", "help"])
|
|
@@ -83492,46 +83493,58 @@ var init_memoryReminder = __esm(() => {
|
|
|
83492
83493
|
};
|
|
83493
83494
|
});
|
|
83494
83495
|
|
|
83495
|
-
// src/
|
|
83496
|
+
// src/utils/systemPromptSize.ts
|
|
83496
83497
|
import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync19 } from "node:fs";
|
|
83497
83498
|
import { join as join29 } from "node:path";
|
|
83498
83499
|
function estimateSystemTokens(text) {
|
|
83499
|
-
return Math.ceil(Buffer.byteLength(text, "utf8") /
|
|
83500
|
+
return Math.ceil(Buffer.byteLength(text, "utf8") / SYSTEM_PROMPT_BYTES_PER_TOKEN);
|
|
83500
83501
|
}
|
|
83501
|
-
function
|
|
83502
|
-
|
|
83503
|
-
|
|
83504
|
-
|
|
83502
|
+
function normalizePath2(value) {
|
|
83503
|
+
return value.replaceAll("\\", "/");
|
|
83504
|
+
}
|
|
83505
|
+
function walkMarkdownFiles(dir) {
|
|
83506
|
+
if (!existsSync26(dir)) {
|
|
83507
|
+
return [];
|
|
83505
83508
|
}
|
|
83506
|
-
const
|
|
83507
|
-
|
|
83508
|
-
|
|
83509
|
+
const out = [];
|
|
83510
|
+
const entries = readdirSync8(dir, { withFileTypes: true });
|
|
83511
|
+
for (const entry of entries) {
|
|
83512
|
+
if (entry.name.startsWith(".")) {
|
|
83513
|
+
continue;
|
|
83509
83514
|
}
|
|
83510
|
-
const
|
|
83511
|
-
|
|
83512
|
-
|
|
83513
|
-
|
|
83514
|
-
continue;
|
|
83515
|
-
}
|
|
83516
|
-
const full = join29(dir, entry.name);
|
|
83517
|
-
if (entry.isDirectory()) {
|
|
83518
|
-
if (entry.name === ".git") {
|
|
83519
|
-
continue;
|
|
83520
|
-
}
|
|
83521
|
-
out.push(...walkMarkdownFiles(full));
|
|
83522
|
-
continue;
|
|
83523
|
-
}
|
|
83524
|
-
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
83525
|
-
out.push(full);
|
|
83526
|
-
}
|
|
83515
|
+
const full = join29(dir, entry.name);
|
|
83516
|
+
if (entry.isDirectory()) {
|
|
83517
|
+
out.push(...walkMarkdownFiles(full));
|
|
83518
|
+
continue;
|
|
83527
83519
|
}
|
|
83528
|
-
|
|
83529
|
-
|
|
83530
|
-
|
|
83520
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
83521
|
+
out.push(full);
|
|
83522
|
+
}
|
|
83523
|
+
}
|
|
83524
|
+
return out;
|
|
83525
|
+
}
|
|
83526
|
+
function estimateSystemPromptSize(memoryDir) {
|
|
83527
|
+
const systemDir = join29(memoryDir, "system");
|
|
83528
|
+
if (!existsSync26(systemDir)) {
|
|
83529
|
+
return { total: 0, files: [] };
|
|
83530
|
+
}
|
|
83531
|
+
const files = walkMarkdownFiles(systemDir).sort();
|
|
83532
|
+
const rows = [];
|
|
83533
|
+
for (const filePath of files) {
|
|
83531
83534
|
const text = readFileSync19(filePath, "utf8");
|
|
83532
|
-
|
|
83533
|
-
|
|
83535
|
+
const rel = normalizePath2(filePath.slice(memoryDir.length + 1));
|
|
83536
|
+
rows.push({ path: rel, tokens: estimateSystemTokens(text) });
|
|
83537
|
+
}
|
|
83538
|
+
const total = rows.reduce((sum, row) => sum + row.tokens, 0);
|
|
83539
|
+
return { total, files: rows };
|
|
83534
83540
|
}
|
|
83541
|
+
function estimateSystemPromptTokensFromMemoryDir(memoryDir) {
|
|
83542
|
+
return estimateSystemPromptSize(memoryDir).total;
|
|
83543
|
+
}
|
|
83544
|
+
var SYSTEM_PROMPT_BYTES_PER_TOKEN = 4;
|
|
83545
|
+
var init_systemPromptSize = () => {};
|
|
83546
|
+
|
|
83547
|
+
// src/cli/helpers/systemPromptWarning.ts
|
|
83535
83548
|
function setSystemPromptDoctorState(agentId, estimatedTokens) {
|
|
83536
83549
|
const nextState = {
|
|
83537
83550
|
estimated_tokens: estimatedTokens,
|
|
@@ -83574,11 +83587,12 @@ function buildStartupSystemPromptWarning(agentState) {
|
|
|
83574
83587
|
}
|
|
83575
83588
|
return null;
|
|
83576
83589
|
}
|
|
83577
|
-
var STARTUP_SYSTEM_PROMPT_WARNING_THRESHOLD_TOKENS = 30000,
|
|
83590
|
+
var STARTUP_SYSTEM_PROMPT_WARNING_THRESHOLD_TOKENS = 30000, systemPromptDoctorStateByAgent;
|
|
83578
83591
|
var init_systemPromptWarning = __esm(() => {
|
|
83579
83592
|
init_memoryFilesystem();
|
|
83580
83593
|
init_settings_manager();
|
|
83581
83594
|
init_debug();
|
|
83595
|
+
init_systemPromptSize();
|
|
83582
83596
|
systemPromptDoctorStateByAgent = new Map;
|
|
83583
83597
|
});
|
|
83584
83598
|
|
|
@@ -87183,10 +87197,132 @@ var init_reflectionTranscript = __esm(() => {
|
|
|
87183
87197
|
init_directoryLimits();
|
|
87184
87198
|
});
|
|
87185
87199
|
|
|
87200
|
+
// src/utils/tuiPerf.ts
|
|
87201
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync20 } from "node:fs";
|
|
87202
|
+
import { dirname as dirname14 } from "node:path";
|
|
87203
|
+
function ensureExitHook() {
|
|
87204
|
+
if (tuiPerfExitHookRegistered) {
|
|
87205
|
+
return;
|
|
87206
|
+
}
|
|
87207
|
+
tuiPerfExitHookRegistered = true;
|
|
87208
|
+
process.once("beforeExit", () => {
|
|
87209
|
+
flushTuiPerfTelemetry();
|
|
87210
|
+
});
|
|
87211
|
+
}
|
|
87212
|
+
function scheduleTuiPerfFlush() {
|
|
87213
|
+
if (tuiPerfFlushTimer) {
|
|
87214
|
+
return;
|
|
87215
|
+
}
|
|
87216
|
+
tuiPerfFlushTimer = setTimeout(() => {
|
|
87217
|
+
tuiPerfFlushTimer = null;
|
|
87218
|
+
flushTuiPerfTelemetry();
|
|
87219
|
+
}, TUI_PERF_FLUSH_INTERVAL_MS);
|
|
87220
|
+
const timerWithUnref = tuiPerfFlushTimer;
|
|
87221
|
+
timerWithUnref.unref?.();
|
|
87222
|
+
}
|
|
87223
|
+
function recordTuiPerf(key, sample) {
|
|
87224
|
+
if (!TUI_PERF_ENABLED || !TUI_PERF_FILE) {
|
|
87225
|
+
return;
|
|
87226
|
+
}
|
|
87227
|
+
ensureExitHook();
|
|
87228
|
+
if (tuiPerfWindowStartedAt === 0) {
|
|
87229
|
+
tuiPerfWindowStartedAt = Date.now();
|
|
87230
|
+
}
|
|
87231
|
+
const bytes = sample?.bytes ?? 0;
|
|
87232
|
+
const ms = sample?.ms ?? 0;
|
|
87233
|
+
const bucket = tuiPerfBuckets.get(key) ?? {
|
|
87234
|
+
count: 0,
|
|
87235
|
+
bytes: 0,
|
|
87236
|
+
ms: 0,
|
|
87237
|
+
maxBytes: 0,
|
|
87238
|
+
maxMs: 0
|
|
87239
|
+
};
|
|
87240
|
+
bucket.count += 1;
|
|
87241
|
+
bucket.bytes += bytes;
|
|
87242
|
+
bucket.ms += ms;
|
|
87243
|
+
bucket.maxBytes = Math.max(bucket.maxBytes, bytes);
|
|
87244
|
+
bucket.maxMs = Math.max(bucket.maxMs, ms);
|
|
87245
|
+
tuiPerfBuckets.set(key, bucket);
|
|
87246
|
+
scheduleTuiPerfFlush();
|
|
87247
|
+
}
|
|
87248
|
+
function recordTuiJsonPayload(key, value) {
|
|
87249
|
+
if (!TUI_PERF_ENABLED || !TUI_PERF_FILE) {
|
|
87250
|
+
return;
|
|
87251
|
+
}
|
|
87252
|
+
try {
|
|
87253
|
+
recordTuiPerf(key, { bytes: Buffer.byteLength(JSON.stringify(value)) });
|
|
87254
|
+
} catch {
|
|
87255
|
+
recordTuiPerf(key);
|
|
87256
|
+
}
|
|
87257
|
+
}
|
|
87258
|
+
function flushTuiPerfTelemetry() {
|
|
87259
|
+
if (tuiPerfBuckets.size === 0) {
|
|
87260
|
+
tuiPerfWindowStartedAt = 0;
|
|
87261
|
+
return;
|
|
87262
|
+
}
|
|
87263
|
+
const filePath = TUI_PERF_FILE;
|
|
87264
|
+
if (!filePath) {
|
|
87265
|
+
tuiPerfBuckets.clear();
|
|
87266
|
+
tuiPerfWindowStartedAt = 0;
|
|
87267
|
+
return;
|
|
87268
|
+
}
|
|
87269
|
+
const windowMs = Math.max(1, Date.now() - tuiPerfWindowStartedAt);
|
|
87270
|
+
const totals = {
|
|
87271
|
+
count: 0,
|
|
87272
|
+
bytes: 0,
|
|
87273
|
+
ms: 0,
|
|
87274
|
+
maxBytes: 0,
|
|
87275
|
+
maxMs: 0
|
|
87276
|
+
};
|
|
87277
|
+
const buckets = {};
|
|
87278
|
+
for (const [key, bucket] of [...tuiPerfBuckets.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
87279
|
+
totals.count += bucket.count;
|
|
87280
|
+
totals.bytes += bucket.bytes;
|
|
87281
|
+
totals.ms += bucket.ms;
|
|
87282
|
+
totals.maxBytes = Math.max(totals.maxBytes, bucket.maxBytes);
|
|
87283
|
+
totals.maxMs = Math.max(totals.maxMs, bucket.maxMs);
|
|
87284
|
+
buckets[key] = {
|
|
87285
|
+
...bucket,
|
|
87286
|
+
avg_bytes: bucket.count > 0 ? bucket.bytes / bucket.count : 0,
|
|
87287
|
+
avg_ms: bucket.count > 0 ? bucket.ms / bucket.count : 0
|
|
87288
|
+
};
|
|
87289
|
+
}
|
|
87290
|
+
try {
|
|
87291
|
+
const dir = dirname14(filePath);
|
|
87292
|
+
if (tuiPerfFileDirEnsured !== dir) {
|
|
87293
|
+
mkdirSync20(dir, { recursive: true });
|
|
87294
|
+
tuiPerfFileDirEnsured = dir;
|
|
87295
|
+
}
|
|
87296
|
+
appendFileSync3(filePath, `${JSON.stringify({
|
|
87297
|
+
ts: new Date().toISOString(),
|
|
87298
|
+
event: "tui_activity",
|
|
87299
|
+
window_ms: windowMs,
|
|
87300
|
+
totals,
|
|
87301
|
+
buckets
|
|
87302
|
+
})}
|
|
87303
|
+
`, { encoding: "utf8" });
|
|
87304
|
+
} catch (error) {
|
|
87305
|
+
if (!tuiPerfWarningEmitted) {
|
|
87306
|
+
tuiPerfWarningEmitted = true;
|
|
87307
|
+
console.error(`[TUI Perf] Failed to write LETTA_TUI_PERF_FILE=${filePath}`, error);
|
|
87308
|
+
}
|
|
87309
|
+
} finally {
|
|
87310
|
+
tuiPerfBuckets.clear();
|
|
87311
|
+
tuiPerfWindowStartedAt = 0;
|
|
87312
|
+
}
|
|
87313
|
+
}
|
|
87314
|
+
var TUI_PERF_FLUSH_INTERVAL_MS = 1000, TUI_PERF_ENV_VALUES, TUI_PERF_ENABLED, TUI_PERF_FILE, tuiPerfBuckets, tuiPerfFlushTimer = null, tuiPerfWindowStartedAt = 0, tuiPerfFileDirEnsured = null, tuiPerfWarningEmitted = false, tuiPerfExitHookRegistered = false;
|
|
87315
|
+
var init_tuiPerf = __esm(() => {
|
|
87316
|
+
TUI_PERF_ENV_VALUES = new Set(["1", "true", "yes"]);
|
|
87317
|
+
TUI_PERF_ENABLED = TUI_PERF_ENV_VALUES.has((process.env.LETTA_TUI_PERF ?? "").toLowerCase());
|
|
87318
|
+
TUI_PERF_FILE = process.env.LETTA_TUI_PERF_FILE?.trim() || null;
|
|
87319
|
+
tuiPerfBuckets = new Map;
|
|
87320
|
+
});
|
|
87321
|
+
|
|
87186
87322
|
// src/cli/helpers/chunkLog.ts
|
|
87187
87323
|
import {
|
|
87188
87324
|
existsSync as existsSync28,
|
|
87189
|
-
mkdirSync as
|
|
87325
|
+
mkdirSync as mkdirSync21,
|
|
87190
87326
|
readdirSync as readdirSync9,
|
|
87191
87327
|
unlinkSync as unlinkSync7,
|
|
87192
87328
|
writeFileSync as writeFileSync16
|
|
@@ -87287,7 +87423,7 @@ class ChunkLog {
|
|
|
87287
87423
|
return;
|
|
87288
87424
|
try {
|
|
87289
87425
|
if (!existsSync28(this.agentDir)) {
|
|
87290
|
-
|
|
87426
|
+
mkdirSync21(this.agentDir, { recursive: true });
|
|
87291
87427
|
}
|
|
87292
87428
|
this.dirCreated = true;
|
|
87293
87429
|
} catch (e) {
|
|
@@ -87427,6 +87563,60 @@ class StreamProcessor {
|
|
|
87427
87563
|
}
|
|
87428
87564
|
|
|
87429
87565
|
// src/cli/helpers/stream.ts
|
|
87566
|
+
function summarizeStreamForDebug(stream2) {
|
|
87567
|
+
if (!stream2 || typeof stream2 !== "object") {
|
|
87568
|
+
return `type=${typeof stream2}`;
|
|
87569
|
+
}
|
|
87570
|
+
const record = stream2;
|
|
87571
|
+
const ctor = stream2.constructor?.name;
|
|
87572
|
+
const controller = record.controller && typeof record.controller === "object" ? record.controller : null;
|
|
87573
|
+
const keys = Object.keys(record).slice(0, 8);
|
|
87574
|
+
return [
|
|
87575
|
+
`ctor=${ctor ?? "unknown"}`,
|
|
87576
|
+
`asyncIterator=${typeof record[Symbol.asyncIterator]}`,
|
|
87577
|
+
`controller=${typeof record.controller}`,
|
|
87578
|
+
`controllerAbort=${typeof controller?.abort}`,
|
|
87579
|
+
`controllerSignal=${typeof controller?.signal}`,
|
|
87580
|
+
keys.length > 0 ? `keys=${keys.join(",")}` : "keys=(none)"
|
|
87581
|
+
].join(" ");
|
|
87582
|
+
}
|
|
87583
|
+
function summarizeChunkForDebug(chunk) {
|
|
87584
|
+
if (!chunk) {
|
|
87585
|
+
return "none";
|
|
87586
|
+
}
|
|
87587
|
+
const record = chunk;
|
|
87588
|
+
const parts = [`message_type=${chunk.message_type ?? "unknown"}`];
|
|
87589
|
+
for (const key of ["run_id", "seq_id", "id", "otid", "tool_call_id"]) {
|
|
87590
|
+
const value = record[key];
|
|
87591
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
87592
|
+
parts.push(`${key}=${value}`);
|
|
87593
|
+
}
|
|
87594
|
+
}
|
|
87595
|
+
if (chunk.message_type === "stop_reason") {
|
|
87596
|
+
parts.push(`stop_reason=${String(record.stop_reason ?? "unknown")}`);
|
|
87597
|
+
}
|
|
87598
|
+
const toolCalls = record.tool_calls;
|
|
87599
|
+
if (Array.isArray(toolCalls)) {
|
|
87600
|
+
parts.push(`tool_calls=${toolCalls.length}`);
|
|
87601
|
+
}
|
|
87602
|
+
return parts.join(" ");
|
|
87603
|
+
}
|
|
87604
|
+
function abortStreamController(stream2, reason) {
|
|
87605
|
+
const controller = stream2.controller;
|
|
87606
|
+
if (!controller || typeof controller !== "object") {
|
|
87607
|
+
debugWarn("drainStream", "stream.controller is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream2));
|
|
87608
|
+
return;
|
|
87609
|
+
}
|
|
87610
|
+
const controllerRecord = controller;
|
|
87611
|
+
if (controllerRecord.signal?.aborted) {
|
|
87612
|
+
return;
|
|
87613
|
+
}
|
|
87614
|
+
if (typeof controllerRecord.abort !== "function") {
|
|
87615
|
+
debugWarn("drainStream", "stream.controller.abort is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream2));
|
|
87616
|
+
return;
|
|
87617
|
+
}
|
|
87618
|
+
controllerRecord.abort();
|
|
87619
|
+
}
|
|
87430
87620
|
function hasPaginatedItems(response) {
|
|
87431
87621
|
return !Array.isArray(response) && typeof response.getPaginatedItems === "function";
|
|
87432
87622
|
}
|
|
@@ -87504,28 +87694,27 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
87504
87694
|
let stopReason = null;
|
|
87505
87695
|
let hasCalledFirstMessage = false;
|
|
87506
87696
|
let fallbackError = null;
|
|
87697
|
+
let lastChunkDebugSummary = "none";
|
|
87507
87698
|
let abortedViaListener = false;
|
|
87508
87699
|
const startAbortGen = buffers.abortGeneration || 0;
|
|
87509
87700
|
const abortHandler = () => {
|
|
87510
87701
|
abortedViaListener = true;
|
|
87511
|
-
|
|
87512
|
-
debugWarn("drainStream", "stream.controller is undefined - cannot abort HTTP request");
|
|
87513
|
-
return;
|
|
87514
|
-
}
|
|
87515
|
-
if (!stream2.controller.signal.aborted) {
|
|
87516
|
-
stream2.controller.abort();
|
|
87517
|
-
}
|
|
87702
|
+
abortStreamController(stream2, "abort_signal");
|
|
87518
87703
|
};
|
|
87519
87704
|
if (abortSignal && !abortSignal.aborted) {
|
|
87520
87705
|
abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
87521
87706
|
} else if (abortSignal?.aborted) {
|
|
87522
87707
|
abortedViaListener = true;
|
|
87523
|
-
|
|
87524
|
-
stream2.controller.abort();
|
|
87525
|
-
}
|
|
87708
|
+
abortStreamController(stream2, "pre_aborted_signal");
|
|
87526
87709
|
}
|
|
87527
87710
|
try {
|
|
87711
|
+
const asyncIterator = stream2[Symbol.asyncIterator];
|
|
87712
|
+
if (typeof asyncIterator !== "function") {
|
|
87713
|
+
throw new TypeError(`Stream is not async iterable (${summarizeStreamForDebug(stream2)})`);
|
|
87714
|
+
}
|
|
87528
87715
|
for await (const chunk of stream2) {
|
|
87716
|
+
lastChunkDebugSummary = summarizeChunkForDebug(chunk);
|
|
87717
|
+
recordTuiJsonPayload(`stream_chunk:${chunk.message_type ?? "unknown"}`, chunk);
|
|
87529
87718
|
if ((buffers.abortGeneration || 0) !== startAbortGen) {
|
|
87530
87719
|
stopReason = "cancelled";
|
|
87531
87720
|
queueMicrotask(refresh);
|
|
@@ -87581,6 +87770,7 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
87581
87770
|
shouldAccumulate = shouldOutputChunk;
|
|
87582
87771
|
}
|
|
87583
87772
|
if (shouldAccumulate) {
|
|
87773
|
+
recordTuiJsonPayload(`stream_accumulate:${chunk.message_type ?? "unknown"}`, chunk);
|
|
87584
87774
|
onChunk(buffers, chunk, contextTracker);
|
|
87585
87775
|
queueMicrotask(refresh);
|
|
87586
87776
|
}
|
|
@@ -87592,7 +87782,10 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
87592
87782
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
87593
87783
|
const sdkDiagnostic = consumeLastSDKDiagnostic();
|
|
87594
87784
|
const errorMessageWithDiagnostic = sdkDiagnostic ? `${errorMessage} [${sdkDiagnostic}]` : errorMessage;
|
|
87595
|
-
debugWarn("drainStream", "Stream error caught:",
|
|
87785
|
+
debugWarn("drainStream", "Stream error caught: %s last_chunk=%s stream=%s", errorMessageWithDiagnostic, lastChunkDebugSummary, summarizeStreamForDebug(stream2));
|
|
87786
|
+
if (e instanceof Error && e.stack) {
|
|
87787
|
+
debugWarn("drainStream", "Stream error stack: %s", e.stack);
|
|
87788
|
+
}
|
|
87596
87789
|
if (!streamProcessor.lastRunId && e instanceof APIError2 && e.error) {
|
|
87597
87790
|
const errorObj = e.error;
|
|
87598
87791
|
if ("run_id" in errorObj && typeof errorObj.run_id === "string") {
|
|
@@ -87663,6 +87856,7 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
87663
87856
|
}
|
|
87664
87857
|
async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold) {
|
|
87665
87858
|
const overallStartTime = performance.now();
|
|
87859
|
+
recordTuiPerf("stream_lifecycle:start");
|
|
87666
87860
|
const streamRequestContext = getStreamRequestContext(stream2);
|
|
87667
87861
|
const streamOtid = streamRequestContext?.otid ?? null;
|
|
87668
87862
|
let _client;
|
|
@@ -87785,6 +87979,9 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
|
|
|
87785
87979
|
markCurrentLineAsFinished(buffers);
|
|
87786
87980
|
}
|
|
87787
87981
|
result.apiDurationMs = performance.now() - overallStartTime;
|
|
87982
|
+
recordTuiPerf(`stream_lifecycle:end:${result.stopReason}`, {
|
|
87983
|
+
ms: result.apiDurationMs
|
|
87984
|
+
});
|
|
87788
87985
|
return result;
|
|
87789
87986
|
}
|
|
87790
87987
|
var FALLBACK_RUN_DISCOVERY_TIMEOUT_MS = 5000;
|
|
@@ -87795,6 +87992,7 @@ var init_stream = __esm(async () => {
|
|
|
87795
87992
|
init_debug();
|
|
87796
87993
|
init_streamAbortRelay();
|
|
87797
87994
|
init_timing();
|
|
87995
|
+
init_tuiPerf();
|
|
87798
87996
|
init_chunkLog();
|
|
87799
87997
|
await __promiseAll([
|
|
87800
87998
|
init_message(),
|
|
@@ -88893,22 +89091,12 @@ function emitToolExecutionFinishedEvents(socket, runtime, params) {
|
|
|
88893
89091
|
}
|
|
88894
89092
|
function createToolExecutionOutputEmitter(socket, runtime, params) {
|
|
88895
89093
|
const outputByToolCallId = new Map;
|
|
88896
|
-
|
|
88897
|
-
if (!
|
|
89094
|
+
const emitToolOutput = (toolCallId, outputState) => {
|
|
89095
|
+
if (!outputState.dirty) {
|
|
88898
89096
|
return;
|
|
88899
89097
|
}
|
|
88900
|
-
|
|
88901
|
-
|
|
88902
|
-
messageId: `message-tool-return-stream-${toolCallId}`,
|
|
88903
|
-
stdout: "",
|
|
88904
|
-
stderr: ""
|
|
88905
|
-
};
|
|
88906
|
-
if (isStderr) {
|
|
88907
|
-
outputState.stderr = appendStreamingOutputWithCap(outputState.stderr, chunk);
|
|
88908
|
-
} else {
|
|
88909
|
-
outputState.stdout = appendStreamingOutputWithCap(outputState.stdout, chunk);
|
|
88910
|
-
}
|
|
88911
|
-
outputByToolCallId.set(toolCallId, outputState);
|
|
89098
|
+
outputState.dirty = false;
|
|
89099
|
+
outputState.lastEmittedAt = Date.now();
|
|
88912
89100
|
const stdout = normalizeStreamingOutputLines(outputState.stdout);
|
|
88913
89101
|
const stderr = normalizeStreamingOutputLines(outputState.stderr);
|
|
88914
89102
|
const toolReturn = [stdout?.join(`
|
|
@@ -88938,6 +89126,52 @@ function createToolExecutionOutputEmitter(socket, runtime, params) {
|
|
|
88938
89126
|
conversation_id: params.conversationId
|
|
88939
89127
|
});
|
|
88940
89128
|
};
|
|
89129
|
+
const flushToolOutput = (toolCallId, outputState) => {
|
|
89130
|
+
if (outputState.timer) {
|
|
89131
|
+
clearTimeout(outputState.timer);
|
|
89132
|
+
outputState.timer = null;
|
|
89133
|
+
}
|
|
89134
|
+
emitToolOutput(toolCallId, outputState);
|
|
89135
|
+
};
|
|
89136
|
+
const emitter = (toolCallId, chunk, isStderr = false) => {
|
|
89137
|
+
if (!toolCallId || chunk.length === 0) {
|
|
89138
|
+
return;
|
|
89139
|
+
}
|
|
89140
|
+
const existing = outputByToolCallId.get(toolCallId);
|
|
89141
|
+
const outputState = existing ?? {
|
|
89142
|
+
messageId: `message-tool-return-stream-${toolCallId}`,
|
|
89143
|
+
stdout: "",
|
|
89144
|
+
stderr: "",
|
|
89145
|
+
dirty: false,
|
|
89146
|
+
lastEmittedAt: 0,
|
|
89147
|
+
timer: null
|
|
89148
|
+
};
|
|
89149
|
+
if (isStderr) {
|
|
89150
|
+
outputState.stderr = appendStreamingOutputWithCap(outputState.stderr, chunk);
|
|
89151
|
+
} else {
|
|
89152
|
+
outputState.stdout = appendStreamingOutputWithCap(outputState.stdout, chunk);
|
|
89153
|
+
}
|
|
89154
|
+
outputByToolCallId.set(toolCallId, outputState);
|
|
89155
|
+
outputState.dirty = true;
|
|
89156
|
+
const now = Date.now();
|
|
89157
|
+
const elapsed = now - outputState.lastEmittedAt;
|
|
89158
|
+
if (elapsed >= STREAMING_TOOL_OUTPUT_EMIT_INTERVAL_MS) {
|
|
89159
|
+
flushToolOutput(toolCallId, outputState);
|
|
89160
|
+
return;
|
|
89161
|
+
}
|
|
89162
|
+
if (!outputState.timer) {
|
|
89163
|
+
outputState.timer = setTimeout(() => {
|
|
89164
|
+
outputState.timer = null;
|
|
89165
|
+
emitToolOutput(toolCallId, outputState);
|
|
89166
|
+
}, STREAMING_TOOL_OUTPUT_EMIT_INTERVAL_MS - elapsed);
|
|
89167
|
+
}
|
|
89168
|
+
};
|
|
89169
|
+
emitter.flush = () => {
|
|
89170
|
+
for (const [toolCallId, outputState] of outputByToolCallId.entries()) {
|
|
89171
|
+
flushToolOutput(toolCallId, outputState);
|
|
89172
|
+
}
|
|
89173
|
+
};
|
|
89174
|
+
return emitter;
|
|
88941
89175
|
}
|
|
88942
89176
|
function getInterruptApprovalsForEmission(runtime, params) {
|
|
88943
89177
|
if (params.lastExecutionResults && params.lastExecutionResults.length > 0) {
|
|
@@ -89055,7 +89289,7 @@ function stashRecoveredApprovalInterrupts(runtime, recovered) {
|
|
|
89055
89289
|
clearRecoveredApprovalState(runtime);
|
|
89056
89290
|
return true;
|
|
89057
89291
|
}
|
|
89058
|
-
var INTERRUPT_TOOL_RETURN_MAX_CHARS, STREAMING_TOOL_OUTPUT_MAX_CHARS;
|
|
89292
|
+
var INTERRUPT_TOOL_RETURN_MAX_CHARS, STREAMING_TOOL_OUTPUT_MAX_CHARS, STREAMING_TOOL_OUTPUT_EMIT_INTERVAL_MS = 100;
|
|
89059
89293
|
var init_interrupts = __esm(async () => {
|
|
89060
89294
|
init_approval_result_normalization();
|
|
89061
89295
|
init_constants();
|
|
@@ -89892,16 +90126,21 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
89892
90126
|
runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
|
|
89893
90127
|
runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
|
|
89894
90128
|
try {
|
|
89895
|
-
|
|
89896
|
-
|
|
89897
|
-
|
|
89898
|
-
|
|
89899
|
-
|
|
89900
|
-
|
|
89901
|
-
|
|
89902
|
-
|
|
89903
|
-
|
|
89904
|
-
|
|
90129
|
+
let approvalResults;
|
|
90130
|
+
try {
|
|
90131
|
+
approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
90132
|
+
abortSignal: recoveryAbortController.signal,
|
|
90133
|
+
onStreamingOutput: emitToolExecutionOutput,
|
|
90134
|
+
toolContextId: preparedToolContext.preparedToolContext.contextId,
|
|
90135
|
+
workingDirectory,
|
|
90136
|
+
parentScope: recovered.agentId && recovered.conversationId ? {
|
|
90137
|
+
agentId: recovered.agentId,
|
|
90138
|
+
conversationId: recovered.conversationId
|
|
90139
|
+
} : undefined
|
|
90140
|
+
});
|
|
90141
|
+
} finally {
|
|
90142
|
+
emitToolExecutionOutput.flush();
|
|
90143
|
+
}
|
|
89905
90144
|
emitToolExecutionFinishedEvents(socket, runtime, {
|
|
89906
90145
|
approvals: approvalResults,
|
|
89907
90146
|
runId: runtime.activeRunId ?? undefined,
|
|
@@ -89915,7 +90154,8 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
89915
90154
|
const continuationMessages = [
|
|
89916
90155
|
{
|
|
89917
90156
|
type: "approval",
|
|
89918
|
-
approvals: approvalResults
|
|
90157
|
+
approvals: approvalResults,
|
|
90158
|
+
otid: crypto.randomUUID()
|
|
89919
90159
|
}
|
|
89920
90160
|
];
|
|
89921
90161
|
let continuationBatchId = `batch-recovered-${crypto.randomUUID()}`;
|
|
@@ -90309,6 +90549,18 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
90309
90549
|
retryAfterMs
|
|
90310
90550
|
});
|
|
90311
90551
|
transientRetries = attempt;
|
|
90552
|
+
const retryMessage = getRetryStatusMessage(errorDetail);
|
|
90553
|
+
if (retryMessage) {
|
|
90554
|
+
emitRetryDelta(socket, runtime, {
|
|
90555
|
+
message: retryMessage,
|
|
90556
|
+
reason: "error",
|
|
90557
|
+
attempt,
|
|
90558
|
+
maxAttempts: LLM_API_ERROR_MAX_RETRIES,
|
|
90559
|
+
delayMs,
|
|
90560
|
+
agentId: runtime.agentId ?? undefined,
|
|
90561
|
+
conversationId
|
|
90562
|
+
});
|
|
90563
|
+
}
|
|
90312
90564
|
await new Promise((resolve27) => setTimeout(resolve27, delayMs));
|
|
90313
90565
|
if (abortSignal?.aborted) {
|
|
90314
90566
|
throw new Error("Cancelled by user");
|
|
@@ -90354,6 +90606,15 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
90354
90606
|
category: "conversation_busy",
|
|
90355
90607
|
attempt: conversationBusyRetries
|
|
90356
90608
|
});
|
|
90609
|
+
emitRetryDelta(socket, runtime, {
|
|
90610
|
+
message: "Conversation is busy, waiting and retrying…",
|
|
90611
|
+
reason: "error",
|
|
90612
|
+
attempt: conversationBusyRetries,
|
|
90613
|
+
maxAttempts: MAX_CONVERSATION_BUSY_RETRIES,
|
|
90614
|
+
delayMs: retryDelayMs,
|
|
90615
|
+
agentId: runtime.agentId ?? undefined,
|
|
90616
|
+
conversationId
|
|
90617
|
+
});
|
|
90357
90618
|
await new Promise((resolve27) => setTimeout(resolve27, retryDelayMs));
|
|
90358
90619
|
if (abortSignal?.aborted) {
|
|
90359
90620
|
throw new Error("Cancelled by user");
|
|
@@ -92710,14 +92971,19 @@ async function handleApprovalStop(params) {
|
|
|
92710
92971
|
}));
|
|
92711
92972
|
}
|
|
92712
92973
|
};
|
|
92713
|
-
|
|
92714
|
-
|
|
92715
|
-
|
|
92716
|
-
|
|
92717
|
-
|
|
92718
|
-
|
|
92719
|
-
|
|
92720
|
-
|
|
92974
|
+
let executionResults;
|
|
92975
|
+
try {
|
|
92976
|
+
executionResults = await executeApprovalBatch(decisions, undefined, {
|
|
92977
|
+
toolContextId: turnToolContextId ?? undefined,
|
|
92978
|
+
abortSignal: abortController.signal,
|
|
92979
|
+
onStreamingOutput: emitToolExecutionOutput,
|
|
92980
|
+
workingDirectory: turnWorkingDirectory,
|
|
92981
|
+
parentScope: agentId && conversationId ? { agentId, conversationId } : undefined,
|
|
92982
|
+
onFileWrite
|
|
92983
|
+
});
|
|
92984
|
+
} finally {
|
|
92985
|
+
emitToolExecutionOutput.flush();
|
|
92986
|
+
}
|
|
92721
92987
|
const persistedExecutionResults = normalizeExecutionResultsForInterruptParity(runtime, executionResults, lastExecutingToolCallIds);
|
|
92722
92988
|
validateApprovalResultIds(decisions.map((decision) => ({
|
|
92723
92989
|
approval: {
|
|
@@ -92738,7 +93004,8 @@ async function handleApprovalStop(params) {
|
|
|
92738
93004
|
const nextInput = [
|
|
92739
93005
|
{
|
|
92740
93006
|
type: "approval",
|
|
92741
|
-
approvals: persistedExecutionResults
|
|
93007
|
+
approvals: persistedExecutionResults,
|
|
93008
|
+
otid: crypto.randomUUID()
|
|
92742
93009
|
}
|
|
92743
93010
|
];
|
|
92744
93011
|
let continuationBatchId = dequeuedBatchId;
|
|
@@ -93898,7 +94165,115 @@ var init_commands = __esm(async () => {
|
|
|
93898
94165
|
});
|
|
93899
94166
|
|
|
93900
94167
|
// src/websocket/listener/protocol-outbound.ts
|
|
94168
|
+
import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync22 } from "node:fs";
|
|
94169
|
+
import { dirname as dirname15 } from "node:path";
|
|
94170
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
93901
94171
|
import WebSocket3 from "ws";
|
|
94172
|
+
function getProtocolPerfKey(message) {
|
|
94173
|
+
if (message.type === "stream_delta" && "delta" in message) {
|
|
94174
|
+
const delta = message.delta;
|
|
94175
|
+
return `${message.type}:${String(delta.message_type ?? "unknown")}`;
|
|
94176
|
+
}
|
|
94177
|
+
return message.type;
|
|
94178
|
+
}
|
|
94179
|
+
function scheduleProtocolPerfFlush() {
|
|
94180
|
+
if (protocolPerfFlushTimer) {
|
|
94181
|
+
return;
|
|
94182
|
+
}
|
|
94183
|
+
protocolPerfFlushTimer = setTimeout(() => {
|
|
94184
|
+
protocolPerfFlushTimer = null;
|
|
94185
|
+
flushProtocolPerfTelemetry();
|
|
94186
|
+
}, PROTOCOL_PERF_FLUSH_INTERVAL_MS);
|
|
94187
|
+
const timerWithUnref = protocolPerfFlushTimer;
|
|
94188
|
+
timerWithUnref.unref?.();
|
|
94189
|
+
}
|
|
94190
|
+
function recordProtocolPerfTelemetry(key, sample) {
|
|
94191
|
+
if (protocolPerfWindowStartedAt === 0) {
|
|
94192
|
+
protocolPerfWindowStartedAt = Date.now();
|
|
94193
|
+
}
|
|
94194
|
+
const bucket = protocolPerfBuckets.get(key) ?? {
|
|
94195
|
+
count: 0,
|
|
94196
|
+
bytes: 0,
|
|
94197
|
+
stringifyMs: 0,
|
|
94198
|
+
sendMs: 0,
|
|
94199
|
+
maxBufferedBefore: 0,
|
|
94200
|
+
maxBufferedAfter: 0
|
|
94201
|
+
};
|
|
94202
|
+
bucket.count += 1;
|
|
94203
|
+
bucket.bytes += sample.bytes;
|
|
94204
|
+
bucket.stringifyMs += sample.stringifyMs;
|
|
94205
|
+
bucket.sendMs += sample.sendMs;
|
|
94206
|
+
bucket.maxBufferedBefore = Math.max(bucket.maxBufferedBefore, sample.bufferedBefore);
|
|
94207
|
+
bucket.maxBufferedAfter = Math.max(bucket.maxBufferedAfter, sample.bufferedAfter);
|
|
94208
|
+
protocolPerfBuckets.set(key, bucket);
|
|
94209
|
+
scheduleProtocolPerfFlush();
|
|
94210
|
+
}
|
|
94211
|
+
function writeProtocolPerfFile(record, fallbackLine) {
|
|
94212
|
+
const filePath = PROTOCOL_PERF_FILE;
|
|
94213
|
+
if (!filePath) {
|
|
94214
|
+
console.error(fallbackLine);
|
|
94215
|
+
return;
|
|
94216
|
+
}
|
|
94217
|
+
try {
|
|
94218
|
+
const dir = dirname15(filePath);
|
|
94219
|
+
if (protocolPerfFileDirEnsured !== dir) {
|
|
94220
|
+
mkdirSync22(dir, { recursive: true });
|
|
94221
|
+
protocolPerfFileDirEnsured = dir;
|
|
94222
|
+
}
|
|
94223
|
+
appendFileSync4(filePath, `${JSON.stringify(record)}
|
|
94224
|
+
`, {
|
|
94225
|
+
encoding: "utf8"
|
|
94226
|
+
});
|
|
94227
|
+
} catch (error) {
|
|
94228
|
+
if (!protocolPerfFileWarningEmitted) {
|
|
94229
|
+
protocolPerfFileWarningEmitted = true;
|
|
94230
|
+
console.error(`[Listen Perf] Failed to write LETTA_LISTENER_PERF_FILE=${filePath}`, error);
|
|
94231
|
+
}
|
|
94232
|
+
console.error(fallbackLine);
|
|
94233
|
+
}
|
|
94234
|
+
}
|
|
94235
|
+
function flushProtocolPerfTelemetry() {
|
|
94236
|
+
if (protocolPerfBuckets.size === 0) {
|
|
94237
|
+
protocolPerfWindowStartedAt = 0;
|
|
94238
|
+
return;
|
|
94239
|
+
}
|
|
94240
|
+
const windowMs = Math.max(1, Date.now() - protocolPerfWindowStartedAt);
|
|
94241
|
+
const totals = {
|
|
94242
|
+
count: 0,
|
|
94243
|
+
bytes: 0,
|
|
94244
|
+
stringifyMs: 0,
|
|
94245
|
+
sendMs: 0,
|
|
94246
|
+
maxBufferedBefore: 0,
|
|
94247
|
+
maxBufferedAfter: 0
|
|
94248
|
+
};
|
|
94249
|
+
const buckets = {};
|
|
94250
|
+
const parts = [...protocolPerfBuckets.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, bucket]) => {
|
|
94251
|
+
totals.count += bucket.count;
|
|
94252
|
+
totals.bytes += bucket.bytes;
|
|
94253
|
+
totals.stringifyMs += bucket.stringifyMs;
|
|
94254
|
+
totals.sendMs += bucket.sendMs;
|
|
94255
|
+
totals.maxBufferedBefore = Math.max(totals.maxBufferedBefore, bucket.maxBufferedBefore);
|
|
94256
|
+
totals.maxBufferedAfter = Math.max(totals.maxBufferedAfter, bucket.maxBufferedAfter);
|
|
94257
|
+
buckets[key] = {
|
|
94258
|
+
...bucket,
|
|
94259
|
+
avg_bytes: bucket.count > 0 ? bucket.bytes / bucket.count : 0,
|
|
94260
|
+
avg_stringify_ms: bucket.count > 0 ? bucket.stringifyMs / bucket.count : 0,
|
|
94261
|
+
avg_send_ms: bucket.count > 0 ? bucket.sendMs / bucket.count : 0
|
|
94262
|
+
};
|
|
94263
|
+
const stringifyMs = bucket.stringifyMs.toFixed(2);
|
|
94264
|
+
const sendMs = bucket.sendMs.toFixed(2);
|
|
94265
|
+
return `${key}{count=${bucket.count},bytes=${bucket.bytes},stringify_ms=${stringifyMs},send_ms=${sendMs},max_buffered_before=${bucket.maxBufferedBefore},max_buffered_after=${bucket.maxBufferedAfter}}`;
|
|
94266
|
+
});
|
|
94267
|
+
writeProtocolPerfFile({
|
|
94268
|
+
ts: new Date().toISOString(),
|
|
94269
|
+
event: "protocol_emit",
|
|
94270
|
+
window_ms: windowMs,
|
|
94271
|
+
totals,
|
|
94272
|
+
buckets
|
|
94273
|
+
}, `[Listen Perf] protocol_emit window_ms=${windowMs} ${parts.join(" ")}`);
|
|
94274
|
+
protocolPerfBuckets.clear();
|
|
94275
|
+
protocolPerfWindowStartedAt = 0;
|
|
94276
|
+
}
|
|
93902
94277
|
function getCachedDeviceGitContext(cwd2) {
|
|
93903
94278
|
const now = Date.now();
|
|
93904
94279
|
const cached = gitContextCache.get(cwd2);
|
|
@@ -94105,8 +94480,24 @@ function emitProtocolV2Message(socket, runtime, message, scope) {
|
|
|
94105
94480
|
emitted_at: new Date().toISOString(),
|
|
94106
94481
|
idempotency_key: `${message.type}:${eventSeq}:${crypto.randomUUID()}`
|
|
94107
94482
|
};
|
|
94483
|
+
const perfEnabled = PROTOCOL_PERF_ENABLED;
|
|
94484
|
+
const stringifyStartedAt = perfEnabled ? performance2.now() : 0;
|
|
94485
|
+
let payload;
|
|
94108
94486
|
try {
|
|
94109
|
-
|
|
94487
|
+
payload = JSON.stringify(outbound);
|
|
94488
|
+
const stringifyMs = perfEnabled ? performance2.now() - stringifyStartedAt : 0;
|
|
94489
|
+
const bufferedBefore = perfEnabled ? socket.bufferedAmount : 0;
|
|
94490
|
+
const sendStartedAt = perfEnabled ? performance2.now() : 0;
|
|
94491
|
+
socket.send(payload);
|
|
94492
|
+
if (perfEnabled) {
|
|
94493
|
+
recordProtocolPerfTelemetry(getProtocolPerfKey(message), {
|
|
94494
|
+
bytes: Buffer.byteLength(payload),
|
|
94495
|
+
stringifyMs,
|
|
94496
|
+
sendMs: performance2.now() - sendStartedAt,
|
|
94497
|
+
bufferedBefore,
|
|
94498
|
+
bufferedAfter: socket.bufferedAmount
|
|
94499
|
+
});
|
|
94500
|
+
}
|
|
94110
94501
|
} catch (error) {
|
|
94111
94502
|
console.error(`[Listen V2] Failed to emit ${message.type} (seq=${eventSeq})`, error);
|
|
94112
94503
|
safeEmitWsEvent("send", "lifecycle", {
|
|
@@ -94340,7 +94731,7 @@ function emitStreamDelta(socket, runtime, delta, scope, subagentId) {
|
|
|
94340
94731
|
};
|
|
94341
94732
|
emitProtocolV2Message(socket, runtime, message, scope);
|
|
94342
94733
|
}
|
|
94343
|
-
var GIT_CONTEXT_CACHE_TTL_MS = 15000, MAX_GIT_CONTEXT_CACHE_ENTRIES = 64, gitContextCache;
|
|
94734
|
+
var GIT_CONTEXT_CACHE_TTL_MS = 15000, MAX_GIT_CONTEXT_CACHE_ENTRIES = 64, PROTOCOL_PERF_FLUSH_INTERVAL_MS = 1000, PROTOCOL_PERF_ENV_VALUES, PROTOCOL_PERF_ENABLED, PROTOCOL_PERF_FILE, protocolPerfBuckets, protocolPerfFlushTimer = null, protocolPerfWindowStartedAt = 0, protocolPerfFileDirEnsured = null, protocolPerfFileWarningEmitted = false, gitContextCache;
|
|
94344
94735
|
var init_protocol_outbound = __esm(async () => {
|
|
94345
94736
|
init_memoryFilesystem();
|
|
94346
94737
|
init_gitContext();
|
|
@@ -94356,6 +94747,10 @@ var init_protocol_outbound = __esm(async () => {
|
|
|
94356
94747
|
init_permissionMode();
|
|
94357
94748
|
init_runtime4();
|
|
94358
94749
|
await init_commands();
|
|
94750
|
+
PROTOCOL_PERF_ENV_VALUES = new Set(["1", "true", "yes"]);
|
|
94751
|
+
PROTOCOL_PERF_ENABLED = PROTOCOL_PERF_ENV_VALUES.has((process.env.LETTA_LISTENER_PERF ?? "").toLowerCase());
|
|
94752
|
+
PROTOCOL_PERF_FILE = process.env.LETTA_LISTENER_PERF_FILE?.trim() || null;
|
|
94753
|
+
protocolPerfBuckets = new Map;
|
|
94359
94754
|
gitContextCache = new Map;
|
|
94360
94755
|
});
|
|
94361
94756
|
|
|
@@ -95423,7 +95818,7 @@ function isSyncCommand(value) {
|
|
|
95423
95818
|
return false;
|
|
95424
95819
|
}
|
|
95425
95820
|
const candidate = value;
|
|
95426
|
-
return candidate.type === "sync" && isRuntimeScope(candidate.runtime);
|
|
95821
|
+
return candidate.type === "sync" && isRuntimeScope(candidate.runtime) && (candidate.recover_approvals === undefined || typeof candidate.recover_approvals === "boolean");
|
|
95427
95822
|
}
|
|
95428
95823
|
function isTerminalSpawnCommand(value) {
|
|
95429
95824
|
if (!value || typeof value !== "object")
|
|
@@ -96104,12 +96499,14 @@ function runDetachedListenerTask(commandName, task2) {
|
|
|
96104
96499
|
async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
|
|
96105
96500
|
const syncScopedRuntime = getOrCreateScopedRuntime(listenerRuntime, scope.agent_id, scope.conversation_id);
|
|
96106
96501
|
const recoverFn = opts?.recoverApprovalStateForSync ?? recoverApprovalStateForSync;
|
|
96107
|
-
|
|
96108
|
-
|
|
96109
|
-
|
|
96110
|
-
|
|
96111
|
-
|
|
96112
|
-
|
|
96502
|
+
if (opts?.recoverApprovals ?? true) {
|
|
96503
|
+
try {
|
|
96504
|
+
await recoverFn(syncScopedRuntime, scope);
|
|
96505
|
+
} catch (error) {
|
|
96506
|
+
trackListenerError("listener_sync_recovery_failed", error, "listener_sync_recovery");
|
|
96507
|
+
if (isDebugEnabled()) {
|
|
96508
|
+
console.warn("[Listen] Sync approval recovery failed:", error);
|
|
96509
|
+
}
|
|
96113
96510
|
}
|
|
96114
96511
|
}
|
|
96115
96512
|
emitStateSync(socket, listenerRuntime, scope);
|
|
@@ -97555,7 +97952,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
97555
97952
|
const {
|
|
97556
97953
|
existsSync: existsSync30,
|
|
97557
97954
|
lstatSync: lstatSync2,
|
|
97558
|
-
mkdirSync:
|
|
97955
|
+
mkdirSync: mkdirSync23,
|
|
97559
97956
|
rmdirSync,
|
|
97560
97957
|
symlinkSync,
|
|
97561
97958
|
unlinkSync: unlinkSync8
|
|
@@ -97586,7 +97983,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
97586
97983
|
}
|
|
97587
97984
|
const linkName = basename13(parsed.skill_path);
|
|
97588
97985
|
const linkPath = join34(globalSkillsDir, linkName);
|
|
97589
|
-
|
|
97986
|
+
mkdirSync23(globalSkillsDir, { recursive: true });
|
|
97590
97987
|
if (existsSync30(linkPath)) {
|
|
97591
97988
|
const stat7 = lstatSync2(linkPath);
|
|
97592
97989
|
if (stat7.isSymbolicLink()) {
|
|
@@ -98456,7 +98853,9 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
98456
98853
|
console.log(`[Listen V2] Dropping sync: runtime mismatch or closed`);
|
|
98457
98854
|
return;
|
|
98458
98855
|
}
|
|
98459
|
-
await replaySyncStateForRuntime(runtime, socket, parsed.runtime
|
|
98856
|
+
await replaySyncStateForRuntime(runtime, socket, parsed.runtime, {
|
|
98857
|
+
recoverApprovals: parsed.recover_approvals !== false
|
|
98858
|
+
});
|
|
98460
98859
|
return;
|
|
98461
98860
|
}
|
|
98462
98861
|
if (parsed.type === "input") {
|
|
@@ -99786,9 +100185,9 @@ __export(exports_debug2, {
|
|
|
99786
100185
|
debugLog: () => debugLog3
|
|
99787
100186
|
});
|
|
99788
100187
|
import {
|
|
99789
|
-
appendFileSync as
|
|
100188
|
+
appendFileSync as appendFileSync5,
|
|
99790
100189
|
existsSync as existsSync31,
|
|
99791
|
-
mkdirSync as
|
|
100190
|
+
mkdirSync as mkdirSync24,
|
|
99792
100191
|
readdirSync as readdirSync11,
|
|
99793
100192
|
readFileSync as readFileSync22,
|
|
99794
100193
|
unlinkSync as unlinkSync8
|
|
@@ -99809,7 +100208,7 @@ function printDebugLine2(line, level = "log") {
|
|
|
99809
100208
|
const debugFile = getDebugFile2();
|
|
99810
100209
|
if (debugFile) {
|
|
99811
100210
|
try {
|
|
99812
|
-
|
|
100211
|
+
appendFileSync5(debugFile, line, { encoding: "utf8" });
|
|
99813
100212
|
return;
|
|
99814
100213
|
} catch {}
|
|
99815
100214
|
}
|
|
@@ -99835,7 +100234,7 @@ class DebugLogFile2 {
|
|
|
99835
100234
|
return;
|
|
99836
100235
|
this.ensureDir();
|
|
99837
100236
|
try {
|
|
99838
|
-
|
|
100237
|
+
appendFileSync5(this.logPath, line, { encoding: "utf8" });
|
|
99839
100238
|
} catch {}
|
|
99840
100239
|
}
|
|
99841
100240
|
getTail(maxLines = DEFAULT_TAIL_LINES2) {
|
|
@@ -99858,7 +100257,7 @@ class DebugLogFile2 {
|
|
|
99858
100257
|
return;
|
|
99859
100258
|
try {
|
|
99860
100259
|
if (!existsSync31(this.agentDir)) {
|
|
99861
|
-
|
|
100260
|
+
mkdirSync24(this.agentDir, { recursive: true });
|
|
99862
100261
|
}
|
|
99863
100262
|
this.dirCreated = true;
|
|
99864
100263
|
} catch {}
|
|
@@ -99928,10 +100327,10 @@ __export(exports_skills2, {
|
|
|
99928
100327
|
});
|
|
99929
100328
|
import { existsSync as existsSync32 } from "node:fs";
|
|
99930
100329
|
import { readdir as readdir8, readFile as readFile13, realpath as realpath4, stat as stat7 } from "node:fs/promises";
|
|
99931
|
-
import { dirname as
|
|
100330
|
+
import { dirname as dirname16, join as join38 } from "node:path";
|
|
99932
100331
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
99933
100332
|
function getBundledSkillsPath2() {
|
|
99934
|
-
const thisDir =
|
|
100333
|
+
const thisDir = dirname16(fileURLToPath9(import.meta.url));
|
|
99935
100334
|
if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
|
|
99936
100335
|
return join38(thisDir, "../skills/builtin");
|
|
99937
100336
|
}
|
|
@@ -100125,16 +100524,16 @@ import {
|
|
|
100125
100524
|
existsSync as existsSync33,
|
|
100126
100525
|
readFileSync as fsReadFileSync2,
|
|
100127
100526
|
writeFileSync as fsWriteFileSync2,
|
|
100128
|
-
mkdirSync as
|
|
100527
|
+
mkdirSync as mkdirSync25
|
|
100129
100528
|
} from "node:fs";
|
|
100130
|
-
import { dirname as
|
|
100529
|
+
import { dirname as dirname17 } from "node:path";
|
|
100131
100530
|
async function readFile14(path26) {
|
|
100132
100531
|
return fsReadFileSync2(path26, { encoding: "utf-8" });
|
|
100133
100532
|
}
|
|
100134
100533
|
async function writeFile12(path26, content) {
|
|
100135
|
-
const dir =
|
|
100534
|
+
const dir = dirname17(path26);
|
|
100136
100535
|
if (!existsSync33(dir)) {
|
|
100137
|
-
|
|
100536
|
+
mkdirSync25(dir, { recursive: true });
|
|
100138
100537
|
}
|
|
100139
100538
|
fsWriteFileSync2(path26, content, { encoding: "utf-8", flush: true });
|
|
100140
100539
|
}
|
|
@@ -100142,7 +100541,7 @@ function exists2(path26) {
|
|
|
100142
100541
|
return existsSync33(path26);
|
|
100143
100542
|
}
|
|
100144
100543
|
async function mkdir9(path26, options) {
|
|
100145
|
-
|
|
100544
|
+
mkdirSync25(path26, options);
|
|
100146
100545
|
}
|
|
100147
100546
|
async function readJsonFile(path26) {
|
|
100148
100547
|
const text = await readFile14(path26);
|
|
@@ -100275,7 +100674,7 @@ var exports_bootstrap_tools = {};
|
|
|
100275
100674
|
__export(exports_bootstrap_tools, {
|
|
100276
100675
|
bootstrapBaseToolsIfNeeded: () => bootstrapBaseToolsIfNeeded
|
|
100277
100676
|
});
|
|
100278
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
100677
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync26, writeFileSync as writeFileSync17 } from "node:fs";
|
|
100279
100678
|
import { homedir as homedir27 } from "node:os";
|
|
100280
100679
|
import { join as join39 } from "node:path";
|
|
100281
100680
|
async function bootstrapBaseToolsIfNeeded() {
|
|
@@ -100285,7 +100684,7 @@ async function bootstrapBaseToolsIfNeeded() {
|
|
|
100285
100684
|
try {
|
|
100286
100685
|
const success = await addBaseToolsToServer();
|
|
100287
100686
|
if (success) {
|
|
100288
|
-
|
|
100687
|
+
mkdirSync26(join39(homedir27(), ".letta"), { recursive: true });
|
|
100289
100688
|
writeFileSync17(MARKER_PATH, new Date().toISOString(), "utf-8");
|
|
100290
100689
|
}
|
|
100291
100690
|
} catch (err) {
|
|
@@ -101989,7 +102388,7 @@ __export(exports_import, {
|
|
|
101989
102388
|
});
|
|
101990
102389
|
import { createReadStream } from "node:fs";
|
|
101991
102390
|
import { chmod, mkdir as mkdir10, readFile as readFile15, writeFile as writeFile13 } from "node:fs/promises";
|
|
101992
|
-
import { dirname as
|
|
102391
|
+
import { dirname as dirname18, resolve as resolve30 } from "node:path";
|
|
101993
102392
|
async function importAgentFromFile(options) {
|
|
101994
102393
|
const client = await getClient();
|
|
101995
102394
|
const resolvedPath = resolve30(options.filePath);
|
|
@@ -102048,7 +102447,7 @@ async function writeSkillFiles(skillDir, files) {
|
|
|
102048
102447
|
}
|
|
102049
102448
|
async function writeSkillFile(skillDir, filePath, content) {
|
|
102050
102449
|
const fullPath = resolve30(skillDir, filePath);
|
|
102051
|
-
await mkdir10(
|
|
102450
|
+
await mkdir10(dirname18(fullPath), { recursive: true });
|
|
102052
102451
|
await writeFile13(fullPath, content, "utf-8");
|
|
102053
102452
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
102054
102453
|
if (isScript) {
|
|
@@ -124703,7 +125102,7 @@ html.dark .agent-name { color: var(--text-dim); }
|
|
|
124703
125102
|
var init_plan_viewer_template = () => {};
|
|
124704
125103
|
|
|
124705
125104
|
// src/web/generate-plan-viewer.ts
|
|
124706
|
-
import { chmodSync as chmodSync2, existsSync as existsSync37, mkdirSync as
|
|
125105
|
+
import { chmodSync as chmodSync2, existsSync as existsSync37, mkdirSync as mkdirSync29, writeFileSync as writeFileSync20 } from "node:fs";
|
|
124707
125106
|
import { homedir as homedir31 } from "node:os";
|
|
124708
125107
|
import { join as join44 } from "node:path";
|
|
124709
125108
|
async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
@@ -124716,7 +125115,7 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
|
124716
125115
|
const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
124717
125116
|
const html = plan_viewer_template_default.replace("<!--LETTA_PLAN_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
124718
125117
|
if (!existsSync37(VIEWERS_DIR)) {
|
|
124719
|
-
|
|
125118
|
+
mkdirSync29(VIEWERS_DIR, { recursive: true, mode: 448 });
|
|
124720
125119
|
}
|
|
124721
125120
|
try {
|
|
124722
125121
|
chmodSync2(VIEWERS_DIR, 448);
|
|
@@ -128026,12 +128425,12 @@ __export(exports_terminalKeybindingInstaller, {
|
|
|
128026
128425
|
import {
|
|
128027
128426
|
copyFileSync,
|
|
128028
128427
|
existsSync as existsSync39,
|
|
128029
|
-
mkdirSync as
|
|
128428
|
+
mkdirSync as mkdirSync30,
|
|
128030
128429
|
readFileSync as readFileSync25,
|
|
128031
128430
|
writeFileSync as writeFileSync21
|
|
128032
128431
|
} from "node:fs";
|
|
128033
128432
|
import { homedir as homedir32, platform as platform6 } from "node:os";
|
|
128034
|
-
import { dirname as
|
|
128433
|
+
import { dirname as dirname19, join as join46 } from "node:path";
|
|
128035
128434
|
function detectTerminalType() {
|
|
128036
128435
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
128037
128436
|
return "cursor";
|
|
@@ -128122,9 +128521,9 @@ function installKeybinding(keybindingsPath) {
|
|
|
128122
128521
|
if (keybindingExists(keybindingsPath)) {
|
|
128123
128522
|
return { success: true, alreadyExists: true };
|
|
128124
128523
|
}
|
|
128125
|
-
const parentDir =
|
|
128524
|
+
const parentDir = dirname19(keybindingsPath);
|
|
128126
128525
|
if (!existsSync39(parentDir)) {
|
|
128127
|
-
|
|
128526
|
+
mkdirSync30(parentDir, { recursive: true });
|
|
128128
128527
|
}
|
|
128129
128528
|
let keybindings = [];
|
|
128130
128529
|
let backupPath = null;
|
|
@@ -128281,9 +128680,9 @@ return config`);
|
|
|
128281
128680
|
${WEZTERM_DELETE_FIX}
|
|
128282
128681
|
`;
|
|
128283
128682
|
}
|
|
128284
|
-
const parentDir =
|
|
128683
|
+
const parentDir = dirname19(configPath);
|
|
128285
128684
|
if (!existsSync39(parentDir)) {
|
|
128286
|
-
|
|
128685
|
+
mkdirSync30(parentDir, { recursive: true });
|
|
128287
128686
|
}
|
|
128288
128687
|
writeFileSync21(configPath, content, { encoding: "utf-8" });
|
|
128289
128688
|
return {
|
|
@@ -128881,7 +129280,7 @@ __export(exports_custom, {
|
|
|
128881
129280
|
});
|
|
128882
129281
|
import { existsSync as existsSync40 } from "node:fs";
|
|
128883
129282
|
import { readdir as readdir10, readFile as readFile16 } from "node:fs/promises";
|
|
128884
|
-
import { basename as basename14, dirname as
|
|
129283
|
+
import { basename as basename14, dirname as dirname20, join as join47 } from "node:path";
|
|
128885
129284
|
async function getCustomCommands() {
|
|
128886
129285
|
if (cachedCommands !== null) {
|
|
128887
129286
|
return cachedCommands;
|
|
@@ -128942,7 +129341,7 @@ async function parseCommandFile(filePath, rootPath, source2) {
|
|
|
128942
129341
|
const content = await readFile16(filePath, "utf-8");
|
|
128943
129342
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
128944
129343
|
const id = basename14(filePath, ".md");
|
|
128945
|
-
const relativePath =
|
|
129344
|
+
const relativePath = dirname20(filePath).slice(rootPath.length);
|
|
128946
129345
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
128947
129346
|
let description = getStringField(frontmatter, "description");
|
|
128948
129347
|
if (!description) {
|
|
@@ -134102,14 +134501,14 @@ var init_InputRich = __esm(async () => {
|
|
|
134102
134501
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
134103
134502
|
import {
|
|
134104
134503
|
existsSync as existsSync41,
|
|
134105
|
-
mkdirSync as
|
|
134504
|
+
mkdirSync as mkdirSync31,
|
|
134106
134505
|
mkdtempSync,
|
|
134107
134506
|
readFileSync as readFileSync26,
|
|
134108
134507
|
rmSync as rmSync4,
|
|
134109
134508
|
writeFileSync as writeFileSync22
|
|
134110
134509
|
} from "node:fs";
|
|
134111
134510
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
134112
|
-
import { dirname as
|
|
134511
|
+
import { dirname as dirname21, join as join49 } from "node:path";
|
|
134113
134512
|
function runCommand(command, args, cwd2, input) {
|
|
134114
134513
|
try {
|
|
134115
134514
|
return execFileSync4(command, args, {
|
|
@@ -134356,8 +134755,8 @@ function runGit3(args, cwd2) {
|
|
|
134356
134755
|
}
|
|
134357
134756
|
function writeWorkflow(repoDir, workflowPath, content) {
|
|
134358
134757
|
const absolutePath = join49(repoDir, workflowPath);
|
|
134359
|
-
if (!existsSync41(
|
|
134360
|
-
|
|
134758
|
+
if (!existsSync41(dirname21(absolutePath))) {
|
|
134759
|
+
mkdirSync31(dirname21(absolutePath), { recursive: true });
|
|
134361
134760
|
}
|
|
134362
134761
|
const next = `${content.trimEnd()}
|
|
134363
134762
|
`;
|
|
@@ -138599,7 +138998,7 @@ __export(exports_generate_memory_viewer, {
|
|
|
138599
138998
|
generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
|
|
138600
138999
|
});
|
|
138601
139000
|
import { execFile as execFileCb3 } from "node:child_process";
|
|
138602
|
-
import { chmodSync as chmodSync3, existsSync as existsSync42, mkdirSync as
|
|
139001
|
+
import { chmodSync as chmodSync3, existsSync as existsSync42, mkdirSync as mkdirSync32, writeFileSync as writeFileSync23 } from "node:fs";
|
|
138603
139002
|
import { homedir as homedir34 } from "node:os";
|
|
138604
139003
|
import { join as join50 } from "node:path";
|
|
138605
139004
|
import { promisify as promisify13 } from "node:util";
|
|
@@ -138920,7 +139319,7 @@ async function generateAndOpenMemoryViewer(agentId, options) {
|
|
|
138920
139319
|
const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
138921
139320
|
const html = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
138922
139321
|
if (!existsSync42(VIEWERS_DIR2)) {
|
|
138923
|
-
|
|
139322
|
+
mkdirSync32(VIEWERS_DIR2, { recursive: true, mode: 448 });
|
|
138924
139323
|
}
|
|
138925
139324
|
try {
|
|
138926
139325
|
chmodSync3(VIEWERS_DIR2, 448);
|
|
@@ -142730,7 +143129,7 @@ function formatDuration3(ms) {
|
|
|
142730
143129
|
}
|
|
142731
143130
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
142732
143131
|
}
|
|
142733
|
-
function
|
|
143132
|
+
function formatNumber2(n) {
|
|
142734
143133
|
return n.toLocaleString();
|
|
142735
143134
|
}
|
|
142736
143135
|
function formatUsageStats({
|
|
@@ -142752,7 +143151,7 @@ function formatUsageStats({
|
|
|
142752
143151
|
const monthlyCredits = Math.round(balance.monthly_credit_balance);
|
|
142753
143152
|
const purchasedCredits = Math.round(balance.purchased_credit_balance);
|
|
142754
143153
|
const toDollars = (credits) => (credits / 1000).toFixed(2);
|
|
142755
|
-
outputLines.push(`Plan: [${balance.billing_tier}]`, buildAppUrl("/settings/organization/usage"), "", `Available credits: ◎${
|
|
143154
|
+
outputLines.push(`Plan: [${balance.billing_tier}]`, buildAppUrl("/settings/organization/usage"), "", `Available credits: ◎${formatNumber2(totalCredits)} ($${toDollars(totalCredits)})`, `Monthly credits: ◎${formatNumber2(monthlyCredits)} ($${toDollars(monthlyCredits)})`, `Purchased credits: ◎${formatNumber2(purchasedCredits)} ($${toDollars(purchasedCredits)})`);
|
|
142756
143155
|
}
|
|
142757
143156
|
return outputLines.join(`
|
|
142758
143157
|
`);
|
|
@@ -150023,6 +150422,7 @@ function App2({
|
|
|
150023
150422
|
streamingRefreshTimeoutRef.current = setTimeout(() => {
|
|
150024
150423
|
streamingRefreshTimeoutRef.current = null;
|
|
150025
150424
|
if (!buffersRef.current.interrupted) {
|
|
150425
|
+
recordTuiPerf("ui_refresh:tool_output");
|
|
150026
150426
|
refreshDerived();
|
|
150027
150427
|
}
|
|
150028
150428
|
}, 100);
|
|
@@ -150035,6 +150435,9 @@ function App2({
|
|
|
150035
150435
|
};
|
|
150036
150436
|
}, []);
|
|
150037
150437
|
const updateStreamingOutput = import_react104.useCallback((toolCallId, chunk, isStderr = false) => {
|
|
150438
|
+
recordTuiPerf(`tool_output:${isStderr ? "stderr" : "stdout"}`, {
|
|
150439
|
+
bytes: Buffer.byteLength(chunk)
|
|
150440
|
+
});
|
|
150038
150441
|
const lineId = buffersRef.current.toolCallIdToLineId.get(toolCallId);
|
|
150039
150442
|
if (!lineId)
|
|
150040
150443
|
return;
|
|
@@ -150055,6 +150458,7 @@ function App2({
|
|
|
150055
150458
|
setTimeout(() => {
|
|
150056
150459
|
buffersRef.current.pendingRefresh = false;
|
|
150057
150460
|
if (!buffersRef.current.interrupted && (buffersRef.current.commitGeneration || 0) === capturedGeneration) {
|
|
150461
|
+
recordTuiPerf("ui_refresh:stream");
|
|
150058
150462
|
refreshDerived();
|
|
150059
150463
|
}
|
|
150060
150464
|
}, 16);
|
|
@@ -157568,6 +157972,7 @@ var init_App2 = __esm(async () => {
|
|
|
157568
157972
|
init_telemetry();
|
|
157569
157973
|
init_toolset_labels();
|
|
157570
157974
|
init_debug();
|
|
157975
|
+
init_tuiPerf();
|
|
157571
157976
|
init_version();
|
|
157572
157977
|
init_mcp();
|
|
157573
157978
|
init_profile();
|
|
@@ -157748,12 +158153,12 @@ __export(exports_terminalKeybindingInstaller2, {
|
|
|
157748
158153
|
import {
|
|
157749
158154
|
copyFileSync as copyFileSync2,
|
|
157750
158155
|
existsSync as existsSync46,
|
|
157751
|
-
mkdirSync as
|
|
158156
|
+
mkdirSync as mkdirSync33,
|
|
157752
158157
|
readFileSync as readFileSync29,
|
|
157753
158158
|
writeFileSync as writeFileSync25
|
|
157754
158159
|
} from "node:fs";
|
|
157755
158160
|
import { homedir as homedir38, platform as platform7 } from "node:os";
|
|
157756
|
-
import { dirname as
|
|
158161
|
+
import { dirname as dirname22, join as join54 } from "node:path";
|
|
157757
158162
|
function detectTerminalType2() {
|
|
157758
158163
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
157759
158164
|
return "cursor";
|
|
@@ -157844,9 +158249,9 @@ function installKeybinding2(keybindingsPath) {
|
|
|
157844
158249
|
if (keybindingExists2(keybindingsPath)) {
|
|
157845
158250
|
return { success: true, alreadyExists: true };
|
|
157846
158251
|
}
|
|
157847
|
-
const parentDir =
|
|
158252
|
+
const parentDir = dirname22(keybindingsPath);
|
|
157848
158253
|
if (!existsSync46(parentDir)) {
|
|
157849
|
-
|
|
158254
|
+
mkdirSync33(parentDir, { recursive: true });
|
|
157850
158255
|
}
|
|
157851
158256
|
let keybindings = [];
|
|
157852
158257
|
let backupPath = null;
|
|
@@ -158003,9 +158408,9 @@ return config`);
|
|
|
158003
158408
|
${WEZTERM_DELETE_FIX2}
|
|
158004
158409
|
`;
|
|
158005
158410
|
}
|
|
158006
|
-
const parentDir =
|
|
158411
|
+
const parentDir = dirname22(configPath);
|
|
158007
158412
|
if (!existsSync46(parentDir)) {
|
|
158008
|
-
|
|
158413
|
+
mkdirSync33(parentDir, { recursive: true });
|
|
158009
158414
|
}
|
|
158010
158415
|
writeFileSync25(configPath, content, { encoding: "utf-8" });
|
|
158011
158416
|
return {
|
|
@@ -158573,7 +158978,7 @@ __export(exports_import2, {
|
|
|
158573
158978
|
});
|
|
158574
158979
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
158575
158980
|
import { chmod as chmod2, mkdir as mkdir11, readFile as readFile19, writeFile as writeFile14 } from "node:fs/promises";
|
|
158576
|
-
import { dirname as
|
|
158981
|
+
import { dirname as dirname23, resolve as resolve35 } from "node:path";
|
|
158577
158982
|
async function importAgentFromFile2(options) {
|
|
158578
158983
|
const client = await getClient();
|
|
158579
158984
|
const resolvedPath = resolve35(options.filePath);
|
|
@@ -158632,7 +159037,7 @@ async function writeSkillFiles2(skillDir, files) {
|
|
|
158632
159037
|
}
|
|
158633
159038
|
async function writeSkillFile2(skillDir, filePath, content) {
|
|
158634
159039
|
const fullPath = resolve35(skillDir, filePath);
|
|
158635
|
-
await mkdir11(
|
|
159040
|
+
await mkdir11(dirname23(fullPath), { recursive: true });
|
|
158636
159041
|
await writeFile14(fullPath, content, "utf-8");
|
|
158637
159042
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
158638
159043
|
if (isScript) {
|
|
@@ -158742,7 +159147,7 @@ __export(exports_memoryFilesystem2, {
|
|
|
158742
159147
|
MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR2,
|
|
158743
159148
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
|
|
158744
159149
|
});
|
|
158745
|
-
import { existsSync as existsSync47, mkdirSync as
|
|
159150
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync34 } from "node:fs";
|
|
158746
159151
|
import { homedir as homedir40 } from "node:os";
|
|
158747
159152
|
import { join as join56, resolve as resolve36 } from "node:path";
|
|
158748
159153
|
function getMemoryFilesystemRoot2(agentId, homeDir = homedir40()) {
|
|
@@ -158778,10 +159183,10 @@ function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir40()) {
|
|
|
158778
159183
|
const root = getMemoryFilesystemRoot2(agentId, homeDir);
|
|
158779
159184
|
const systemDir = getMemorySystemDir2(agentId, homeDir);
|
|
158780
159185
|
if (!existsSync47(root)) {
|
|
158781
|
-
|
|
159186
|
+
mkdirSync34(root, { recursive: true });
|
|
158782
159187
|
}
|
|
158783
159188
|
if (!existsSync47(systemDir)) {
|
|
158784
|
-
|
|
159189
|
+
mkdirSync34(systemDir, { recursive: true });
|
|
158785
159190
|
}
|
|
158786
159191
|
}
|
|
158787
159192
|
async function isMemfsEnabledOnServer2(agentId) {
|
|
@@ -164102,51 +164507,141 @@ async function runListenSubcommand(argv) {
|
|
|
164102
164507
|
}
|
|
164103
164508
|
}
|
|
164104
164509
|
|
|
164105
|
-
// src/cli/subcommands/
|
|
164510
|
+
// src/cli/subcommands/memory.ts
|
|
164106
164511
|
init_memoryGit();
|
|
164107
|
-
import { cpSync, existsSync as existsSync30, mkdirSync as
|
|
164512
|
+
import { cpSync, existsSync as existsSync30, mkdirSync as mkdirSync23, rmSync as rmSync3, statSync as statSync8 } from "node:fs";
|
|
164108
164513
|
import { readdir as readdir7 } from "node:fs/promises";
|
|
164109
164514
|
import { homedir as homedir23 } from "node:os";
|
|
164110
164515
|
import { join as join34 } from "node:path";
|
|
164111
164516
|
import { parseArgs as parseArgs8 } from "node:util";
|
|
164517
|
+
|
|
164518
|
+
// src/cli/subcommands/memoryTokens.ts
|
|
164519
|
+
init_systemPromptSize();
|
|
164520
|
+
var DEFAULT_TOP = 20;
|
|
164521
|
+
var USAGE_EXIT = 64;
|
|
164522
|
+
var IO_EXIT = 65;
|
|
164523
|
+
function parsePositiveInt(raw, fallback) {
|
|
164524
|
+
if (raw === undefined)
|
|
164525
|
+
return fallback;
|
|
164526
|
+
if (!/^\d+$/.test(raw))
|
|
164527
|
+
return null;
|
|
164528
|
+
return Number.parseInt(raw, 10);
|
|
164529
|
+
}
|
|
164530
|
+
function formatNumber(value) {
|
|
164531
|
+
return value.toLocaleString("en-US");
|
|
164532
|
+
}
|
|
164533
|
+
function printText(total, files, top, quiet) {
|
|
164534
|
+
console.log("System prompt token estimate");
|
|
164535
|
+
console.log(` Total: ${formatNumber(total)} tokens`);
|
|
164536
|
+
if (quiet || top <= 0 || files.length === 0) {
|
|
164537
|
+
return;
|
|
164538
|
+
}
|
|
164539
|
+
const ranked = [...files].sort((a, b) => b.tokens - a.tokens);
|
|
164540
|
+
const limited = ranked.slice(0, top);
|
|
164541
|
+
console.log("");
|
|
164542
|
+
console.log("Top files:");
|
|
164543
|
+
console.log(` ${"tokens".padStart(8)} path`);
|
|
164544
|
+
for (const row of limited) {
|
|
164545
|
+
console.log(` ${formatNumber(row.tokens).padStart(8)} ${row.path}`);
|
|
164546
|
+
}
|
|
164547
|
+
}
|
|
164548
|
+
function printJson(total, files) {
|
|
164549
|
+
console.log(JSON.stringify({
|
|
164550
|
+
total_tokens: total,
|
|
164551
|
+
files
|
|
164552
|
+
}, null, 2));
|
|
164553
|
+
}
|
|
164554
|
+
function resolveMemoryDir3(options) {
|
|
164555
|
+
if (options.memoryDir)
|
|
164556
|
+
return options.memoryDir;
|
|
164557
|
+
if (process.env.MEMORY_DIR)
|
|
164558
|
+
return process.env.MEMORY_DIR;
|
|
164559
|
+
if (options.agentMemoryDir)
|
|
164560
|
+
return options.agentMemoryDir;
|
|
164561
|
+
return null;
|
|
164562
|
+
}
|
|
164563
|
+
async function runMemoryTokensAction(options) {
|
|
164564
|
+
const format2 = options.format ?? "text";
|
|
164565
|
+
if (format2 !== "text" && format2 !== "json") {
|
|
164566
|
+
console.error(`Invalid --format: ${format2} (expected text or json)`);
|
|
164567
|
+
return USAGE_EXIT;
|
|
164568
|
+
}
|
|
164569
|
+
const top = parsePositiveInt(options.top, DEFAULT_TOP);
|
|
164570
|
+
if (top === null) {
|
|
164571
|
+
console.error(`Invalid --top: ${options.top} (expected non-negative integer)`);
|
|
164572
|
+
return USAGE_EXIT;
|
|
164573
|
+
}
|
|
164574
|
+
const memoryDir = resolveMemoryDir3(options);
|
|
164575
|
+
if (!memoryDir) {
|
|
164576
|
+
console.error("Missing memory dir. Set --memory-dir, --agent, $MEMORY_DIR, or $LETTA_AGENT_ID.");
|
|
164577
|
+
return USAGE_EXIT;
|
|
164578
|
+
}
|
|
164579
|
+
let estimate;
|
|
164580
|
+
try {
|
|
164581
|
+
estimate = estimateSystemPromptSize(memoryDir);
|
|
164582
|
+
} catch (error) {
|
|
164583
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
164584
|
+
console.error(`Failed to read memory dir: ${message}`);
|
|
164585
|
+
return IO_EXIT;
|
|
164586
|
+
}
|
|
164587
|
+
const { total, files } = estimate;
|
|
164588
|
+
if (format2 === "json") {
|
|
164589
|
+
printJson(total, files);
|
|
164590
|
+
} else {
|
|
164591
|
+
printText(total, files, top, options.quiet);
|
|
164592
|
+
}
|
|
164593
|
+
return 0;
|
|
164594
|
+
}
|
|
164595
|
+
|
|
164596
|
+
// src/cli/subcommands/memory.ts
|
|
164112
164597
|
function printUsage5() {
|
|
164113
164598
|
console.log(`
|
|
164114
164599
|
Usage:
|
|
164115
|
-
letta
|
|
164116
|
-
letta
|
|
164117
|
-
letta
|
|
164118
|
-
letta
|
|
164119
|
-
letta
|
|
164120
|
-
letta
|
|
164121
|
-
letta
|
|
164600
|
+
letta memory status [--agent <id>]
|
|
164601
|
+
letta memory diff [--agent <id>]
|
|
164602
|
+
letta memory backup [--agent <id>]
|
|
164603
|
+
letta memory backups [--agent <id>]
|
|
164604
|
+
letta memory restore --from <backup> --force [--agent <id>]
|
|
164605
|
+
letta memory export --agent <id> --out <dir>
|
|
164606
|
+
letta memory pull [--agent <id>]
|
|
164607
|
+
letta memory tokens [--memory-dir <path>] [--agent <id>] [--top <N>]
|
|
164608
|
+
[--format text|json] [--quiet]
|
|
164122
164609
|
|
|
164123
164610
|
Notes:
|
|
164124
|
-
-
|
|
164125
|
-
-
|
|
164611
|
+
- Most actions require agent id via --agent or LETTA_AGENT_ID and output JSON.
|
|
164612
|
+
- \`tokens\` additionally accepts --memory-dir or $MEMORY_DIR; reports the
|
|
164613
|
+
estimated token size of system/. Policy (whether a size is concerning) is
|
|
164614
|
+
up to the caller.
|
|
164126
164615
|
- Memory is git-backed. Use git commands for commit/push.
|
|
164127
164616
|
|
|
164128
164617
|
Examples:
|
|
164129
|
-
LETTA_AGENT_ID=agent-123 letta
|
|
164130
|
-
letta
|
|
164131
|
-
letta
|
|
164132
|
-
letta
|
|
164618
|
+
LETTA_AGENT_ID=agent-123 letta memory status
|
|
164619
|
+
letta memory pull --agent agent-123
|
|
164620
|
+
letta memory backup --agent agent-123
|
|
164621
|
+
letta memory export --agent agent-123 --out /tmp/letta-memory-agent-123
|
|
164622
|
+
letta memory tokens
|
|
164623
|
+
letta memory tokens --memory-dir ~/.letta/agents/agent-123/memory --format json
|
|
164133
164624
|
`.trim());
|
|
164134
164625
|
}
|
|
164135
164626
|
function getAgentId5(agentFromArgs, agentIdFromArgs) {
|
|
164136
164627
|
return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
|
|
164137
164628
|
}
|
|
164138
|
-
var
|
|
164629
|
+
var MEMORY_OPTIONS = {
|
|
164139
164630
|
help: { type: "boolean", short: "h" },
|
|
164140
164631
|
agent: { type: "string" },
|
|
164141
164632
|
"agent-id": { type: "string" },
|
|
164142
164633
|
from: { type: "string" },
|
|
164143
164634
|
force: { type: "boolean" },
|
|
164144
|
-
out: { type: "string" }
|
|
164635
|
+
out: { type: "string" },
|
|
164636
|
+
"memory-dir": { type: "string" },
|
|
164637
|
+
top: { type: "string" },
|
|
164638
|
+
format: { type: "string" },
|
|
164639
|
+
quiet: { type: "boolean" }
|
|
164145
164640
|
};
|
|
164146
|
-
function
|
|
164641
|
+
function parseMemoryArgs(argv) {
|
|
164147
164642
|
return parseArgs8({
|
|
164148
164643
|
args: argv,
|
|
164149
|
-
options:
|
|
164644
|
+
options: MEMORY_OPTIONS,
|
|
164150
164645
|
strict: true,
|
|
164151
164646
|
allowPositionals: true
|
|
164152
164647
|
});
|
|
@@ -164198,10 +164693,10 @@ function resolveBackupPath(agentId, from) {
|
|
|
164198
164693
|
}
|
|
164199
164694
|
return join34(getAgentRoot(agentId), from);
|
|
164200
164695
|
}
|
|
164201
|
-
async function
|
|
164696
|
+
async function runMemorySubcommand(argv) {
|
|
164202
164697
|
let parsed;
|
|
164203
164698
|
try {
|
|
164204
|
-
parsed =
|
|
164699
|
+
parsed = parseMemoryArgs(argv);
|
|
164205
164700
|
} catch (error) {
|
|
164206
164701
|
const message = error instanceof Error ? error.message : String(error);
|
|
164207
164702
|
console.error(`Error: ${message}`);
|
|
@@ -164214,6 +164709,15 @@ async function runMemfsSubcommand(argv) {
|
|
|
164214
164709
|
return 0;
|
|
164215
164710
|
}
|
|
164216
164711
|
const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
|
|
164712
|
+
if (action === "tokens") {
|
|
164713
|
+
return runMemoryTokensAction({
|
|
164714
|
+
memoryDir: parsed.values["memory-dir"],
|
|
164715
|
+
agentMemoryDir: agentId ? getMemoryRoot(agentId) : undefined,
|
|
164716
|
+
top: parsed.values.top,
|
|
164717
|
+
format: parsed.values.format,
|
|
164718
|
+
quiet: Boolean(parsed.values.quiet)
|
|
164719
|
+
});
|
|
164720
|
+
}
|
|
164217
164721
|
if (!agentId) {
|
|
164218
164722
|
console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
|
|
164219
164723
|
return 1;
|
|
@@ -164326,7 +164830,7 @@ async function runMemfsSubcommand(argv) {
|
|
|
164326
164830
|
return 1;
|
|
164327
164831
|
}
|
|
164328
164832
|
} else {
|
|
164329
|
-
|
|
164833
|
+
mkdirSync23(out, { recursive: true });
|
|
164330
164834
|
}
|
|
164331
164835
|
cpSync(root, out, { recursive: true });
|
|
164332
164836
|
console.log(JSON.stringify({ exportedFrom: root, exportedTo: out, agentId }, null, 2));
|
|
@@ -164685,8 +165189,9 @@ async function runSubcommand(argv) {
|
|
|
164685
165189
|
return null;
|
|
164686
165190
|
}
|
|
164687
165191
|
switch (command) {
|
|
165192
|
+
case "memory":
|
|
164688
165193
|
case "memfs":
|
|
164689
|
-
return
|
|
165194
|
+
return runMemorySubcommand(rest);
|
|
164690
165195
|
case "agents":
|
|
164691
165196
|
return runAgentsSubcommand(rest);
|
|
164692
165197
|
case "messages":
|
|
@@ -166855,7 +167360,7 @@ USAGE
|
|
|
166855
167360
|
|
|
166856
167361
|
# maintenance
|
|
166857
167362
|
letta update Manually check for updates and install if available
|
|
166858
|
-
letta
|
|
167363
|
+
letta memory ... Memory filesystem subcommands
|
|
166859
167364
|
letta agents ... Agents subcommands (JSON-only)
|
|
166860
167365
|
letta messages ... Messages subcommands (JSON-only)
|
|
166861
167366
|
letta blocks ... Blocks subcommands (JSON-only)
|
|
@@ -166864,14 +167369,16 @@ USAGE
|
|
|
166864
167369
|
OPTIONS
|
|
166865
167370
|
${renderCliOptionsHelp()}
|
|
166866
167371
|
|
|
166867
|
-
SUBCOMMANDS
|
|
166868
|
-
letta
|
|
166869
|
-
letta
|
|
166870
|
-
letta
|
|
166871
|
-
letta
|
|
166872
|
-
letta
|
|
166873
|
-
letta
|
|
166874
|
-
letta
|
|
167372
|
+
SUBCOMMANDS
|
|
167373
|
+
letta memory status --agent <id>
|
|
167374
|
+
letta memory diff --agent <id>
|
|
167375
|
+
letta memory resolve --agent <id> --resolutions '<JSON>'
|
|
167376
|
+
letta memory backup --agent <id>
|
|
167377
|
+
letta memory backups --agent <id>
|
|
167378
|
+
letta memory restore --agent <id> --from <backup> --force
|
|
167379
|
+
letta memory export --agent <id> --out <dir>
|
|
167380
|
+
letta memory pull --agent <id>
|
|
167381
|
+
letta memory tokens [--memory-dir <path>] [--agent <id>] [--format text|json]
|
|
166875
167382
|
letta agents list [--query <text> | --name <name> | --tags <tags>]
|
|
166876
167383
|
letta messages search --query <text> [--all-agents]
|
|
166877
167384
|
letta messages list [--agent <id>]
|
|
@@ -168205,4 +168712,4 @@ Error during initialization: ${message}`);
|
|
|
168205
168712
|
}
|
|
168206
168713
|
main();
|
|
168207
168714
|
|
|
168208
|
-
//# debugId=
|
|
168715
|
+
//# debugId=A2D8C37B0089C68564756E2164756E21
|