@letta-ai/letta-code 0.19.8 → 0.19.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +1526 -800
- package/package.json +1 -1
- package/scripts/latency-benchmark.ts +18 -9
package/letta.js
CHANGED
|
@@ -3255,7 +3255,7 @@ var package_default;
|
|
|
3255
3255
|
var init_package = __esm(() => {
|
|
3256
3256
|
package_default = {
|
|
3257
3257
|
name: "@letta-ai/letta-code",
|
|
3258
|
-
version: "0.19.
|
|
3258
|
+
version: "0.19.9",
|
|
3259
3259
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3260
3260
|
type: "module",
|
|
3261
3261
|
bin: {
|
|
@@ -4247,6 +4247,11 @@ class SettingsManager {
|
|
|
4247
4247
|
}
|
|
4248
4248
|
return this.getGlobalLastAgentId();
|
|
4249
4249
|
}
|
|
4250
|
+
persistSession(agentId, conversationId, workingDirectory = process.cwd()) {
|
|
4251
|
+
const session = { agentId, conversationId };
|
|
4252
|
+
this.setLocalLastSession(session, workingDirectory);
|
|
4253
|
+
this.setGlobalLastSession(session);
|
|
4254
|
+
}
|
|
4250
4255
|
getGlobalPinnedAgents() {
|
|
4251
4256
|
const settings = this.getSettings();
|
|
4252
4257
|
const serverKey = getCurrentServerKey(settings);
|
|
@@ -4609,6 +4614,7 @@ var init_settings_manager = __esm(async () => {
|
|
|
4609
4614
|
enableSleeptime: false,
|
|
4610
4615
|
conversationSwitchAlertEnabled: false,
|
|
4611
4616
|
sessionContextEnabled: true,
|
|
4617
|
+
autoSwapOnQuotaLimit: true,
|
|
4612
4618
|
memoryReminderInterval: 25,
|
|
4613
4619
|
reflectionTrigger: "step-count",
|
|
4614
4620
|
reflectionStepCount: 25,
|
|
@@ -40351,6 +40357,31 @@ var init_fileIndex = __esm(() => {
|
|
|
40351
40357
|
cachedEntryPaths2 = new Set;
|
|
40352
40358
|
});
|
|
40353
40359
|
|
|
40360
|
+
// src/cli/helpers/messageQueueBridge.ts
|
|
40361
|
+
function setMessageQueueAdder(fn) {
|
|
40362
|
+
queueAdder = fn;
|
|
40363
|
+
if (queueAdder && pendingMessages.length > 0) {
|
|
40364
|
+
for (const message of pendingMessages) {
|
|
40365
|
+
queueAdder(message);
|
|
40366
|
+
}
|
|
40367
|
+
pendingMessages.length = 0;
|
|
40368
|
+
}
|
|
40369
|
+
}
|
|
40370
|
+
function addToMessageQueue(message) {
|
|
40371
|
+
if (queueAdder) {
|
|
40372
|
+
queueAdder(message);
|
|
40373
|
+
return;
|
|
40374
|
+
}
|
|
40375
|
+
if (pendingMessages.length >= MAX_PENDING_MESSAGES) {
|
|
40376
|
+
pendingMessages.shift();
|
|
40377
|
+
}
|
|
40378
|
+
pendingMessages.push(message);
|
|
40379
|
+
}
|
|
40380
|
+
var queueAdder = null, pendingMessages, MAX_PENDING_MESSAGES = 10;
|
|
40381
|
+
var init_messageQueueBridge = __esm(() => {
|
|
40382
|
+
pendingMessages = [];
|
|
40383
|
+
});
|
|
40384
|
+
|
|
40354
40385
|
// src/cli/helpers/planName.ts
|
|
40355
40386
|
import { homedir as homedir8 } from "node:os";
|
|
40356
40387
|
import { join as join9 } from "node:path";
|
|
@@ -40469,6 +40500,186 @@ var init_planName = __esm(() => {
|
|
|
40469
40500
|
];
|
|
40470
40501
|
});
|
|
40471
40502
|
|
|
40503
|
+
// src/cli/helpers/subagentState.ts
|
|
40504
|
+
function updateSnapshot() {
|
|
40505
|
+
cachedSnapshot = {
|
|
40506
|
+
agents: Array.from(store.agents.values()),
|
|
40507
|
+
expanded: store.expanded
|
|
40508
|
+
};
|
|
40509
|
+
}
|
|
40510
|
+
function notifyListeners() {
|
|
40511
|
+
updateSnapshot();
|
|
40512
|
+
for (const listener of store.listeners) {
|
|
40513
|
+
listener();
|
|
40514
|
+
}
|
|
40515
|
+
}
|
|
40516
|
+
function generateSubagentId() {
|
|
40517
|
+
return `subagent-${Date.now()}-${++subagentCounter}`;
|
|
40518
|
+
}
|
|
40519
|
+
function getSubagentByToolCallId(toolCallId) {
|
|
40520
|
+
for (const agent of store.agents.values()) {
|
|
40521
|
+
if (agent.toolCallId === toolCallId) {
|
|
40522
|
+
return agent;
|
|
40523
|
+
}
|
|
40524
|
+
}
|
|
40525
|
+
return;
|
|
40526
|
+
}
|
|
40527
|
+
function registerSubagent(id, type, description, toolCallId, isBackground, silent) {
|
|
40528
|
+
const displayType = type.charAt(0).toUpperCase() + type.slice(1);
|
|
40529
|
+
const agent = {
|
|
40530
|
+
id,
|
|
40531
|
+
type: displayType,
|
|
40532
|
+
description,
|
|
40533
|
+
status: "pending",
|
|
40534
|
+
agentURL: null,
|
|
40535
|
+
toolCalls: [],
|
|
40536
|
+
maxToolCallsSeen: 0,
|
|
40537
|
+
totalTokens: 0,
|
|
40538
|
+
durationMs: 0,
|
|
40539
|
+
startTime: Date.now(),
|
|
40540
|
+
toolCallId,
|
|
40541
|
+
isBackground,
|
|
40542
|
+
silent
|
|
40543
|
+
};
|
|
40544
|
+
store.agents.set(id, agent);
|
|
40545
|
+
notifyListeners();
|
|
40546
|
+
}
|
|
40547
|
+
function updateSubagent(id, updates) {
|
|
40548
|
+
const agent = store.agents.get(id);
|
|
40549
|
+
if (!agent)
|
|
40550
|
+
return;
|
|
40551
|
+
if (updates.agentURL && agent.status === "pending") {
|
|
40552
|
+
updates.status = "running";
|
|
40553
|
+
}
|
|
40554
|
+
const nextToolCalls = updates.toolCalls ?? agent.toolCalls;
|
|
40555
|
+
const nextMax = Math.max(agent.maxToolCallsSeen, nextToolCalls.length, updates.maxToolCallsSeen ?? 0);
|
|
40556
|
+
const keys = Object.keys(updates);
|
|
40557
|
+
const isNoop = keys.every((k) => agent[k] === updates[k]) && nextMax === agent.maxToolCallsSeen;
|
|
40558
|
+
if (isNoop)
|
|
40559
|
+
return;
|
|
40560
|
+
const updatedAgent = { ...agent, ...updates, maxToolCallsSeen: nextMax };
|
|
40561
|
+
store.agents.set(id, updatedAgent);
|
|
40562
|
+
notifyListeners();
|
|
40563
|
+
}
|
|
40564
|
+
function addToolCall(subagentId, toolCallId, toolName, toolArgs) {
|
|
40565
|
+
const agent = store.agents.get(subagentId);
|
|
40566
|
+
if (!agent)
|
|
40567
|
+
return;
|
|
40568
|
+
if (agent.toolCalls.some((tc) => tc.id === toolCallId))
|
|
40569
|
+
return;
|
|
40570
|
+
const updatedAgent = {
|
|
40571
|
+
...agent,
|
|
40572
|
+
toolCalls: [
|
|
40573
|
+
...agent.toolCalls,
|
|
40574
|
+
{ id: toolCallId, name: toolName, args: toolArgs }
|
|
40575
|
+
],
|
|
40576
|
+
maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length + 1)
|
|
40577
|
+
};
|
|
40578
|
+
store.agents.set(subagentId, updatedAgent);
|
|
40579
|
+
notifyListeners();
|
|
40580
|
+
}
|
|
40581
|
+
function completeSubagent(id, result) {
|
|
40582
|
+
const agent = store.agents.get(id);
|
|
40583
|
+
if (!agent)
|
|
40584
|
+
return;
|
|
40585
|
+
const updatedAgent = {
|
|
40586
|
+
...agent,
|
|
40587
|
+
status: result.success ? "completed" : "error",
|
|
40588
|
+
error: result.error,
|
|
40589
|
+
durationMs: Date.now() - agent.startTime,
|
|
40590
|
+
totalTokens: result.totalTokens ?? agent.totalTokens,
|
|
40591
|
+
maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length)
|
|
40592
|
+
};
|
|
40593
|
+
store.agents.set(id, updatedAgent);
|
|
40594
|
+
notifyListeners();
|
|
40595
|
+
}
|
|
40596
|
+
function getSubagentToolCount(agent) {
|
|
40597
|
+
return Math.max(agent.toolCalls.length, agent.maxToolCallsSeen);
|
|
40598
|
+
}
|
|
40599
|
+
function toggleExpanded() {
|
|
40600
|
+
store.expanded = !store.expanded;
|
|
40601
|
+
notifyListeners();
|
|
40602
|
+
}
|
|
40603
|
+
function getSubagents() {
|
|
40604
|
+
return Array.from(store.agents.values());
|
|
40605
|
+
}
|
|
40606
|
+
function getActiveBackgroundAgents() {
|
|
40607
|
+
return Array.from(store.agents.values()).filter((a) => a.silent === true && (a.status === "pending" || a.status === "running"));
|
|
40608
|
+
}
|
|
40609
|
+
function clearCompletedSubagents() {
|
|
40610
|
+
for (const [id, agent] of store.agents.entries()) {
|
|
40611
|
+
if (agent.status === "completed" || agent.status === "error") {
|
|
40612
|
+
store.agents.delete(id);
|
|
40613
|
+
}
|
|
40614
|
+
}
|
|
40615
|
+
notifyListeners();
|
|
40616
|
+
}
|
|
40617
|
+
function clearSubagentsByIds(ids) {
|
|
40618
|
+
for (const id of ids) {
|
|
40619
|
+
store.agents.delete(id);
|
|
40620
|
+
}
|
|
40621
|
+
notifyListeners();
|
|
40622
|
+
}
|
|
40623
|
+
function hasActiveSubagents() {
|
|
40624
|
+
for (const agent of store.agents.values()) {
|
|
40625
|
+
if (agent.status === "pending" || agent.status === "running") {
|
|
40626
|
+
return true;
|
|
40627
|
+
}
|
|
40628
|
+
}
|
|
40629
|
+
return false;
|
|
40630
|
+
}
|
|
40631
|
+
function interruptActiveSubagents(errorMessage) {
|
|
40632
|
+
let anyInterrupted = false;
|
|
40633
|
+
for (const [id, agent] of store.agents.entries()) {
|
|
40634
|
+
if (agent.status === "pending" || agent.status === "running") {
|
|
40635
|
+
const updatedAgent = {
|
|
40636
|
+
...agent,
|
|
40637
|
+
status: "error",
|
|
40638
|
+
error: errorMessage,
|
|
40639
|
+
durationMs: Date.now() - agent.startTime
|
|
40640
|
+
};
|
|
40641
|
+
store.agents.set(id, updatedAgent);
|
|
40642
|
+
anyInterrupted = true;
|
|
40643
|
+
}
|
|
40644
|
+
}
|
|
40645
|
+
if (anyInterrupted) {
|
|
40646
|
+
notifyListeners();
|
|
40647
|
+
}
|
|
40648
|
+
}
|
|
40649
|
+
function subscribe2(listener) {
|
|
40650
|
+
store.listeners.add(listener);
|
|
40651
|
+
return () => {
|
|
40652
|
+
store.listeners.delete(listener);
|
|
40653
|
+
};
|
|
40654
|
+
}
|
|
40655
|
+
function getSnapshot2() {
|
|
40656
|
+
return cachedSnapshot;
|
|
40657
|
+
}
|
|
40658
|
+
function subscribeToStreamEvents(listener) {
|
|
40659
|
+
streamEventListeners.add(listener);
|
|
40660
|
+
return () => {
|
|
40661
|
+
streamEventListeners.delete(listener);
|
|
40662
|
+
};
|
|
40663
|
+
}
|
|
40664
|
+
function emitStreamEvent(subagentId, event) {
|
|
40665
|
+
for (const listener of streamEventListeners) {
|
|
40666
|
+
listener(subagentId, event);
|
|
40667
|
+
}
|
|
40668
|
+
}
|
|
40669
|
+
var store, cachedSnapshot, subagentCounter = 0, streamEventListeners;
|
|
40670
|
+
var init_subagentState = __esm(() => {
|
|
40671
|
+
store = {
|
|
40672
|
+
agents: new Map,
|
|
40673
|
+
expanded: false,
|
|
40674
|
+
listeners: new Set
|
|
40675
|
+
};
|
|
40676
|
+
cachedSnapshot = {
|
|
40677
|
+
agents: [],
|
|
40678
|
+
expanded: false
|
|
40679
|
+
};
|
|
40680
|
+
streamEventListeners = new Set;
|
|
40681
|
+
});
|
|
40682
|
+
|
|
40472
40683
|
// src/queue/queueRuntime.ts
|
|
40473
40684
|
function isCoalescable(kind) {
|
|
40474
40685
|
return kind === "message" || kind === "task_notification";
|
|
@@ -40738,6 +40949,7 @@ async function executeSingleDecision(decision, onChunk, options) {
|
|
|
40738
40949
|
signal: options?.abortSignal,
|
|
40739
40950
|
toolCallId: decision.approval.toolCallId,
|
|
40740
40951
|
toolContextId: options?.toolContextId,
|
|
40952
|
+
parentScope: options?.parentScope,
|
|
40741
40953
|
onOutput: options?.onStreamingOutput ? (chunk, stream) => options.onStreamingOutput?.(decision.approval.toolCallId, chunk, stream === "stderr") : undefined
|
|
40742
40954
|
});
|
|
40743
40955
|
if (onChunk) {
|
|
@@ -43157,6 +43369,141 @@ var init_telemetry = __esm(async () => {
|
|
|
43157
43369
|
telemetry = new TelemetryManager;
|
|
43158
43370
|
});
|
|
43159
43371
|
|
|
43372
|
+
// src/utils/secretsStore.ts
|
|
43373
|
+
var exports_secretsStore = {};
|
|
43374
|
+
__export(exports_secretsStore, {
|
|
43375
|
+
setSecretOnServer: () => setSecretOnServer,
|
|
43376
|
+
loadSecrets: () => loadSecrets,
|
|
43377
|
+
listSecretNames: () => listSecretNames,
|
|
43378
|
+
initSecretsFromServer: () => initSecretsFromServer,
|
|
43379
|
+
deleteSecretOnServer: () => deleteSecretOnServer,
|
|
43380
|
+
clearSecretsCache: () => clearSecretsCache
|
|
43381
|
+
});
|
|
43382
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
43383
|
+
import { dirname as dirname3, join as join11 } from "node:path";
|
|
43384
|
+
function getAgentId3() {
|
|
43385
|
+
const agentId = storedAgentId || process.env.AGENT_ID || process.env.LETTA_AGENT_ID;
|
|
43386
|
+
if (!agentId) {
|
|
43387
|
+
throw new Error("No agent ID available — call initSecretsFromServer first");
|
|
43388
|
+
}
|
|
43389
|
+
return agentId;
|
|
43390
|
+
}
|
|
43391
|
+
async function initSecretsFromServer(agentId, memoryDir) {
|
|
43392
|
+
storedAgentId = agentId;
|
|
43393
|
+
if (memoryDir)
|
|
43394
|
+
storedMemoryDir = memoryDir;
|
|
43395
|
+
const client = await getClient2();
|
|
43396
|
+
const agent = await client.agents.retrieve(agentId, {
|
|
43397
|
+
include: ["agent.secrets"]
|
|
43398
|
+
});
|
|
43399
|
+
const secrets2 = {};
|
|
43400
|
+
if (agent.secrets && Array.isArray(agent.secrets)) {
|
|
43401
|
+
for (const env3 of agent.secrets) {
|
|
43402
|
+
if (env3.key && env3.value) {
|
|
43403
|
+
secrets2[env3.key] = env3.value;
|
|
43404
|
+
}
|
|
43405
|
+
}
|
|
43406
|
+
}
|
|
43407
|
+
cachedSecrets = secrets2;
|
|
43408
|
+
syncSecretsToMemoryBlock();
|
|
43409
|
+
}
|
|
43410
|
+
function loadSecrets() {
|
|
43411
|
+
return cachedSecrets ?? {};
|
|
43412
|
+
}
|
|
43413
|
+
function listSecretNames() {
|
|
43414
|
+
return Object.keys(loadSecrets()).sort();
|
|
43415
|
+
}
|
|
43416
|
+
async function setSecretOnServer(key, value) {
|
|
43417
|
+
const client = await getClient2();
|
|
43418
|
+
const agentId = getAgentId3();
|
|
43419
|
+
const secrets2 = { ...loadSecrets() };
|
|
43420
|
+
secrets2[key] = value;
|
|
43421
|
+
await client.agents.update(agentId, { secrets: secrets2 });
|
|
43422
|
+
cachedSecrets = secrets2;
|
|
43423
|
+
syncSecretsToMemoryBlock();
|
|
43424
|
+
}
|
|
43425
|
+
async function deleteSecretOnServer(key) {
|
|
43426
|
+
const secrets2 = { ...loadSecrets() };
|
|
43427
|
+
if (!(key in secrets2)) {
|
|
43428
|
+
return false;
|
|
43429
|
+
}
|
|
43430
|
+
delete secrets2[key];
|
|
43431
|
+
const client = await getClient2();
|
|
43432
|
+
const agentId = getAgentId3();
|
|
43433
|
+
await client.agents.update(agentId, { secrets: secrets2 });
|
|
43434
|
+
cachedSecrets = secrets2;
|
|
43435
|
+
syncSecretsToMemoryBlock();
|
|
43436
|
+
return true;
|
|
43437
|
+
}
|
|
43438
|
+
function syncSecretsToMemoryBlock() {
|
|
43439
|
+
const memoryDir = storedMemoryDir || process.env.MEMORY_DIR;
|
|
43440
|
+
if (!memoryDir)
|
|
43441
|
+
return;
|
|
43442
|
+
const names = listSecretNames();
|
|
43443
|
+
const secretsFilePath = join11(memoryDir, "system", "secrets.md");
|
|
43444
|
+
const description = names.length > 0 ? "Available secrets for shell command substitution" : "No secrets configured";
|
|
43445
|
+
const body = names.length > 0 ? `Use \`$SECRET_NAME\` syntax in shell commands to reference these secrets:
|
|
43446
|
+
|
|
43447
|
+
${names.map((n) => `- \`$${n}\``).join(`
|
|
43448
|
+
`)}` : "";
|
|
43449
|
+
const rendered = `---
|
|
43450
|
+
description: ${description}
|
|
43451
|
+
---
|
|
43452
|
+
|
|
43453
|
+
## Available Secrets
|
|
43454
|
+
|
|
43455
|
+
${body}
|
|
43456
|
+
`;
|
|
43457
|
+
const systemDir = dirname3(secretsFilePath);
|
|
43458
|
+
if (!existsSync10(systemDir)) {
|
|
43459
|
+
mkdirSync8(systemDir, { recursive: true });
|
|
43460
|
+
}
|
|
43461
|
+
writeFileSync5(secretsFilePath, rendered, "utf8");
|
|
43462
|
+
}
|
|
43463
|
+
function clearSecretsCache() {
|
|
43464
|
+
cachedSecrets = null;
|
|
43465
|
+
}
|
|
43466
|
+
var cachedSecrets = null, storedAgentId = null, storedMemoryDir = null;
|
|
43467
|
+
var init_secretsStore = __esm(async () => {
|
|
43468
|
+
await init_client2();
|
|
43469
|
+
});
|
|
43470
|
+
|
|
43471
|
+
// src/tools/secret-substitution.ts
|
|
43472
|
+
function substituteSecretsInString(input) {
|
|
43473
|
+
const secrets2 = loadSecrets();
|
|
43474
|
+
return input.replace(SECRET_PATTERN, (match, name) => {
|
|
43475
|
+
const value = secrets2[name];
|
|
43476
|
+
return value !== undefined ? value : match;
|
|
43477
|
+
});
|
|
43478
|
+
}
|
|
43479
|
+
function substituteSecretsInArgs(args) {
|
|
43480
|
+
const result = {};
|
|
43481
|
+
for (const [key, value] of Object.entries(args)) {
|
|
43482
|
+
if (typeof value === "string") {
|
|
43483
|
+
result[key] = substituteSecretsInString(value);
|
|
43484
|
+
} else {
|
|
43485
|
+
result[key] = value;
|
|
43486
|
+
}
|
|
43487
|
+
}
|
|
43488
|
+
return result;
|
|
43489
|
+
}
|
|
43490
|
+
function scrubSecretsFromString(input) {
|
|
43491
|
+
const secrets2 = loadSecrets();
|
|
43492
|
+
let result = input;
|
|
43493
|
+
const entries = Object.entries(secrets2).sort(([, a], [, b]) => b.length - a.length);
|
|
43494
|
+
for (const [name, value] of entries) {
|
|
43495
|
+
if (value.length > 0) {
|
|
43496
|
+
result = result.replaceAll(value, `$${name}`);
|
|
43497
|
+
}
|
|
43498
|
+
}
|
|
43499
|
+
return result;
|
|
43500
|
+
}
|
|
43501
|
+
var SECRET_PATTERN;
|
|
43502
|
+
var init_secret_substitution = __esm(async () => {
|
|
43503
|
+
await init_secretsStore();
|
|
43504
|
+
SECRET_PATTERN = /\$([A-Z_][A-Z0-9_]*)/g;
|
|
43505
|
+
});
|
|
43506
|
+
|
|
43160
43507
|
// src/tools/descriptions/ApplyPatch.md
|
|
43161
43508
|
var ApplyPatch_default = `Use the \`apply_patch\` tool to edit files.
|
|
43162
43509
|
Your patch language is a stripped‑down, file‑oriented diff format designed to be easy to parse and safe to apply. You can think of it as a high‑level envelope:
|
|
@@ -44859,20 +45206,20 @@ __export(exports_memoryGit, {
|
|
|
44859
45206
|
import { execFile as execFileCb } from "node:child_process";
|
|
44860
45207
|
import {
|
|
44861
45208
|
chmodSync,
|
|
44862
|
-
existsSync as
|
|
44863
|
-
mkdirSync as
|
|
45209
|
+
existsSync as existsSync11,
|
|
45210
|
+
mkdirSync as mkdirSync9,
|
|
44864
45211
|
renameSync,
|
|
44865
45212
|
rmSync,
|
|
44866
|
-
writeFileSync as
|
|
45213
|
+
writeFileSync as writeFileSync6
|
|
44867
45214
|
} from "node:fs";
|
|
44868
45215
|
import { homedir as homedir12 } from "node:os";
|
|
44869
|
-
import { join as
|
|
45216
|
+
import { join as join12 } from "node:path";
|
|
44870
45217
|
import { promisify as promisify6 } from "node:util";
|
|
44871
45218
|
function getAgentRootDir(agentId) {
|
|
44872
|
-
return
|
|
45219
|
+
return join12(homedir12(), ".letta", "agents", agentId);
|
|
44873
45220
|
}
|
|
44874
45221
|
function getMemoryRepoDir(agentId) {
|
|
44875
|
-
return
|
|
45222
|
+
return join12(getAgentRootDir(agentId), "memory");
|
|
44876
45223
|
}
|
|
44877
45224
|
function normalizeCredentialBaseUrl(serverUrl) {
|
|
44878
45225
|
const trimmed = serverUrl.trim().replace(/\/+$/, "");
|
|
@@ -44924,39 +45271,39 @@ async function configureLocalCredentialHelper(dir, token) {
|
|
|
44924
45271
|
debugLog("memfs-git", `Configured local credential helper for ${normalizedBaseUrl}${rawBaseUrl !== normalizedBaseUrl ? ` (and raw ${rawBaseUrl})` : ""}`);
|
|
44925
45272
|
}
|
|
44926
45273
|
function installPreCommitHook(dir) {
|
|
44927
|
-
const hooksDir =
|
|
44928
|
-
const hookPath =
|
|
44929
|
-
if (!
|
|
44930
|
-
|
|
45274
|
+
const hooksDir = join12(dir, ".git", "hooks");
|
|
45275
|
+
const hookPath = join12(hooksDir, "pre-commit");
|
|
45276
|
+
if (!existsSync11(hooksDir)) {
|
|
45277
|
+
mkdirSync9(hooksDir, { recursive: true });
|
|
44931
45278
|
}
|
|
44932
|
-
|
|
45279
|
+
writeFileSync6(hookPath, PRE_COMMIT_HOOK_SCRIPT, "utf-8");
|
|
44933
45280
|
chmodSync(hookPath, 493);
|
|
44934
45281
|
debugLog("memfs-git", "Installed pre-commit hook");
|
|
44935
45282
|
}
|
|
44936
45283
|
function isGitRepo(agentId) {
|
|
44937
|
-
return
|
|
45284
|
+
return existsSync11(join12(getMemoryRepoDir(agentId), ".git"));
|
|
44938
45285
|
}
|
|
44939
45286
|
async function cloneMemoryRepo(agentId) {
|
|
44940
45287
|
const token = await getAuthToken();
|
|
44941
45288
|
const url = getGitRemoteUrl(agentId);
|
|
44942
45289
|
const dir = getMemoryRepoDir(agentId);
|
|
44943
45290
|
debugLog("memfs-git", `Cloning ${url} → ${dir}`);
|
|
44944
|
-
if (!
|
|
44945
|
-
|
|
45291
|
+
if (!existsSync11(dir)) {
|
|
45292
|
+
mkdirSync9(dir, { recursive: true });
|
|
44946
45293
|
await runGit(dir, ["clone", url, "."], token);
|
|
44947
|
-
} else if (!
|
|
45294
|
+
} else if (!existsSync11(join12(dir, ".git"))) {
|
|
44948
45295
|
const tmpDir = `${dir}-git-clone-tmp`;
|
|
44949
45296
|
try {
|
|
44950
|
-
if (
|
|
45297
|
+
if (existsSync11(tmpDir)) {
|
|
44951
45298
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
44952
45299
|
}
|
|
44953
|
-
|
|
45300
|
+
mkdirSync9(tmpDir, { recursive: true });
|
|
44954
45301
|
await runGit(tmpDir, ["clone", url, "."], token);
|
|
44955
|
-
renameSync(
|
|
45302
|
+
renameSync(join12(tmpDir, ".git"), join12(dir, ".git"));
|
|
44956
45303
|
await runGit(dir, ["checkout", "--", "."], token);
|
|
44957
45304
|
debugLog("memfs-git", "Migrated existing memory directory to git repo");
|
|
44958
45305
|
} finally {
|
|
44959
|
-
if (
|
|
45306
|
+
if (existsSync11(tmpDir)) {
|
|
44960
45307
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
44961
45308
|
}
|
|
44962
45309
|
}
|
|
@@ -45699,23 +46046,23 @@ __export(exports_memoryFilesystem, {
|
|
|
45699
46046
|
MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR,
|
|
45700
46047
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR
|
|
45701
46048
|
});
|
|
45702
|
-
import { existsSync as
|
|
46049
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync10 } from "node:fs";
|
|
45703
46050
|
import { homedir as homedir13 } from "node:os";
|
|
45704
|
-
import { join as
|
|
46051
|
+
import { join as join13 } from "node:path";
|
|
45705
46052
|
function getMemoryFilesystemRoot(agentId, homeDir = homedir13()) {
|
|
45706
|
-
return
|
|
46053
|
+
return join13(homeDir, MEMORY_FS_ROOT, MEMORY_FS_AGENTS_DIR, agentId, MEMORY_FS_MEMORY_DIR);
|
|
45707
46054
|
}
|
|
45708
46055
|
function getMemorySystemDir(agentId, homeDir = homedir13()) {
|
|
45709
|
-
return
|
|
46056
|
+
return join13(getMemoryFilesystemRoot(agentId, homeDir), MEMORY_SYSTEM_DIR);
|
|
45710
46057
|
}
|
|
45711
46058
|
function ensureMemoryFilesystemDirs(agentId, homeDir = homedir13()) {
|
|
45712
46059
|
const root = getMemoryFilesystemRoot(agentId, homeDir);
|
|
45713
46060
|
const systemDir = getMemorySystemDir(agentId, homeDir);
|
|
45714
|
-
if (!
|
|
45715
|
-
|
|
46061
|
+
if (!existsSync12(root)) {
|
|
46062
|
+
mkdirSync10(root, { recursive: true });
|
|
45716
46063
|
}
|
|
45717
|
-
if (!
|
|
45718
|
-
|
|
46064
|
+
if (!existsSync12(systemDir)) {
|
|
46065
|
+
mkdirSync10(systemDir, { recursive: true });
|
|
45719
46066
|
}
|
|
45720
46067
|
}
|
|
45721
46068
|
function labelFromRelativePath(relativePath) {
|
|
@@ -45883,6 +46230,10 @@ async function applyMemfsFlags(agentId, memfsFlag, noMemfsFlag, options) {
|
|
|
45883
46230
|
const result = await pullMemory2(agentId);
|
|
45884
46231
|
pullSummary = result.summary;
|
|
45885
46232
|
}
|
|
46233
|
+
const { initSecretsFromServer: initSecretsFromServer2 } = await init_secretsStore().then(() => exports_secretsStore);
|
|
46234
|
+
try {
|
|
46235
|
+
await initSecretsFromServer2(agentId, getMemoryFilesystemRoot(agentId));
|
|
46236
|
+
} catch {}
|
|
45886
46237
|
}
|
|
45887
46238
|
const action = memfsFlag || shouldAutoEnableFromTag ? "enabled" : noMemfsFlag ? "disabled" : "unchanged";
|
|
45888
46239
|
return {
|
|
@@ -45922,7 +46273,7 @@ __export(exports_shellEnv, {
|
|
|
45922
46273
|
getShellEnv: () => getShellEnv,
|
|
45923
46274
|
ensureLettaShimDir: () => ensureLettaShimDir
|
|
45924
46275
|
});
|
|
45925
|
-
import { mkdirSync as
|
|
46276
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync7 } from "node:fs";
|
|
45926
46277
|
import { createRequire as createRequire2 } from "node:module";
|
|
45927
46278
|
import { tmpdir } from "node:os";
|
|
45928
46279
|
import * as path5 from "node:path";
|
|
@@ -45995,19 +46346,19 @@ function ensureLettaShimDir(invocation) {
|
|
|
45995
46346
|
if (!invocation.command)
|
|
45996
46347
|
return null;
|
|
45997
46348
|
const shimDir = path5.join(tmpdir(), "letta-code-shell-shim");
|
|
45998
|
-
|
|
46349
|
+
mkdirSync11(shimDir, { recursive: true });
|
|
45999
46350
|
if (process.platform === "win32") {
|
|
46000
46351
|
const cmdPath = path5.join(shimDir, "letta.cmd");
|
|
46001
46352
|
const quotedCommand = `"${invocation.command.replaceAll('"', '""')}"`;
|
|
46002
46353
|
const quotedArgs = invocation.args.map((arg) => `"${arg.replaceAll('"', '""')}"`).join(" ");
|
|
46003
|
-
|
|
46354
|
+
writeFileSync7(cmdPath, `@echo off\r
|
|
46004
46355
|
${quotedCommand} ${quotedArgs} %*\r
|
|
46005
46356
|
`);
|
|
46006
46357
|
return shimDir;
|
|
46007
46358
|
}
|
|
46008
46359
|
const shimPath = path5.join(shimDir, "letta");
|
|
46009
46360
|
const commandWithArgs = [invocation.command, ...invocation.args].map(shellEscape).join(" ");
|
|
46010
|
-
|
|
46361
|
+
writeFileSync7(shimPath, `#!/bin/sh
|
|
46011
46362
|
exec ${commandWithArgs} "$@"
|
|
46012
46363
|
`, {
|
|
46013
46364
|
mode: 493
|
|
@@ -47548,7 +47899,7 @@ var init_LS2 = __esm(() => {
|
|
|
47548
47899
|
|
|
47549
47900
|
// src/tools/impl/LS.ts
|
|
47550
47901
|
import { readdir as readdir2, stat } from "node:fs/promises";
|
|
47551
|
-
import { join as
|
|
47902
|
+
import { join as join17, resolve as resolve11 } from "node:path";
|
|
47552
47903
|
async function ls(args) {
|
|
47553
47904
|
validateRequiredParams(args, ["path"], "LS");
|
|
47554
47905
|
validateParamTypes(args, LS_default2, "LS");
|
|
@@ -47558,7 +47909,7 @@ async function ls(args) {
|
|
|
47558
47909
|
const items = await readdir2(dirPath);
|
|
47559
47910
|
const filteredItems = items.filter((item) => !ignore.some((pattern) => import_picomatch2.default.isMatch(item, pattern)));
|
|
47560
47911
|
const fileInfos = await Promise.all(filteredItems.map(async (item) => {
|
|
47561
|
-
const fullPath =
|
|
47912
|
+
const fullPath = join17(dirPath, item);
|
|
47562
47913
|
try {
|
|
47563
47914
|
const stats = await stat(fullPath);
|
|
47564
47915
|
return {
|
|
@@ -47910,7 +48261,7 @@ var init_runtime = () => {};
|
|
|
47910
48261
|
|
|
47911
48262
|
// src/tools/impl/Memory.ts
|
|
47912
48263
|
import { execFile as execFileCb2 } from "node:child_process";
|
|
47913
|
-
import { existsSync as
|
|
48264
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
47914
48265
|
import {
|
|
47915
48266
|
mkdir as mkdir2,
|
|
47916
48267
|
readFile as readFile3,
|
|
@@ -47921,7 +48272,7 @@ import {
|
|
|
47921
48272
|
writeFile as writeFile2
|
|
47922
48273
|
} from "node:fs/promises";
|
|
47923
48274
|
import { homedir as homedir15 } from "node:os";
|
|
47924
|
-
import { dirname as
|
|
48275
|
+
import { dirname as dirname6, isAbsolute as isAbsolute8, relative as relative5, resolve as resolve12 } from "node:path";
|
|
47925
48276
|
import { promisify as promisify9 } from "node:util";
|
|
47926
48277
|
async function getAgentIdentity() {
|
|
47927
48278
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
@@ -47963,14 +48314,14 @@ async function memory(args) {
|
|
|
47963
48314
|
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
47964
48315
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
47965
48316
|
const relPath = toRepoRelative(memoryDir, filePath);
|
|
47966
|
-
if (
|
|
48317
|
+
if (existsSync14(filePath)) {
|
|
47967
48318
|
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
47968
48319
|
}
|
|
47969
48320
|
const body = args.file_text ?? "";
|
|
47970
48321
|
const rendered = renderMemoryFile({
|
|
47971
48322
|
description
|
|
47972
48323
|
}, body);
|
|
47973
|
-
await mkdir2(
|
|
48324
|
+
await mkdir2(dirname6(filePath), { recursive: true });
|
|
47974
48325
|
await writeFile2(filePath, rendered, "utf8");
|
|
47975
48326
|
affectedPaths = [relPath];
|
|
47976
48327
|
} else if (command === "str_replace") {
|
|
@@ -48015,7 +48366,7 @@ async function memory(args) {
|
|
|
48015
48366
|
const pathArg = requireString(args.path, "path", "delete");
|
|
48016
48367
|
const label = normalizeMemoryLabel(memoryDir, pathArg, "path");
|
|
48017
48368
|
const targetPath = resolveMemoryPath(memoryDir, label);
|
|
48018
|
-
if (
|
|
48369
|
+
if (existsSync14(targetPath) && (await stat2(targetPath)).isDirectory()) {
|
|
48019
48370
|
const relPath = toRepoRelative(memoryDir, targetPath);
|
|
48020
48371
|
await rm(targetPath, { recursive: true, force: false });
|
|
48021
48372
|
affectedPaths = [relPath];
|
|
@@ -48035,11 +48386,11 @@ async function memory(args) {
|
|
|
48035
48386
|
const newFilePath = resolveMemoryFilePath(memoryDir, newLabel);
|
|
48036
48387
|
const oldRelPath = toRepoRelative(memoryDir, oldFilePath);
|
|
48037
48388
|
const newRelPath = toRepoRelative(memoryDir, newFilePath);
|
|
48038
|
-
if (
|
|
48389
|
+
if (existsSync14(newFilePath)) {
|
|
48039
48390
|
throw new Error(`memory rename: destination already exists at ${newPathArg}`);
|
|
48040
48391
|
}
|
|
48041
48392
|
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
48042
|
-
await mkdir2(
|
|
48393
|
+
await mkdir2(dirname6(newFilePath), { recursive: true });
|
|
48043
48394
|
await rename(oldFilePath, newFilePath);
|
|
48044
48395
|
affectedPaths = [oldRelPath, newRelPath];
|
|
48045
48396
|
} else if (command === "update_description") {
|
|
@@ -48092,10 +48443,10 @@ function resolveMemoryDir() {
|
|
|
48092
48443
|
throw new Error("memory: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
48093
48444
|
}
|
|
48094
48445
|
function ensureMemoryRepo(memoryDir) {
|
|
48095
|
-
if (!
|
|
48446
|
+
if (!existsSync14(memoryDir)) {
|
|
48096
48447
|
throw new Error(`memory: memory directory does not exist: ${memoryDir}`);
|
|
48097
48448
|
}
|
|
48098
|
-
if (!
|
|
48449
|
+
if (!existsSync14(resolve12(memoryDir, ".git"))) {
|
|
48099
48450
|
throw new Error(`memory: ${memoryDir} is not a git repository. This tool requires a git-backed memory filesystem.`);
|
|
48100
48451
|
}
|
|
48101
48452
|
}
|
|
@@ -48325,7 +48676,7 @@ var init_Memory2 = __esm(async () => {
|
|
|
48325
48676
|
|
|
48326
48677
|
// src/tools/impl/MemoryApplyPatch.ts
|
|
48327
48678
|
import { execFile as execFileCb3 } from "node:child_process";
|
|
48328
|
-
import { existsSync as
|
|
48679
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
48329
48680
|
import {
|
|
48330
48681
|
access,
|
|
48331
48682
|
mkdir as mkdir3,
|
|
@@ -48336,7 +48687,7 @@ import {
|
|
|
48336
48687
|
writeFile as writeFile3
|
|
48337
48688
|
} from "node:fs/promises";
|
|
48338
48689
|
import { homedir as homedir16 } from "node:os";
|
|
48339
|
-
import { dirname as
|
|
48690
|
+
import { dirname as dirname7, isAbsolute as isAbsolute9, relative as relative6, resolve as resolve13 } from "node:path";
|
|
48340
48691
|
import { promisify as promisify10 } from "node:util";
|
|
48341
48692
|
async function getAgentIdentity2() {
|
|
48342
48693
|
const envAgentId = (process.env.AGENT_ID || process.env.LETTA_AGENT_ID || "").trim();
|
|
@@ -48449,7 +48800,7 @@ async function memory_apply_patch(args) {
|
|
|
48449
48800
|
}
|
|
48450
48801
|
}
|
|
48451
48802
|
for (const [absPath, content] of pendingWrites.entries()) {
|
|
48452
|
-
await mkdir3(
|
|
48803
|
+
await mkdir3(dirname7(absPath), { recursive: true });
|
|
48453
48804
|
await writeFile3(absPath, content, "utf8");
|
|
48454
48805
|
}
|
|
48455
48806
|
for (const absPath of pendingDeletes) {
|
|
@@ -48628,10 +48979,10 @@ function resolveMemoryDir2() {
|
|
|
48628
48979
|
throw new Error("memory_apply_patch: unable to resolve memory directory. Ensure MEMORY_DIR (or AGENT_ID) is available.");
|
|
48629
48980
|
}
|
|
48630
48981
|
function ensureMemoryRepo2(memoryDir) {
|
|
48631
|
-
if (!
|
|
48982
|
+
if (!existsSync15(memoryDir)) {
|
|
48632
48983
|
throw new Error(`memory_apply_patch: memory directory does not exist: ${memoryDir}`);
|
|
48633
48984
|
}
|
|
48634
|
-
if (!
|
|
48985
|
+
if (!existsSync15(resolve13(memoryDir, ".git"))) {
|
|
48635
48986
|
throw new Error(`memory_apply_patch: ${memoryDir} is not a git repository. This tool requires a git-backed memory filesystem.`);
|
|
48636
48987
|
}
|
|
48637
48988
|
}
|
|
@@ -48984,12 +49335,12 @@ __export(exports_imageResize_magick, {
|
|
|
48984
49335
|
MAX_IMAGE_BYTES: () => MAX_IMAGE_BYTES
|
|
48985
49336
|
});
|
|
48986
49337
|
import { execSync } from "node:child_process";
|
|
48987
|
-
import { readFileSync as readFileSync7, unlinkSync as unlinkSync4, writeFileSync as
|
|
49338
|
+
import { readFileSync as readFileSync7, unlinkSync as unlinkSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
48988
49339
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
48989
|
-
import { join as
|
|
49340
|
+
import { join as join18 } from "node:path";
|
|
48990
49341
|
async function getImageDimensions(buffer) {
|
|
48991
|
-
const tempInput =
|
|
48992
|
-
|
|
49342
|
+
const tempInput = join18(tmpdir2(), `image-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
|
|
49343
|
+
writeFileSync9(tempInput, buffer);
|
|
48993
49344
|
try {
|
|
48994
49345
|
const output = execSync(`magick identify -format "%w %h %m" "${tempInput}"`, {
|
|
48995
49346
|
encoding: "utf-8"
|
|
@@ -49011,12 +49362,12 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
|
|
|
49011
49362
|
if (buffer.length <= MAX_IMAGE_BYTES) {
|
|
49012
49363
|
return null;
|
|
49013
49364
|
}
|
|
49014
|
-
const tempInput =
|
|
49015
|
-
|
|
49365
|
+
const tempInput = join18(tmpdir2(), `compress-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
|
|
49366
|
+
writeFileSync9(tempInput, buffer);
|
|
49016
49367
|
try {
|
|
49017
49368
|
const qualities = [85, 70, 55, 40];
|
|
49018
49369
|
for (const quality of qualities) {
|
|
49019
|
-
const tempOutput =
|
|
49370
|
+
const tempOutput = join18(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
|
|
49020
49371
|
try {
|
|
49021
49372
|
execSync(`magick "${tempInput}" -quality ${quality} "${tempOutput}"`, {
|
|
49022
49373
|
stdio: "ignore"
|
|
@@ -49042,7 +49393,7 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
|
|
|
49042
49393
|
for (const scale of scales) {
|
|
49043
49394
|
const scaledWidth = Math.floor(currentWidth * scale);
|
|
49044
49395
|
const scaledHeight = Math.floor(currentHeight * scale);
|
|
49045
|
-
const tempOutput =
|
|
49396
|
+
const tempOutput = join18(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
|
|
49046
49397
|
try {
|
|
49047
49398
|
execSync(`magick "${tempInput}" -resize ${scaledWidth}x${scaledHeight} -quality 70 "${tempOutput}"`, {
|
|
49048
49399
|
stdio: "ignore"
|
|
@@ -49086,11 +49437,11 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
|
|
|
49086
49437
|
resized: false
|
|
49087
49438
|
};
|
|
49088
49439
|
}
|
|
49089
|
-
const tempInput =
|
|
49090
|
-
|
|
49440
|
+
const tempInput = join18(tmpdir2(), `resize-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
|
|
49441
|
+
writeFileSync9(tempInput, buffer);
|
|
49091
49442
|
try {
|
|
49092
49443
|
if (needsResize) {
|
|
49093
|
-
const tempOutput2 =
|
|
49444
|
+
const tempOutput2 = join18(tmpdir2(), `resize-output-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
49094
49445
|
let outputBuffer2;
|
|
49095
49446
|
let outputMediaType;
|
|
49096
49447
|
if (format2 === "jpeg" || format2 === "jpg") {
|
|
@@ -49121,7 +49472,7 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
|
|
|
49121
49472
|
resized: true
|
|
49122
49473
|
};
|
|
49123
49474
|
}
|
|
49124
|
-
const tempOutput =
|
|
49475
|
+
const tempOutput = join18(tmpdir2(), `convert-output-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
|
|
49125
49476
|
execSync(`magick "${tempInput}" "${tempOutput}"`, {
|
|
49126
49477
|
stdio: "ignore"
|
|
49127
49478
|
});
|
|
@@ -61282,8 +61633,8 @@ var init_ignore = __esm(() => {
|
|
|
61282
61633
|
// node_modules/glob/dist/esm/processor.js
|
|
61283
61634
|
class HasWalkedCache {
|
|
61284
61635
|
store;
|
|
61285
|
-
constructor(
|
|
61286
|
-
this.store =
|
|
61636
|
+
constructor(store2 = new Map) {
|
|
61637
|
+
this.store = store2;
|
|
61287
61638
|
}
|
|
61288
61639
|
copy() {
|
|
61289
61640
|
return new HasWalkedCache(new Map(this.store));
|
|
@@ -62184,7 +62535,7 @@ var init_ReplaceGemini2 = __esm(() => {
|
|
|
62184
62535
|
});
|
|
62185
62536
|
|
|
62186
62537
|
// src/tools/impl/Shell.ts
|
|
62187
|
-
import { existsSync as
|
|
62538
|
+
import { existsSync as existsSync16, statSync as statSync4 } from "node:fs";
|
|
62188
62539
|
import * as path16 from "node:path";
|
|
62189
62540
|
async function runProcess(context3) {
|
|
62190
62541
|
const { stdout, stderr, exitCode } = await spawnWithLauncher(context3.command, {
|
|
@@ -62272,7 +62623,7 @@ function arraysEqual(a, b) {
|
|
|
62272
62623
|
}
|
|
62273
62624
|
function isUsableDirectory(candidate) {
|
|
62274
62625
|
try {
|
|
62275
|
-
return
|
|
62626
|
+
return existsSync16(candidate) && statSync4(candidate).isDirectory();
|
|
62276
62627
|
} catch {
|
|
62277
62628
|
return false;
|
|
62278
62629
|
}
|
|
@@ -62423,22 +62774,22 @@ __export(exports_skills, {
|
|
|
62423
62774
|
SKILLS_DIR: () => SKILLS_DIR,
|
|
62424
62775
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
|
|
62425
62776
|
});
|
|
62426
|
-
import { existsSync as
|
|
62777
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
62427
62778
|
import { readdir as readdir4, readFile as readFile5, realpath as realpath2, stat as stat4 } from "node:fs/promises";
|
|
62428
|
-
import { dirname as
|
|
62779
|
+
import { dirname as dirname8, join as join19 } from "node:path";
|
|
62429
62780
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
62430
62781
|
function getBundledSkillsPath() {
|
|
62431
|
-
const thisDir =
|
|
62782
|
+
const thisDir = dirname8(fileURLToPath7(import.meta.url));
|
|
62432
62783
|
if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
|
|
62433
|
-
return
|
|
62784
|
+
return join19(thisDir, "../skills/builtin");
|
|
62434
62785
|
}
|
|
62435
|
-
return
|
|
62786
|
+
return join19(thisDir, "skills");
|
|
62436
62787
|
}
|
|
62437
62788
|
function compareSkills(a, b) {
|
|
62438
62789
|
return a.id.localeCompare(b.id) || a.source.localeCompare(b.source) || a.path.localeCompare(b.path);
|
|
62439
62790
|
}
|
|
62440
62791
|
function getAgentSkillsDir(agentId) {
|
|
62441
|
-
return
|
|
62792
|
+
return join19(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
|
|
62442
62793
|
}
|
|
62443
62794
|
async function getBundledSkills() {
|
|
62444
62795
|
const bundledPath = getBundledSkillsPath();
|
|
@@ -62447,7 +62798,7 @@ async function getBundledSkills() {
|
|
|
62447
62798
|
}
|
|
62448
62799
|
async function discoverSkillsFromDir(skillsPath, source) {
|
|
62449
62800
|
const errors = [];
|
|
62450
|
-
if (!
|
|
62801
|
+
if (!existsSync17(skillsPath)) {
|
|
62451
62802
|
return { skills: [], errors: [] };
|
|
62452
62803
|
}
|
|
62453
62804
|
const skills = [];
|
|
@@ -62461,7 +62812,7 @@ async function discoverSkillsFromDir(skillsPath, source) {
|
|
|
62461
62812
|
}
|
|
62462
62813
|
return { skills, errors };
|
|
62463
62814
|
}
|
|
62464
|
-
async function discoverSkills(projectSkillsPath =
|
|
62815
|
+
async function discoverSkills(projectSkillsPath = join19(process.cwd(), SKILLS_DIR), agentId, options) {
|
|
62465
62816
|
const allErrors = [];
|
|
62466
62817
|
const skillsById = new Map;
|
|
62467
62818
|
const sourceSet = new Set(options?.sources ?? ALL_SKILL_SOURCES);
|
|
@@ -62516,7 +62867,7 @@ async function findSkillFiles(currentPath, rootPath, skills, errors, source, vis
|
|
|
62516
62867
|
try {
|
|
62517
62868
|
const entries = await readdir4(currentPath, { withFileTypes: true });
|
|
62518
62869
|
for (const entry of entries) {
|
|
62519
|
-
const fullPath =
|
|
62870
|
+
const fullPath = join19(currentPath, entry.name);
|
|
62520
62871
|
try {
|
|
62521
62872
|
let isDirectory = entry.isDirectory();
|
|
62522
62873
|
let isFile = entry.isFile();
|
|
@@ -62605,7 +62956,7 @@ ${lines.join(`
|
|
|
62605
62956
|
var SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
|
|
62606
62957
|
var init_skills = __esm(() => {
|
|
62607
62958
|
init_skillSources();
|
|
62608
|
-
GLOBAL_SKILLS_DIR =
|
|
62959
|
+
GLOBAL_SKILLS_DIR = join19(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
|
|
62609
62960
|
});
|
|
62610
62961
|
|
|
62611
62962
|
// src/tools/impl/skillContentRegistry.ts
|
|
@@ -62630,10 +62981,10 @@ var init_skillContentRegistry = __esm(() => {
|
|
|
62630
62981
|
// src/tools/impl/Skill.ts
|
|
62631
62982
|
import { readdirSync as readdirSync7 } from "node:fs";
|
|
62632
62983
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
62633
|
-
import { dirname as
|
|
62984
|
+
import { dirname as dirname9, join as join20 } from "node:path";
|
|
62634
62985
|
function hasAdditionalFiles(skillMdPath) {
|
|
62635
62986
|
try {
|
|
62636
|
-
const skillDir =
|
|
62987
|
+
const skillDir = dirname9(skillMdPath);
|
|
62637
62988
|
const entries = readdirSync7(skillDir);
|
|
62638
62989
|
return entries.some((e) => e.toUpperCase() !== "SKILL.MD");
|
|
62639
62990
|
} catch {
|
|
@@ -62641,19 +62992,19 @@ function hasAdditionalFiles(skillMdPath) {
|
|
|
62641
62992
|
}
|
|
62642
62993
|
}
|
|
62643
62994
|
async function readSkillContent(skillId, skillsDir, agentId) {
|
|
62644
|
-
const projectSkillPath =
|
|
62995
|
+
const projectSkillPath = join20(skillsDir, skillId, "SKILL.md");
|
|
62645
62996
|
try {
|
|
62646
62997
|
const content = await readFile6(projectSkillPath, "utf-8");
|
|
62647
62998
|
return { content, path: projectSkillPath };
|
|
62648
62999
|
} catch {}
|
|
62649
63000
|
if (agentId) {
|
|
62650
|
-
const agentSkillPath =
|
|
63001
|
+
const agentSkillPath = join20(getAgentSkillsDir(agentId), skillId, "SKILL.md");
|
|
62651
63002
|
try {
|
|
62652
63003
|
const content = await readFile6(agentSkillPath, "utf-8");
|
|
62653
63004
|
return { content, path: agentSkillPath };
|
|
62654
63005
|
} catch {}
|
|
62655
63006
|
}
|
|
62656
|
-
const globalSkillPath =
|
|
63007
|
+
const globalSkillPath = join20(GLOBAL_SKILLS_DIR, skillId, "SKILL.md");
|
|
62657
63008
|
try {
|
|
62658
63009
|
const content = await readFile6(globalSkillPath, "utf-8");
|
|
62659
63010
|
return { content, path: globalSkillPath };
|
|
@@ -62667,8 +63018,8 @@ async function readSkillContent(skillId, skillsDir, agentId) {
|
|
|
62667
63018
|
} catch {}
|
|
62668
63019
|
}
|
|
62669
63020
|
try {
|
|
62670
|
-
const bundledSkillsDir =
|
|
62671
|
-
const bundledSkillPath =
|
|
63021
|
+
const bundledSkillsDir = join20(process.cwd(), "skills", "skills");
|
|
63022
|
+
const bundledSkillPath = join20(bundledSkillsDir, skillId, "SKILL.md");
|
|
62672
63023
|
const content = await readFile6(bundledSkillPath, "utf-8");
|
|
62673
63024
|
return { content, path: bundledSkillPath };
|
|
62674
63025
|
} catch {
|
|
@@ -62680,7 +63031,7 @@ async function getResolvedSkillsDir() {
|
|
|
62680
63031
|
if (skillsDir) {
|
|
62681
63032
|
return skillsDir;
|
|
62682
63033
|
}
|
|
62683
|
-
return
|
|
63034
|
+
return join20(process.cwd(), SKILLS_DIR);
|
|
62684
63035
|
}
|
|
62685
63036
|
async function skill(args) {
|
|
62686
63037
|
validateRequiredParams(args, ["skill"], "Skill");
|
|
@@ -62692,7 +63043,7 @@ async function skill(args) {
|
|
|
62692
63043
|
const agentId = getCurrentAgentId();
|
|
62693
63044
|
const skillsDir = await getResolvedSkillsDir();
|
|
62694
63045
|
const { content: skillContent, path: skillPath } = await readSkillContent(skillName, skillsDir, agentId);
|
|
62695
|
-
const skillDir =
|
|
63046
|
+
const skillDir = dirname9(skillPath);
|
|
62696
63047
|
const hasExtras = hasAdditionalFiles(skillPath);
|
|
62697
63048
|
const processedContent = hasExtras ? skillContent.replace(/<SKILL_DIR>/g, skillDir) : skillContent;
|
|
62698
63049
|
const dirHeader = hasExtras ? `# Skill Directory: ${skillDir}
|
|
@@ -62718,174 +63069,6 @@ var init_Skill2 = __esm(() => {
|
|
|
62718
63069
|
init_skillContentRegistry();
|
|
62719
63070
|
});
|
|
62720
63071
|
|
|
62721
|
-
// src/cli/helpers/subagentState.ts
|
|
62722
|
-
function updateSnapshot() {
|
|
62723
|
-
cachedSnapshot = {
|
|
62724
|
-
agents: Array.from(store.agents.values()),
|
|
62725
|
-
expanded: store.expanded
|
|
62726
|
-
};
|
|
62727
|
-
}
|
|
62728
|
-
function notifyListeners() {
|
|
62729
|
-
updateSnapshot();
|
|
62730
|
-
for (const listener of store.listeners) {
|
|
62731
|
-
listener();
|
|
62732
|
-
}
|
|
62733
|
-
}
|
|
62734
|
-
function generateSubagentId() {
|
|
62735
|
-
return `subagent-${Date.now()}-${++subagentCounter}`;
|
|
62736
|
-
}
|
|
62737
|
-
function getSubagentByToolCallId(toolCallId) {
|
|
62738
|
-
for (const agent of store.agents.values()) {
|
|
62739
|
-
if (agent.toolCallId === toolCallId) {
|
|
62740
|
-
return agent;
|
|
62741
|
-
}
|
|
62742
|
-
}
|
|
62743
|
-
return;
|
|
62744
|
-
}
|
|
62745
|
-
function registerSubagent(id, type, description, toolCallId, isBackground, silent) {
|
|
62746
|
-
const displayType = type.charAt(0).toUpperCase() + type.slice(1);
|
|
62747
|
-
const agent = {
|
|
62748
|
-
id,
|
|
62749
|
-
type: displayType,
|
|
62750
|
-
description,
|
|
62751
|
-
status: "pending",
|
|
62752
|
-
agentURL: null,
|
|
62753
|
-
toolCalls: [],
|
|
62754
|
-
maxToolCallsSeen: 0,
|
|
62755
|
-
totalTokens: 0,
|
|
62756
|
-
durationMs: 0,
|
|
62757
|
-
startTime: Date.now(),
|
|
62758
|
-
toolCallId,
|
|
62759
|
-
isBackground,
|
|
62760
|
-
silent
|
|
62761
|
-
};
|
|
62762
|
-
store.agents.set(id, agent);
|
|
62763
|
-
notifyListeners();
|
|
62764
|
-
}
|
|
62765
|
-
function updateSubagent(id, updates) {
|
|
62766
|
-
const agent = store.agents.get(id);
|
|
62767
|
-
if (!agent)
|
|
62768
|
-
return;
|
|
62769
|
-
if (updates.agentURL && agent.status === "pending") {
|
|
62770
|
-
updates.status = "running";
|
|
62771
|
-
}
|
|
62772
|
-
const nextToolCalls = updates.toolCalls ?? agent.toolCalls;
|
|
62773
|
-
const nextMax = Math.max(agent.maxToolCallsSeen, nextToolCalls.length, updates.maxToolCallsSeen ?? 0);
|
|
62774
|
-
const keys = Object.keys(updates);
|
|
62775
|
-
const isNoop = keys.every((k) => agent[k] === updates[k]) && nextMax === agent.maxToolCallsSeen;
|
|
62776
|
-
if (isNoop)
|
|
62777
|
-
return;
|
|
62778
|
-
const updatedAgent = { ...agent, ...updates, maxToolCallsSeen: nextMax };
|
|
62779
|
-
store.agents.set(id, updatedAgent);
|
|
62780
|
-
notifyListeners();
|
|
62781
|
-
}
|
|
62782
|
-
function addToolCall(subagentId, toolCallId, toolName, toolArgs) {
|
|
62783
|
-
const agent = store.agents.get(subagentId);
|
|
62784
|
-
if (!agent)
|
|
62785
|
-
return;
|
|
62786
|
-
if (agent.toolCalls.some((tc) => tc.id === toolCallId))
|
|
62787
|
-
return;
|
|
62788
|
-
const updatedAgent = {
|
|
62789
|
-
...agent,
|
|
62790
|
-
toolCalls: [
|
|
62791
|
-
...agent.toolCalls,
|
|
62792
|
-
{ id: toolCallId, name: toolName, args: toolArgs }
|
|
62793
|
-
],
|
|
62794
|
-
maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length + 1)
|
|
62795
|
-
};
|
|
62796
|
-
store.agents.set(subagentId, updatedAgent);
|
|
62797
|
-
notifyListeners();
|
|
62798
|
-
}
|
|
62799
|
-
function completeSubagent(id, result) {
|
|
62800
|
-
const agent = store.agents.get(id);
|
|
62801
|
-
if (!agent)
|
|
62802
|
-
return;
|
|
62803
|
-
const updatedAgent = {
|
|
62804
|
-
...agent,
|
|
62805
|
-
status: result.success ? "completed" : "error",
|
|
62806
|
-
error: result.error,
|
|
62807
|
-
durationMs: Date.now() - agent.startTime,
|
|
62808
|
-
totalTokens: result.totalTokens ?? agent.totalTokens,
|
|
62809
|
-
maxToolCallsSeen: Math.max(agent.maxToolCallsSeen, agent.toolCalls.length)
|
|
62810
|
-
};
|
|
62811
|
-
store.agents.set(id, updatedAgent);
|
|
62812
|
-
notifyListeners();
|
|
62813
|
-
}
|
|
62814
|
-
function getSubagentToolCount(agent) {
|
|
62815
|
-
return Math.max(agent.toolCalls.length, agent.maxToolCallsSeen);
|
|
62816
|
-
}
|
|
62817
|
-
function toggleExpanded() {
|
|
62818
|
-
store.expanded = !store.expanded;
|
|
62819
|
-
notifyListeners();
|
|
62820
|
-
}
|
|
62821
|
-
function getSubagents() {
|
|
62822
|
-
return Array.from(store.agents.values());
|
|
62823
|
-
}
|
|
62824
|
-
function getActiveBackgroundAgents() {
|
|
62825
|
-
return Array.from(store.agents.values()).filter((a) => a.silent === true && (a.status === "pending" || a.status === "running"));
|
|
62826
|
-
}
|
|
62827
|
-
function clearCompletedSubagents() {
|
|
62828
|
-
for (const [id, agent] of store.agents.entries()) {
|
|
62829
|
-
if (agent.status === "completed" || agent.status === "error") {
|
|
62830
|
-
store.agents.delete(id);
|
|
62831
|
-
}
|
|
62832
|
-
}
|
|
62833
|
-
notifyListeners();
|
|
62834
|
-
}
|
|
62835
|
-
function clearSubagentsByIds(ids) {
|
|
62836
|
-
for (const id of ids) {
|
|
62837
|
-
store.agents.delete(id);
|
|
62838
|
-
}
|
|
62839
|
-
notifyListeners();
|
|
62840
|
-
}
|
|
62841
|
-
function hasActiveSubagents() {
|
|
62842
|
-
for (const agent of store.agents.values()) {
|
|
62843
|
-
if (agent.status === "pending" || agent.status === "running") {
|
|
62844
|
-
return true;
|
|
62845
|
-
}
|
|
62846
|
-
}
|
|
62847
|
-
return false;
|
|
62848
|
-
}
|
|
62849
|
-
function interruptActiveSubagents(errorMessage) {
|
|
62850
|
-
let anyInterrupted = false;
|
|
62851
|
-
for (const [id, agent] of store.agents.entries()) {
|
|
62852
|
-
if (agent.status === "pending" || agent.status === "running") {
|
|
62853
|
-
const updatedAgent = {
|
|
62854
|
-
...agent,
|
|
62855
|
-
status: "error",
|
|
62856
|
-
error: errorMessage,
|
|
62857
|
-
durationMs: Date.now() - agent.startTime
|
|
62858
|
-
};
|
|
62859
|
-
store.agents.set(id, updatedAgent);
|
|
62860
|
-
anyInterrupted = true;
|
|
62861
|
-
}
|
|
62862
|
-
}
|
|
62863
|
-
if (anyInterrupted) {
|
|
62864
|
-
notifyListeners();
|
|
62865
|
-
}
|
|
62866
|
-
}
|
|
62867
|
-
function subscribe2(listener) {
|
|
62868
|
-
store.listeners.add(listener);
|
|
62869
|
-
return () => {
|
|
62870
|
-
store.listeners.delete(listener);
|
|
62871
|
-
};
|
|
62872
|
-
}
|
|
62873
|
-
function getSnapshot2() {
|
|
62874
|
-
return cachedSnapshot;
|
|
62875
|
-
}
|
|
62876
|
-
var store, cachedSnapshot, subagentCounter = 0;
|
|
62877
|
-
var init_subagentState = __esm(() => {
|
|
62878
|
-
store = {
|
|
62879
|
-
agents: new Map,
|
|
62880
|
-
expanded: false,
|
|
62881
|
-
listeners: new Set
|
|
62882
|
-
};
|
|
62883
|
-
cachedSnapshot = {
|
|
62884
|
-
agents: [],
|
|
62885
|
-
expanded: false
|
|
62886
|
-
};
|
|
62887
|
-
});
|
|
62888
|
-
|
|
62889
63072
|
// src/permissions/canonical.ts
|
|
62890
63073
|
function canonicalToolName(toolName) {
|
|
62891
63074
|
if (SHELL_TOOL_NAMES.has(toolName))
|
|
@@ -63279,6 +63462,8 @@ function processStreamEvent(line, state, subagentId) {
|
|
|
63279
63462
|
case "message":
|
|
63280
63463
|
if (event.message_type === "approval_request_message") {
|
|
63281
63464
|
handleApprovalRequestEvent(event, state);
|
|
63465
|
+
} else {
|
|
63466
|
+
emitStreamEvent(subagentId, event);
|
|
63282
63467
|
}
|
|
63283
63468
|
break;
|
|
63284
63469
|
case "auto_approval":
|
|
@@ -63632,31 +63817,6 @@ var init_manager2 = __esm(async () => {
|
|
|
63632
63817
|
};
|
|
63633
63818
|
});
|
|
63634
63819
|
|
|
63635
|
-
// src/cli/helpers/messageQueueBridge.ts
|
|
63636
|
-
function setMessageQueueAdder(fn) {
|
|
63637
|
-
queueAdder = fn;
|
|
63638
|
-
if (queueAdder && pendingMessages.length > 0) {
|
|
63639
|
-
for (const message of pendingMessages) {
|
|
63640
|
-
queueAdder(message);
|
|
63641
|
-
}
|
|
63642
|
-
pendingMessages.length = 0;
|
|
63643
|
-
}
|
|
63644
|
-
}
|
|
63645
|
-
function addToMessageQueue(message) {
|
|
63646
|
-
if (queueAdder) {
|
|
63647
|
-
queueAdder(message);
|
|
63648
|
-
return;
|
|
63649
|
-
}
|
|
63650
|
-
if (pendingMessages.length >= MAX_PENDING_MESSAGES) {
|
|
63651
|
-
pendingMessages.shift();
|
|
63652
|
-
}
|
|
63653
|
-
pendingMessages.push(message);
|
|
63654
|
-
}
|
|
63655
|
-
var queueAdder = null, pendingMessages, MAX_PENDING_MESSAGES = 10;
|
|
63656
|
-
var init_messageQueueBridge = __esm(() => {
|
|
63657
|
-
pendingMessages = [];
|
|
63658
|
-
});
|
|
63659
|
-
|
|
63660
63820
|
// src/cli/helpers/taskNotifications.ts
|
|
63661
63821
|
function escapeXml(str) {
|
|
63662
63822
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -63737,11 +63897,13 @@ __export(exports_Task, {
|
|
|
63737
63897
|
task: () => task,
|
|
63738
63898
|
spawnBackgroundSubagentTask: () => spawnBackgroundSubagentTask
|
|
63739
63899
|
});
|
|
63740
|
-
function buildTaskResultHeader(subagentType, result) {
|
|
63900
|
+
function buildTaskResultHeader(subagentType, subagentId, result, status) {
|
|
63741
63901
|
return [
|
|
63742
63902
|
`subagent_type=${subagentType}`,
|
|
63743
|
-
|
|
63744
|
-
|
|
63903
|
+
`subagent_id=${subagentId}`,
|
|
63904
|
+
status ? `subagent_status=${status}` : undefined,
|
|
63905
|
+
result?.agentId ? `agent_id=${result.agentId}` : undefined,
|
|
63906
|
+
result?.conversationId ? `conversation_id=${result.conversationId}` : undefined
|
|
63745
63907
|
].filter(Boolean).join(" ");
|
|
63746
63908
|
}
|
|
63747
63909
|
function writeTaskTranscriptStart(outputFile, description, subagentType) {
|
|
@@ -63760,7 +63922,9 @@ ${result.report}
|
|
|
63760
63922
|
`);
|
|
63761
63923
|
return;
|
|
63762
63924
|
}
|
|
63763
|
-
appendToOutputFile(outputFile,
|
|
63925
|
+
appendToOutputFile(outputFile, `${header ? `${header}
|
|
63926
|
+
|
|
63927
|
+
` : ""}[error] ${result.error || "Subagent execution failed"}
|
|
63764
63928
|
|
|
63765
63929
|
[Task failed]
|
|
63766
63930
|
`);
|
|
@@ -63800,6 +63964,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
63800
63964
|
existingAgentId,
|
|
63801
63965
|
existingConversationId,
|
|
63802
63966
|
maxTurns,
|
|
63967
|
+
parentScope,
|
|
63803
63968
|
silentCompletion,
|
|
63804
63969
|
onComplete,
|
|
63805
63970
|
deps
|
|
@@ -63834,7 +63999,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
63834
63999
|
if (result.error) {
|
|
63835
64000
|
bgTask.error = result.error;
|
|
63836
64001
|
}
|
|
63837
|
-
const header = buildTaskResultHeader(subagentType, result);
|
|
64002
|
+
const header = buildTaskResultHeader(subagentType, subagentId, result, result.success ? "success" : "error");
|
|
63838
64003
|
writeTaskTranscriptResult(outputFile, result, header);
|
|
63839
64004
|
if (result.success) {
|
|
63840
64005
|
bgTask.output.push(result.report || "");
|
|
@@ -63857,7 +64022,9 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
63857
64022
|
const durationMs = Math.max(0, Date.now() - bgTask.startTime.getTime());
|
|
63858
64023
|
const fullResult = result.success ? `${header}
|
|
63859
64024
|
|
|
63860
|
-
${result.report || ""}` :
|
|
64025
|
+
${result.report || ""}` : `${header}
|
|
64026
|
+
|
|
64027
|
+
Error: ${result.error || "Subagent execution failed"}`;
|
|
63861
64028
|
const userCwd = process.env.USER_CWD || process.cwd();
|
|
63862
64029
|
const { content: truncatedResult } = truncateByChars(fullResult, LIMITS.TASK_OUTPUT_CHARS, "Task", { workingDirectory: userCwd, toolName: "Task" });
|
|
63863
64030
|
const notificationXml = formatTaskNotificationFn({
|
|
@@ -63874,7 +64041,9 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
|
|
|
63874
64041
|
});
|
|
63875
64042
|
addToMessageQueueFn({
|
|
63876
64043
|
kind: "task_notification",
|
|
63877
|
-
text: notificationXml
|
|
64044
|
+
text: notificationXml,
|
|
64045
|
+
agentId: parentScope?.agentId,
|
|
64046
|
+
conversationId: parentScope?.conversationId
|
|
63878
64047
|
});
|
|
63879
64048
|
}
|
|
63880
64049
|
runSubagentStopHooksFn(subagentType, subagentId, result.success, result.error, result.agentId, result.conversationId).catch(() => {});
|
|
@@ -63896,11 +64065,17 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
|
|
|
63896
64065
|
const subagentSnapshot = getSubagentSnapshotFn();
|
|
63897
64066
|
const subagentEntry = subagentSnapshot.agents.find((agent) => agent.id === subagentId);
|
|
63898
64067
|
const durationMs = Math.max(0, Date.now() - bgTask.startTime.getTime());
|
|
64068
|
+
const header = buildTaskResultHeader(subagentType, subagentId, {
|
|
64069
|
+
agentId: existingAgentId ?? "",
|
|
64070
|
+
conversationId: existingConversationId
|
|
64071
|
+
}, "error");
|
|
63899
64072
|
const notificationXml = formatTaskNotificationFn({
|
|
63900
64073
|
taskId,
|
|
63901
64074
|
status: "failed",
|
|
63902
64075
|
summary: `Agent "${description}" failed`,
|
|
63903
|
-
result:
|
|
64076
|
+
result: `${header}
|
|
64077
|
+
|
|
64078
|
+
Error: ${errorMessage}`,
|
|
63904
64079
|
outputFile,
|
|
63905
64080
|
usage: {
|
|
63906
64081
|
toolUses: subagentEntry === undefined ? undefined : getSubagentToolCount(subagentEntry),
|
|
@@ -63909,7 +64084,9 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
|
|
|
63909
64084
|
});
|
|
63910
64085
|
addToMessageQueueFn({
|
|
63911
64086
|
kind: "task_notification",
|
|
63912
|
-
text: notificationXml
|
|
64087
|
+
text: notificationXml,
|
|
64088
|
+
agentId: parentScope?.agentId,
|
|
64089
|
+
conversationId: parentScope?.conversationId
|
|
63913
64090
|
});
|
|
63914
64091
|
}
|
|
63915
64092
|
runSubagentStopHooksFn(subagentType, subagentId, false, errorMessage, existingAgentId, existingConversationId).catch(() => {});
|
|
@@ -63960,7 +64137,8 @@ async function task(args) {
|
|
|
63960
64137
|
toolCallId,
|
|
63961
64138
|
existingAgentId: args.agent_id,
|
|
63962
64139
|
existingConversationId: args.conversation_id,
|
|
63963
|
-
maxTurns: args.max_turns
|
|
64140
|
+
maxTurns: args.max_turns,
|
|
64141
|
+
parentScope: args.parentScope
|
|
63964
64142
|
});
|
|
63965
64143
|
await waitForBackgroundSubagentLink(subagentId2, null, signal);
|
|
63966
64144
|
const linkedAgent = getSnapshot2().agents.find((a) => a.id === subagentId2);
|
|
@@ -63991,11 +64169,14 @@ You will be notified automatically when this task completes — a <task-notifica
|
|
|
63991
64169
|
...result,
|
|
63992
64170
|
error: errorMessage
|
|
63993
64171
|
};
|
|
63994
|
-
|
|
63995
|
-
|
|
64172
|
+
const header2 = buildTaskResultHeader(subagent_type, subagentId, failedResult, "error");
|
|
64173
|
+
writeTaskTranscriptResult(outputFile, failedResult, header2);
|
|
64174
|
+
return `${header2}
|
|
64175
|
+
|
|
64176
|
+
Error: ${errorMessage}
|
|
63996
64177
|
Output file: ${outputFile}`;
|
|
63997
64178
|
}
|
|
63998
|
-
const header = buildTaskResultHeader(subagent_type, result);
|
|
64179
|
+
const header = buildTaskResultHeader(subagent_type, subagentId, result, "success");
|
|
63999
64180
|
const fullOutput = `${header}
|
|
64000
64181
|
|
|
64001
64182
|
${result.report}`;
|
|
@@ -64006,13 +64187,21 @@ ${result.report}`;
|
|
|
64006
64187
|
Output file: ${outputFile}`;
|
|
64007
64188
|
} catch (error) {
|
|
64008
64189
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64190
|
+
const header = buildTaskResultHeader(subagent_type, subagentId, {
|
|
64191
|
+
agentId: args.agent_id ?? "",
|
|
64192
|
+
conversationId: args.conversation_id
|
|
64193
|
+
}, "error");
|
|
64009
64194
|
completeSubagent(subagentId, { success: false, error: errorMessage });
|
|
64010
64195
|
runSubagentStopHooks(subagent_type, subagentId, false, errorMessage, args.agent_id, args.conversation_id).catch(() => {});
|
|
64011
|
-
appendToOutputFile(outputFile,
|
|
64196
|
+
appendToOutputFile(outputFile, `${header}
|
|
64197
|
+
|
|
64198
|
+
[error] ${errorMessage}
|
|
64012
64199
|
|
|
64013
64200
|
[Task failed]
|
|
64014
64201
|
`);
|
|
64015
|
-
return
|
|
64202
|
+
return `${header}
|
|
64203
|
+
|
|
64204
|
+
Error: ${errorMessage}
|
|
64016
64205
|
Output file: ${outputFile}`;
|
|
64017
64206
|
}
|
|
64018
64207
|
}
|
|
@@ -67675,13 +67864,13 @@ __export(exports_loader, {
|
|
|
67675
67864
|
getUserSettingsPaths: () => getUserSettingsPaths
|
|
67676
67865
|
});
|
|
67677
67866
|
import { homedir as homedir17 } from "node:os";
|
|
67678
|
-
import { join as
|
|
67867
|
+
import { join as join21 } from "node:path";
|
|
67679
67868
|
function getUserSettingsPaths(options = {}) {
|
|
67680
67869
|
const homeDir = options.homeDir || homedir17();
|
|
67681
|
-
const xdgConfigHome = options.xdgConfigHome || process.env.XDG_CONFIG_HOME ||
|
|
67870
|
+
const xdgConfigHome = options.xdgConfigHome || process.env.XDG_CONFIG_HOME || join21(homeDir, ".config");
|
|
67682
67871
|
return {
|
|
67683
|
-
canonical:
|
|
67684
|
-
legacy:
|
|
67872
|
+
canonical: join21(homeDir, ".letta", "settings.json"),
|
|
67873
|
+
legacy: join21(xdgConfigHome, "letta", "settings.json")
|
|
67685
67874
|
};
|
|
67686
67875
|
}
|
|
67687
67876
|
async function loadPermissions(workingDirectory = process.cwd()) {
|
|
@@ -67695,8 +67884,8 @@ async function loadPermissions(workingDirectory = process.cwd()) {
|
|
|
67695
67884
|
const sources = [
|
|
67696
67885
|
legacyUserSettingsPath,
|
|
67697
67886
|
userSettingsPath,
|
|
67698
|
-
|
|
67699
|
-
|
|
67887
|
+
join21(workingDirectory, ".letta", "settings.json"),
|
|
67888
|
+
join21(workingDirectory, ".letta", "settings.local.json")
|
|
67700
67889
|
];
|
|
67701
67890
|
for (const settingsPath of sources) {
|
|
67702
67891
|
try {
|
|
@@ -67744,10 +67933,10 @@ async function savePermissionRule(rule, ruleType, scope, workingDirectory = proc
|
|
|
67744
67933
|
settingsPath = getUserSettingsPaths().canonical;
|
|
67745
67934
|
break;
|
|
67746
67935
|
case "project":
|
|
67747
|
-
settingsPath =
|
|
67936
|
+
settingsPath = join21(workingDirectory, ".letta", "settings.json");
|
|
67748
67937
|
break;
|
|
67749
67938
|
case "local":
|
|
67750
|
-
settingsPath =
|
|
67939
|
+
settingsPath = join21(workingDirectory, ".letta", "settings.local.json");
|
|
67751
67940
|
break;
|
|
67752
67941
|
}
|
|
67753
67942
|
let settings = {};
|
|
@@ -67773,7 +67962,7 @@ async function savePermissionRule(rule, ruleType, scope, workingDirectory = proc
|
|
|
67773
67962
|
}
|
|
67774
67963
|
}
|
|
67775
67964
|
async function ensureLocalSettingsIgnored(workingDirectory) {
|
|
67776
|
-
const gitignorePath =
|
|
67965
|
+
const gitignorePath = join21(workingDirectory, ".gitignore");
|
|
67777
67966
|
const pattern = ".letta/settings.local.json";
|
|
67778
67967
|
try {
|
|
67779
67968
|
let content = "";
|
|
@@ -67800,7 +67989,7 @@ __export(exports_analyzer, {
|
|
|
67800
67989
|
analyzeApprovalContext: () => analyzeApprovalContext
|
|
67801
67990
|
});
|
|
67802
67991
|
import { homedir as homedir18 } from "node:os";
|
|
67803
|
-
import { dirname as
|
|
67992
|
+
import { dirname as dirname11, relative as relative8, resolve as resolve22, win32 as win322 } from "node:path";
|
|
67804
67993
|
function normalizeOsPath(path20) {
|
|
67805
67994
|
return path20.replace(/\\/g, "/");
|
|
67806
67995
|
}
|
|
@@ -67826,7 +68015,7 @@ function isPathWithinDirectory(path20, directory) {
|
|
|
67826
68015
|
return !relativePath.startsWith("../") && relativePath !== ".." && !relativePath.startsWith("/") && !/^[a-zA-Z]:\//.test(relativePath);
|
|
67827
68016
|
}
|
|
67828
68017
|
function dirnameForContext(path20) {
|
|
67829
|
-
return isWindowsPath(path20) ? win322.dirname(path20) :
|
|
68018
|
+
return isWindowsPath(path20) ? win322.dirname(path20) : dirname11(path20);
|
|
67830
68019
|
}
|
|
67831
68020
|
function formatAbsoluteRulePath(path20) {
|
|
67832
68021
|
const normalized = normalizeOsPath(path20).replace(/\/+$/, "");
|
|
@@ -67887,7 +68076,7 @@ function analyzeReadApproval(filePath, workingDir) {
|
|
|
67887
68076
|
};
|
|
67888
68077
|
}
|
|
67889
68078
|
const relativePath = normalizeOsPath(relativePathForContext(workingDir, absolutePath));
|
|
67890
|
-
const relativeDir =
|
|
68079
|
+
const relativeDir = dirname11(relativePath);
|
|
67891
68080
|
const pattern = relativeDir === "." || relativeDir === "" ? "**" : `${relativeDir}/**`;
|
|
67892
68081
|
return {
|
|
67893
68082
|
recommendedRule: `Read(${pattern})`,
|
|
@@ -68972,6 +69161,7 @@ async function executeTool(name, args, options) {
|
|
|
68972
69161
|
if (options?.onOutput) {
|
|
68973
69162
|
enhancedArgs = { ...enhancedArgs, onOutput: options.onOutput };
|
|
68974
69163
|
}
|
|
69164
|
+
enhancedArgs = substituteSecretsInArgs(enhancedArgs);
|
|
68975
69165
|
}
|
|
68976
69166
|
if (internalName === "Task") {
|
|
68977
69167
|
if (options?.toolCallId) {
|
|
@@ -68980,6 +69170,9 @@ async function executeTool(name, args, options) {
|
|
|
68980
69170
|
if (options?.signal) {
|
|
68981
69171
|
enhancedArgs = { ...enhancedArgs, signal: options.signal };
|
|
68982
69172
|
}
|
|
69173
|
+
if (options?.parentScope) {
|
|
69174
|
+
enhancedArgs = { ...enhancedArgs, parentScope: options.parentScope };
|
|
69175
|
+
}
|
|
68983
69176
|
}
|
|
68984
69177
|
if (internalName === "Skill" && options?.toolCallId) {
|
|
68985
69178
|
enhancedArgs = { ...enhancedArgs, toolCallId: options.toolCallId };
|
|
@@ -69007,7 +69200,24 @@ async function executeTool(name, args, options) {
|
|
|
69007
69200
|
const stdout = isStringArray(stdoutValue) ? stdoutValue : undefined;
|
|
69008
69201
|
const stderr = isStringArray(stderrValue) ? stderrValue : undefined;
|
|
69009
69202
|
const toolStatus = recordResult?.status === "error" ? "error" : "success";
|
|
69010
|
-
|
|
69203
|
+
let flattenedResponse = flattenToolResponse(result);
|
|
69204
|
+
if (STREAMING_SHELL_TOOLS.has(internalName)) {
|
|
69205
|
+
if (typeof flattenedResponse === "string") {
|
|
69206
|
+
flattenedResponse = scrubSecretsFromString(flattenedResponse);
|
|
69207
|
+
} else if (Array.isArray(flattenedResponse)) {
|
|
69208
|
+
flattenedResponse = flattenedResponse.map((block) => block.type === "text" ? { ...block, text: scrubSecretsFromString(block.text) } : block);
|
|
69209
|
+
}
|
|
69210
|
+
if (stdout) {
|
|
69211
|
+
for (let i = 0;i < stdout.length; i++) {
|
|
69212
|
+
stdout[i] = scrubSecretsFromString(stdout[i]);
|
|
69213
|
+
}
|
|
69214
|
+
}
|
|
69215
|
+
if (stderr) {
|
|
69216
|
+
for (let i = 0;i < stderr.length; i++) {
|
|
69217
|
+
stderr[i] = scrubSecretsFromString(stderr[i]);
|
|
69218
|
+
}
|
|
69219
|
+
}
|
|
69220
|
+
}
|
|
69011
69221
|
const responseSize = typeof flattenedResponse === "string" ? flattenedResponse.length : JSON.stringify(flattenedResponse).length;
|
|
69012
69222
|
telemetry.trackToolUsage(internalName, toolStatus === "success", duration, responseSize, toolStatus === "error" ? "tool_error" : undefined, stderr ? stderr.join(`
|
|
69013
69223
|
`) : undefined);
|
|
@@ -69133,6 +69343,7 @@ var init_manager3 = __esm(async () => {
|
|
|
69133
69343
|
init_hooks(),
|
|
69134
69344
|
init_openai_codex_provider(),
|
|
69135
69345
|
init_telemetry(),
|
|
69346
|
+
init_secret_substitution(),
|
|
69136
69347
|
init_toolDefinitions()
|
|
69137
69348
|
]);
|
|
69138
69349
|
FILE_MODIFYING_TOOLS = new Set([
|
|
@@ -69528,7 +69739,7 @@ var init_constants2 = __esm(() => {
|
|
|
69528
69739
|
});
|
|
69529
69740
|
|
|
69530
69741
|
// src/websocket/listener/remote-settings.ts
|
|
69531
|
-
import { existsSync as
|
|
69742
|
+
import { existsSync as existsSync18, readFileSync as readFileSync8 } from "node:fs";
|
|
69532
69743
|
import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
69533
69744
|
import { homedir as homedir19 } from "node:os";
|
|
69534
69745
|
import path20 from "node:path";
|
|
@@ -69542,7 +69753,7 @@ function loadRemoteSettings() {
|
|
|
69542
69753
|
let loaded = {};
|
|
69543
69754
|
try {
|
|
69544
69755
|
const settingsPath = getRemoteSettingsPath();
|
|
69545
|
-
if (
|
|
69756
|
+
if (existsSync18(settingsPath)) {
|
|
69546
69757
|
const raw = readFileSync8(settingsPath, "utf-8");
|
|
69547
69758
|
const parsed = JSON.parse(raw);
|
|
69548
69759
|
loaded = parsed;
|
|
@@ -69551,7 +69762,7 @@ function loadRemoteSettings() {
|
|
|
69551
69762
|
if (loaded.cwdMap) {
|
|
69552
69763
|
const validCwdMap = {};
|
|
69553
69764
|
for (const [key, value] of Object.entries(loaded.cwdMap)) {
|
|
69554
|
-
if (typeof value === "string" &&
|
|
69765
|
+
if (typeof value === "string" && existsSync18(value)) {
|
|
69555
69766
|
validCwdMap[key] = value;
|
|
69556
69767
|
}
|
|
69557
69768
|
}
|
|
@@ -69578,13 +69789,13 @@ function saveRemoteSettings(updates) {
|
|
|
69578
69789
|
function loadLegacyCwdCache() {
|
|
69579
69790
|
try {
|
|
69580
69791
|
const legacyPath = path20.join(homedir19(), ".letta", "cwd-cache.json");
|
|
69581
|
-
if (!
|
|
69792
|
+
if (!existsSync18(legacyPath))
|
|
69582
69793
|
return {};
|
|
69583
69794
|
const raw = readFileSync8(legacyPath, "utf-8");
|
|
69584
69795
|
const parsed = JSON.parse(raw);
|
|
69585
69796
|
const result = {};
|
|
69586
69797
|
for (const [key, value] of Object.entries(parsed)) {
|
|
69587
|
-
if (typeof value === "string" &&
|
|
69798
|
+
if (typeof value === "string" && existsSync18(value)) {
|
|
69588
69799
|
result[key] = value;
|
|
69589
69800
|
}
|
|
69590
69801
|
}
|
|
@@ -69991,6 +70202,38 @@ function emitStateSync(socket, runtime, scope) {
|
|
|
69991
70202
|
emitDeviceStatusUpdate(socket, runtime, scope);
|
|
69992
70203
|
emitLoopStatusUpdate(socket, runtime, scope);
|
|
69993
70204
|
emitQueueUpdate(socket, runtime, scope);
|
|
70205
|
+
emitSubagentStateUpdate(socket, runtime, scope);
|
|
70206
|
+
}
|
|
70207
|
+
function buildSubagentSnapshot() {
|
|
70208
|
+
return getSubagents().filter((a) => !a.silent && (a.status === "pending" || a.status === "running")).map((a) => ({
|
|
70209
|
+
subagent_id: a.id,
|
|
70210
|
+
subagent_type: a.type,
|
|
70211
|
+
description: a.description,
|
|
70212
|
+
status: a.status,
|
|
70213
|
+
agent_url: a.agentURL,
|
|
70214
|
+
model: a.model,
|
|
70215
|
+
is_background: a.isBackground,
|
|
70216
|
+
silent: a.silent,
|
|
70217
|
+
tool_call_id: a.toolCallId,
|
|
70218
|
+
start_time: a.startTime,
|
|
70219
|
+
tool_calls: a.toolCalls,
|
|
70220
|
+
total_tokens: a.totalTokens,
|
|
70221
|
+
duration_ms: a.durationMs,
|
|
70222
|
+
error: a.error
|
|
70223
|
+
}));
|
|
70224
|
+
}
|
|
70225
|
+
function emitSubagentStateUpdate(socket, runtime, scope) {
|
|
70226
|
+
const message = {
|
|
70227
|
+
type: "update_subagent_state",
|
|
70228
|
+
subagents: buildSubagentSnapshot()
|
|
70229
|
+
};
|
|
70230
|
+
emitProtocolV2Message(socket, runtime, message, scope);
|
|
70231
|
+
}
|
|
70232
|
+
function emitSubagentStateIfOpen(runtime, scope) {
|
|
70233
|
+
const listener = getListenerRuntime(runtime);
|
|
70234
|
+
if (listener?.socket?.readyState === WebSocket2.OPEN) {
|
|
70235
|
+
emitSubagentStateUpdate(listener.socket, runtime, scope);
|
|
70236
|
+
}
|
|
69994
70237
|
}
|
|
69995
70238
|
function scheduleQueueEmit(runtime, scope) {
|
|
69996
70239
|
runtime.pendingQueueEmitScope = scope;
|
|
@@ -70060,15 +70303,17 @@ function emitInterruptedStatusDelta(socket, runtime, params) {
|
|
|
70060
70303
|
conversationId: params.conversationId ?? undefined
|
|
70061
70304
|
});
|
|
70062
70305
|
}
|
|
70063
|
-
function emitStreamDelta(socket, runtime, delta, scope) {
|
|
70306
|
+
function emitStreamDelta(socket, runtime, delta, scope, subagentId) {
|
|
70064
70307
|
const message = {
|
|
70065
70308
|
type: "stream_delta",
|
|
70066
|
-
delta
|
|
70309
|
+
delta,
|
|
70310
|
+
...subagentId ? { subagent_id: subagentId } : {}
|
|
70067
70311
|
};
|
|
70068
70312
|
emitProtocolV2Message(socket, runtime, message, scope);
|
|
70069
70313
|
}
|
|
70070
70314
|
var init_protocol_outbound = __esm(async () => {
|
|
70071
70315
|
init_memoryFilesystem();
|
|
70316
|
+
init_subagentState();
|
|
70072
70317
|
init_mode();
|
|
70073
70318
|
init_constants2();
|
|
70074
70319
|
init_cwd();
|
|
@@ -71029,7 +71274,22 @@ function buildQueuedTurnMessage(runtime, batch) {
|
|
|
71029
71274
|
for (const item of batch.items) {
|
|
71030
71275
|
runtime.queuedMessagesByItemId.delete(item.id);
|
|
71031
71276
|
}
|
|
71032
|
-
|
|
71277
|
+
const mergedContent2 = mergeDequeuedBatchContent(batch.items);
|
|
71278
|
+
if (mergedContent2 === null) {
|
|
71279
|
+
return null;
|
|
71280
|
+
}
|
|
71281
|
+
const scopeItem = batch.items[0];
|
|
71282
|
+
return {
|
|
71283
|
+
type: "message",
|
|
71284
|
+
agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
|
|
71285
|
+
conversationId: scopeItem?.conversationId ?? runtime.conversationId,
|
|
71286
|
+
messages: [
|
|
71287
|
+
{
|
|
71288
|
+
role: "user",
|
|
71289
|
+
content: mergedContent2
|
|
71290
|
+
}
|
|
71291
|
+
]
|
|
71292
|
+
};
|
|
71033
71293
|
}
|
|
71034
71294
|
const template = runtime.queuedMessagesByItemId.get(primaryItem.id);
|
|
71035
71295
|
for (const item of batch.items) {
|
|
@@ -71069,6 +71329,7 @@ function consumeQueuedTurn(runtime) {
|
|
|
71069
71329
|
}
|
|
71070
71330
|
let queueLen = 0;
|
|
71071
71331
|
let hasMessage = false;
|
|
71332
|
+
let hasTaskNotification = false;
|
|
71072
71333
|
for (const item of queuedItems) {
|
|
71073
71334
|
if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
|
|
71074
71335
|
break;
|
|
@@ -71077,8 +71338,11 @@ function consumeQueuedTurn(runtime) {
|
|
|
71077
71338
|
if (item.kind === "message") {
|
|
71078
71339
|
hasMessage = true;
|
|
71079
71340
|
}
|
|
71341
|
+
if (item.kind === "task_notification") {
|
|
71342
|
+
hasTaskNotification = true;
|
|
71343
|
+
}
|
|
71080
71344
|
}
|
|
71081
|
-
if (!hasMessage || queueLen === 0) {
|
|
71345
|
+
if (!hasMessage && !hasTaskNotification || queueLen === 0) {
|
|
71082
71346
|
return null;
|
|
71083
71347
|
}
|
|
71084
71348
|
const dequeuedBatch = runtime.queueRuntime.consumeItems(queueLen);
|
|
@@ -71965,6 +72229,9 @@ function isCloudflareEdge52xDetail(detail) {
|
|
|
71965
72229
|
return false;
|
|
71966
72230
|
return isCloudflareEdge52xHtmlError2(detail);
|
|
71967
72231
|
}
|
|
72232
|
+
function isQuotaLimitErrorDetail(detail) {
|
|
72233
|
+
return hasNonRetryableQuotaDetail(detail);
|
|
72234
|
+
}
|
|
71968
72235
|
function hasNonRetryableQuotaDetail(detail) {
|
|
71969
72236
|
if (typeof detail !== "string")
|
|
71970
72237
|
return false;
|
|
@@ -73421,7 +73688,7 @@ var init_accumulator = __esm(async () => {
|
|
|
73421
73688
|
});
|
|
73422
73689
|
|
|
73423
73690
|
// src/agent/clientSkills.ts
|
|
73424
|
-
import { join as
|
|
73691
|
+
import { join as join22 } from "node:path";
|
|
73425
73692
|
function toClientSkill(skill2) {
|
|
73426
73693
|
return {
|
|
73427
73694
|
name: skill2.id,
|
|
@@ -73430,37 +73697,64 @@ function toClientSkill(skill2) {
|
|
|
73430
73697
|
};
|
|
73431
73698
|
}
|
|
73432
73699
|
function resolveSkillDiscoveryContext(options) {
|
|
73433
|
-
const
|
|
73700
|
+
const legacySkillsDirectory = options.skillsDirectory ?? getSkillsDirectory() ?? join22(process.cwd(), SKILLS_DIR);
|
|
73434
73701
|
const skillSources = options.skillSources ?? getSkillSources();
|
|
73435
|
-
return {
|
|
73702
|
+
return { legacySkillsDirectory, skillSources };
|
|
73703
|
+
}
|
|
73704
|
+
function getPrimaryProjectSkillsDirectory() {
|
|
73705
|
+
return join22(process.cwd(), ".agents", "skills");
|
|
73436
73706
|
}
|
|
73437
73707
|
async function buildClientSkillsPayload(options = {}) {
|
|
73438
|
-
const {
|
|
73708
|
+
const { legacySkillsDirectory, skillSources } = resolveSkillDiscoveryContext(options);
|
|
73439
73709
|
const discoverSkillsFn = options.discoverSkillsFn ?? discoverSkills;
|
|
73440
|
-
|
|
73441
|
-
|
|
73442
|
-
|
|
73710
|
+
const skillsById = new Map;
|
|
73711
|
+
const errors = [];
|
|
73712
|
+
const primaryProjectSkillsDirectory = getPrimaryProjectSkillsDirectory();
|
|
73713
|
+
const nonProjectSources = skillSources.filter((source) => source !== "project");
|
|
73714
|
+
const discoveryRuns = [];
|
|
73715
|
+
if (nonProjectSources.length > 0) {
|
|
73716
|
+
discoveryRuns.push({
|
|
73717
|
+
path: primaryProjectSkillsDirectory,
|
|
73718
|
+
sources: nonProjectSources
|
|
73443
73719
|
});
|
|
73444
|
-
const sortedSkills = [...discovery.skills].sort(compareSkills);
|
|
73445
|
-
return {
|
|
73446
|
-
clientSkills: sortedSkills.map(toClientSkill),
|
|
73447
|
-
skillPathById: Object.fromEntries(sortedSkills.filter((skill2) => typeof skill2.path === "string" && skill2.path.length > 0).map((skill2) => [skill2.id, skill2.path])),
|
|
73448
|
-
errors: discovery.errors
|
|
73449
|
-
};
|
|
73450
|
-
} catch (error) {
|
|
73451
|
-
const message = error instanceof Error ? error.message : `Unknown error: ${String(error)}`;
|
|
73452
|
-
options.logger?.(`Failed to build client_skills payload: ${message}`);
|
|
73453
|
-
return {
|
|
73454
|
-
clientSkills: [],
|
|
73455
|
-
skillPathById: {},
|
|
73456
|
-
errors: [
|
|
73457
|
-
{
|
|
73458
|
-
path: skillsDirectory,
|
|
73459
|
-
message
|
|
73460
|
-
}
|
|
73461
|
-
]
|
|
73462
|
-
};
|
|
73463
73720
|
}
|
|
73721
|
+
const includeProjectSource = skillSources.includes("project");
|
|
73722
|
+
if (includeProjectSource && legacySkillsDirectory !== primaryProjectSkillsDirectory) {
|
|
73723
|
+
discoveryRuns.push({
|
|
73724
|
+
path: legacySkillsDirectory,
|
|
73725
|
+
sources: ["project"]
|
|
73726
|
+
});
|
|
73727
|
+
}
|
|
73728
|
+
if (includeProjectSource) {
|
|
73729
|
+
discoveryRuns.push({
|
|
73730
|
+
path: primaryProjectSkillsDirectory,
|
|
73731
|
+
sources: ["project"]
|
|
73732
|
+
});
|
|
73733
|
+
}
|
|
73734
|
+
for (const run of discoveryRuns) {
|
|
73735
|
+
try {
|
|
73736
|
+
const discovery = await discoverSkillsFn(run.path, options.agentId, {
|
|
73737
|
+
sources: run.sources
|
|
73738
|
+
});
|
|
73739
|
+
errors.push(...discovery.errors);
|
|
73740
|
+
for (const skill2 of discovery.skills) {
|
|
73741
|
+
skillsById.set(skill2.id, skill2);
|
|
73742
|
+
}
|
|
73743
|
+
} catch (error) {
|
|
73744
|
+
const message = error instanceof Error ? error.message : `Unknown error: ${String(error)}`;
|
|
73745
|
+
errors.push({ path: run.path, message });
|
|
73746
|
+
}
|
|
73747
|
+
}
|
|
73748
|
+
const sortedSkills = [...skillsById.values()].sort(compareSkills);
|
|
73749
|
+
if (errors.length > 0) {
|
|
73750
|
+
const summarizedErrors = errors.map((error) => `${error.path}: ${error.message}`);
|
|
73751
|
+
options.logger?.(`Failed to build some client_skills entries: ${summarizedErrors.join("; ")}`);
|
|
73752
|
+
}
|
|
73753
|
+
return {
|
|
73754
|
+
clientSkills: sortedSkills.map(toClientSkill),
|
|
73755
|
+
skillPathById: Object.fromEntries(sortedSkills.filter((skill2) => typeof skill2.path === "string" && skill2.path.length > 0).map((skill2) => [skill2.id, skill2.path])),
|
|
73756
|
+
errors
|
|
73757
|
+
};
|
|
73464
73758
|
}
|
|
73465
73759
|
var init_clientSkills = __esm(() => {
|
|
73466
73760
|
init_context();
|
|
@@ -73491,6 +73785,7 @@ function buildConversationMessagesCreateRequestBody(conversationId, messages, op
|
|
|
73491
73785
|
client_skills: clientSkills,
|
|
73492
73786
|
client_tools: clientTools,
|
|
73493
73787
|
include_compaction_messages: true,
|
|
73788
|
+
...opts.overrideModel ? { override_model: opts.overrideModel } : {},
|
|
73494
73789
|
...isDefaultConversation ? { agent_id: opts.agentId } : {}
|
|
73495
73790
|
};
|
|
73496
73791
|
}
|
|
@@ -73535,7 +73830,8 @@ async function sendMessageStream(conversationId, messages, opts = { streamTokens
|
|
|
73535
73830
|
}
|
|
73536
73831
|
return `message:parts:${content.length}`;
|
|
73537
73832
|
}).join(",");
|
|
73538
|
-
|
|
73833
|
+
const firstOtid = messages[0]?.otid;
|
|
73834
|
+
debugLog("send-message-stream", "request_start conversation_id=%s agent_id=%s messages=%s otid=%s stream_tokens=%s background=%s max_retries=%s", resolvedConversationId, opts.agentId ?? "none", messageSummary || "(empty)", firstOtid ?? "none", opts.streamTokens ?? true, opts.background ?? true, requestOptions.maxRetries ?? "default");
|
|
73539
73835
|
let stream2;
|
|
73540
73836
|
try {
|
|
73541
73837
|
stream2 = await client.conversations.messages.create(resolvedConversationId, requestBody, {
|
|
@@ -73546,10 +73842,10 @@ async function sendMessageStream(conversationId, messages, opts = { streamTokens
|
|
|
73546
73842
|
}
|
|
73547
73843
|
});
|
|
73548
73844
|
} catch (error) {
|
|
73549
|
-
debugWarn("send-message-stream", "request_error conversation_id=%s status=%s error=%s", resolvedConversationId, error?.status ?? "none", error instanceof Error ? error.message : String(error));
|
|
73845
|
+
debugWarn("send-message-stream", "request_error conversation_id=%s otid=%s status=%s error=%s", resolvedConversationId, firstOtid ?? "none", error?.status ?? "none", error instanceof Error ? error.message : String(error));
|
|
73550
73846
|
throw error;
|
|
73551
73847
|
}
|
|
73552
|
-
debugLog("send-message-stream", "request_ok conversation_id=%s", resolvedConversationId);
|
|
73848
|
+
debugLog("send-message-stream", "request_ok conversation_id=%s otid=%s", resolvedConversationId, firstOtid ?? "none");
|
|
73553
73849
|
if (requestStartTime !== undefined) {
|
|
73554
73850
|
streamRequestStartTimes.set(stream2, requestStartTime);
|
|
73555
73851
|
}
|
|
@@ -73558,7 +73854,8 @@ async function sendMessageStream(conversationId, messages, opts = { streamTokens
|
|
|
73558
73854
|
conversationId,
|
|
73559
73855
|
resolvedConversationId,
|
|
73560
73856
|
agentId: opts.agentId ?? null,
|
|
73561
|
-
requestStartedAtMs
|
|
73857
|
+
requestStartedAtMs,
|
|
73858
|
+
otid: firstOtid
|
|
73562
73859
|
});
|
|
73563
73860
|
return stream2;
|
|
73564
73861
|
}
|
|
@@ -73580,14 +73877,14 @@ var init_message = __esm(async () => {
|
|
|
73580
73877
|
|
|
73581
73878
|
// src/cli/helpers/chunkLog.ts
|
|
73582
73879
|
import {
|
|
73583
|
-
existsSync as
|
|
73584
|
-
mkdirSync as
|
|
73880
|
+
existsSync as existsSync19,
|
|
73881
|
+
mkdirSync as mkdirSync13,
|
|
73585
73882
|
readdirSync as readdirSync8,
|
|
73586
73883
|
unlinkSync as unlinkSync5,
|
|
73587
|
-
writeFileSync as
|
|
73884
|
+
writeFileSync as writeFileSync10
|
|
73588
73885
|
} from "node:fs";
|
|
73589
73886
|
import { homedir as homedir20 } from "node:os";
|
|
73590
|
-
import { join as
|
|
73887
|
+
import { join as join23 } from "node:path";
|
|
73591
73888
|
function truncateStr(value, maxLen) {
|
|
73592
73889
|
if (value === null || value === undefined)
|
|
73593
73890
|
return "";
|
|
@@ -73651,8 +73948,8 @@ class ChunkLog {
|
|
|
73651
73948
|
agentDir = null;
|
|
73652
73949
|
dirCreated = false;
|
|
73653
73950
|
init(agentId, sessionId) {
|
|
73654
|
-
this.agentDir =
|
|
73655
|
-
this.logPath =
|
|
73951
|
+
this.agentDir = join23(LOG_BASE_DIR, agentId);
|
|
73952
|
+
this.logPath = join23(this.agentDir, `${sessionId}.jsonl`);
|
|
73656
73953
|
this.buffer = [];
|
|
73657
73954
|
this.dirty = false;
|
|
73658
73955
|
this.dirCreated = false;
|
|
@@ -73681,8 +73978,8 @@ class ChunkLog {
|
|
|
73681
73978
|
if (this.dirCreated || !this.agentDir)
|
|
73682
73979
|
return;
|
|
73683
73980
|
try {
|
|
73684
|
-
if (!
|
|
73685
|
-
|
|
73981
|
+
if (!existsSync19(this.agentDir)) {
|
|
73982
|
+
mkdirSync13(this.agentDir, { recursive: true });
|
|
73686
73983
|
}
|
|
73687
73984
|
this.dirCreated = true;
|
|
73688
73985
|
} catch (e) {
|
|
@@ -73696,7 +73993,7 @@ class ChunkLog {
|
|
|
73696
73993
|
try {
|
|
73697
73994
|
const content = this.buffer.map((entry) => JSON.stringify(entry)).join(`
|
|
73698
73995
|
`);
|
|
73699
|
-
|
|
73996
|
+
writeFileSync10(this.logPath, `${content}
|
|
73700
73997
|
`, "utf8");
|
|
73701
73998
|
} catch (e) {
|
|
73702
73999
|
debugWarn("chunkLog", `Failed to write ${this.logPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -73706,14 +74003,14 @@ class ChunkLog {
|
|
|
73706
74003
|
if (!this.agentDir)
|
|
73707
74004
|
return;
|
|
73708
74005
|
try {
|
|
73709
|
-
if (!
|
|
74006
|
+
if (!existsSync19(this.agentDir))
|
|
73710
74007
|
return;
|
|
73711
74008
|
const files = readdirSync8(this.agentDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
73712
74009
|
if (files.length >= MAX_SESSION_FILES2) {
|
|
73713
74010
|
const toDelete = files.slice(0, files.length - MAX_SESSION_FILES2 + 1);
|
|
73714
74011
|
for (const file of toDelete) {
|
|
73715
74012
|
try {
|
|
73716
|
-
unlinkSync5(
|
|
74013
|
+
unlinkSync5(join23(this.agentDir, file));
|
|
73717
74014
|
} catch (e) {
|
|
73718
74015
|
debugWarn("chunkLog", `Failed to delete old session log ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
73719
74016
|
}
|
|
@@ -73727,7 +74024,7 @@ class ChunkLog {
|
|
|
73727
74024
|
var MAX_ENTRIES = 100, CONTENT_TRUNCATE_LEN = 200, MAX_SESSION_FILES2 = 5, LOG_BASE_DIR, chunkLog;
|
|
73728
74025
|
var init_chunkLog = __esm(() => {
|
|
73729
74026
|
init_debug();
|
|
73730
|
-
LOG_BASE_DIR =
|
|
74027
|
+
LOG_BASE_DIR = join23(homedir20(), ".letta", "logs", "chunk-logs");
|
|
73731
74028
|
chunkLog = new ChunkLog;
|
|
73732
74029
|
});
|
|
73733
74030
|
|
|
@@ -73890,7 +74187,7 @@ async function discoverFallbackRunIdForResume(client, ctx) {
|
|
|
73890
74187
|
}
|
|
73891
74188
|
return null;
|
|
73892
74189
|
}
|
|
73893
|
-
async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, isResumeStream) {
|
|
74190
|
+
async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, isResumeStream, skipCancelToolsOnError) {
|
|
73894
74191
|
const startTime = performance.now();
|
|
73895
74192
|
const requestStartTime = getStreamRequestStartTime(stream2) ?? startTime;
|
|
73896
74193
|
let hasLoggedTTFT = false;
|
|
@@ -73996,7 +74293,11 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
73996
74293
|
}
|
|
73997
74294
|
fallbackError = errorMessageWithDiagnostic;
|
|
73998
74295
|
stopReason = streamProcessor.stopReason || "error";
|
|
73999
|
-
|
|
74296
|
+
if (skipCancelToolsOnError) {
|
|
74297
|
+
buffers.interrupted = true;
|
|
74298
|
+
} else {
|
|
74299
|
+
markIncompleteToolsAsCancelled(buffers, true, "stream_error", true);
|
|
74300
|
+
}
|
|
74000
74301
|
queueMicrotask(refresh);
|
|
74001
74302
|
} finally {
|
|
74002
74303
|
try {
|
|
@@ -74021,13 +74322,15 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
74021
74322
|
if (stopReason === "cancelled") {
|
|
74022
74323
|
markIncompleteToolsAsCancelled(buffers, true, "user_interrupt");
|
|
74023
74324
|
}
|
|
74024
|
-
|
|
74325
|
+
if (stopReason !== "error") {
|
|
74326
|
+
markCurrentLineAsFinished(buffers);
|
|
74327
|
+
}
|
|
74025
74328
|
queueMicrotask(refresh);
|
|
74026
74329
|
const allPending = Array.from(streamProcessor.pendingApprovals.values());
|
|
74027
74330
|
const approvals = allPending.map((a) => ({
|
|
74028
74331
|
toolCallId: a.toolCallId,
|
|
74029
74332
|
toolName: a.toolName || "",
|
|
74030
|
-
toolArgs: a.toolArgs || "
|
|
74333
|
+
toolArgs: a.toolArgs || ""
|
|
74031
74334
|
}));
|
|
74032
74335
|
const approval = approvals[0] || null;
|
|
74033
74336
|
streamProcessor.pendingApprovals.clear();
|
|
@@ -74048,6 +74351,7 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
|
|
|
74048
74351
|
async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold) {
|
|
74049
74352
|
const overallStartTime = performance.now();
|
|
74050
74353
|
const streamRequestContext = getStreamRequestContext(stream2);
|
|
74354
|
+
const streamOtid = streamRequestContext?.otid ?? null;
|
|
74051
74355
|
let _client;
|
|
74052
74356
|
const lazyClient = async () => {
|
|
74053
74357
|
if (!_client) {
|
|
@@ -74055,54 +74359,84 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
|
|
|
74055
74359
|
}
|
|
74056
74360
|
return _client;
|
|
74057
74361
|
};
|
|
74058
|
-
let result = await drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold);
|
|
74362
|
+
let result = await drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, false, true);
|
|
74059
74363
|
let runIdToResume = result.lastRunId ?? null;
|
|
74060
74364
|
let runIdSource = result.lastRunId ? "stream_chunk" : null;
|
|
74061
74365
|
if (result.stopReason === "error" && !runIdToResume && streamRequestContext && abortSignal && !abortSignal.aborted) {
|
|
74062
|
-
|
|
74063
|
-
|
|
74064
|
-
|
|
74065
|
-
|
|
74066
|
-
|
|
74067
|
-
|
|
74068
|
-
|
|
74069
|
-
|
|
74366
|
+
if (streamOtid) {
|
|
74367
|
+
runIdSource = "otid";
|
|
74368
|
+
debugLog("stream", "Mid-stream resume: will use OTID-based conversations stream (otid=%s)", streamOtid);
|
|
74369
|
+
} else {
|
|
74370
|
+
try {
|
|
74371
|
+
debugLog("stream", "Mid-stream resume: attempting run discovery (conv=%s, agent=%s)", streamRequestContext.conversationId, streamRequestContext.agentId);
|
|
74372
|
+
const client = await lazyClient();
|
|
74373
|
+
runIdToResume = await discoverFallbackRunIdWithTimeout(client, streamRequestContext);
|
|
74374
|
+
debugLog("stream", "Mid-stream resume: run discovery result: %s", runIdToResume ?? "none");
|
|
74375
|
+
if (runIdToResume) {
|
|
74376
|
+
result.lastRunId = runIdToResume;
|
|
74377
|
+
runIdSource = "discovery";
|
|
74378
|
+
}
|
|
74379
|
+
} catch (lookupError) {
|
|
74380
|
+
const lookupErrorMsg = lookupError instanceof Error ? lookupError.message : String(lookupError);
|
|
74381
|
+
telemetry.trackError("stream_resume_lookup_failed", lookupErrorMsg, "stream_resume");
|
|
74382
|
+
debugWarn("drainStreamWithResume", "Fallback run_id lookup failed:", lookupError);
|
|
74070
74383
|
}
|
|
74071
|
-
} catch (lookupError) {
|
|
74072
|
-
const lookupErrorMsg = lookupError instanceof Error ? lookupError.message : String(lookupError);
|
|
74073
|
-
telemetry.trackError("stream_resume_lookup_failed", lookupErrorMsg, "stream_resume");
|
|
74074
|
-
debugWarn("drainStreamWithResume", "Fallback run_id lookup failed:", lookupError);
|
|
74075
74384
|
}
|
|
74076
74385
|
}
|
|
74077
|
-
|
|
74386
|
+
const isApprovalPendingConflict = result.fallbackError?.includes("waiting for approval on a tool call") ?? false;
|
|
74387
|
+
const canResume = result.stopReason === "error" && !isApprovalPendingConflict && (runIdToResume || runIdSource === "otid") && abortSignal && !abortSignal.aborted;
|
|
74388
|
+
if (canResume) {
|
|
74078
74389
|
const originalFallbackError = result.fallbackError;
|
|
74079
74390
|
const originalApprovals = result.approvals;
|
|
74080
74391
|
const originalApproval = result.approval;
|
|
74081
74392
|
telemetry.trackError("stream_resume_attempt", originalFallbackError || "Stream error (no client-side detail)", "stream_resume", {
|
|
74082
74393
|
runId: result.lastRunId ?? undefined
|
|
74083
74394
|
});
|
|
74084
|
-
|
|
74085
|
-
debugLog("stream", "Mid-stream resume: attempting resume (runId=%s, lastSeqId=%s)", runIdToResume, result.lastSeqId ?? 0);
|
|
74395
|
+
debugWarn("stream", "[MID-STREAM RESUME] Attempting (runId=%s, lastSeqId=%s, source=%s, otid=%s)", runIdToResume ?? "none", result.lastSeqId ?? 0, runIdSource ?? "unknown", streamOtid ?? "none");
|
|
74086
74396
|
try {
|
|
74087
74397
|
const client = await lazyClient();
|
|
74088
74398
|
buffers.commitGeneration = (buffers.commitGeneration || 0) + 1;
|
|
74089
74399
|
buffers.interrupted = false;
|
|
74090
|
-
const resumeStream = await client.
|
|
74400
|
+
const resumeStream = runIdSource === "otid" && streamOtid && streamRequestContext ? await client.conversations.messages.stream(streamRequestContext.resolvedConversationId, {
|
|
74401
|
+
agent_id: streamRequestContext.conversationId === "default" ? streamRequestContext.agentId ?? undefined : undefined,
|
|
74402
|
+
otid: streamOtid,
|
|
74403
|
+
starting_after: result.lastSeqId ?? 0,
|
|
74404
|
+
batch_size: 1000
|
|
74405
|
+
}) : await client.runs.messages.stream(runIdToResume, {
|
|
74091
74406
|
starting_after: result.lastSeqId ?? 0,
|
|
74092
74407
|
batch_size: 1000
|
|
74093
74408
|
});
|
|
74094
74409
|
const resumeResult = await drainStream(resumeStream, buffers, refresh, abortSignal, undefined, onChunkProcessed, contextTracker, seenSeqIdThreshold, true);
|
|
74095
|
-
|
|
74410
|
+
if (resumeResult.stopReason !== "error") {
|
|
74411
|
+
debugWarn("stream", "[MID-STREAM RESUME] ✅ Success (runId=%s, stopReason=%s)", runIdToResume, resumeResult.stopReason);
|
|
74412
|
+
} else {
|
|
74413
|
+
debugWarn("stream", "[MID-STREAM RESUME] ⚠️ Resumed but terminal error persisted (runId=%s)", runIdToResume);
|
|
74414
|
+
}
|
|
74096
74415
|
result = resumeResult;
|
|
74097
|
-
if (result.stopReason === "requires_approval" && (
|
|
74098
|
-
result.approvals
|
|
74099
|
-
|
|
74416
|
+
if (result.stopReason === "requires_approval" && (originalApprovals?.length ?? 0) > 0) {
|
|
74417
|
+
if ((result.approvals?.length ?? 0) === 0) {
|
|
74418
|
+
result.approvals = originalApprovals;
|
|
74419
|
+
result.approval = originalApproval;
|
|
74420
|
+
} else {
|
|
74421
|
+
result.approvals = (result.approvals ?? []).map((resumeApproval) => {
|
|
74422
|
+
const orig = originalApprovals?.find((a) => a.toolCallId === resumeApproval.toolCallId);
|
|
74423
|
+
if (!orig)
|
|
74424
|
+
return resumeApproval;
|
|
74425
|
+
return {
|
|
74426
|
+
...resumeApproval,
|
|
74427
|
+
toolName: resumeApproval.toolName || orig.toolName,
|
|
74428
|
+
toolArgs: (orig.toolArgs || "") + (resumeApproval.toolArgs || "")
|
|
74429
|
+
};
|
|
74430
|
+
});
|
|
74431
|
+
result.approval = result.approvals[0] ?? null;
|
|
74432
|
+
}
|
|
74100
74433
|
}
|
|
74101
74434
|
} catch (resumeError) {
|
|
74435
|
+
markIncompleteToolsAsCancelled(buffers, false, "stream_error", true);
|
|
74102
74436
|
markCurrentLineAsFinished(buffers);
|
|
74103
74437
|
result.fallbackError = originalFallbackError;
|
|
74104
74438
|
const resumeErrorMsg = resumeError instanceof Error ? resumeError.message : String(resumeError);
|
|
74105
|
-
|
|
74439
|
+
debugWarn("stream", "[MID-STREAM RESUME] ❌ Failed (runId=%s): %s", runIdToResume, resumeErrorMsg);
|
|
74106
74440
|
telemetry.trackError("stream_resume_failed", resumeErrorMsg, "stream_resume", {
|
|
74107
74441
|
runId: result.lastRunId ?? undefined
|
|
74108
74442
|
});
|
|
@@ -74110,13 +74444,14 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
|
|
|
74110
74444
|
}
|
|
74111
74445
|
if (result.stopReason === "error") {
|
|
74112
74446
|
const skipReasons = [];
|
|
74113
|
-
if (!result.lastRunId)
|
|
74447
|
+
if (!result.lastRunId && runIdSource !== "otid")
|
|
74114
74448
|
skipReasons.push("no_run_id");
|
|
74115
74449
|
if (!abortSignal)
|
|
74116
74450
|
skipReasons.push("no_abort_signal");
|
|
74117
74451
|
if (abortSignal?.aborted)
|
|
74118
74452
|
skipReasons.push("user_aborted");
|
|
74119
74453
|
if (skipReasons.length > 0) {
|
|
74454
|
+
markIncompleteToolsAsCancelled(buffers, false, "stream_error", true);
|
|
74120
74455
|
markCurrentLineAsFinished(buffers);
|
|
74121
74456
|
debugLog("stream", "Mid-stream resume skipped: %s", skipReasons.join(", "));
|
|
74122
74457
|
telemetry.trackError("stream_resume_skipped", `${result.fallbackError || "Stream error (no client-side detail)"} [skip: ${skipReasons.join(", ")}]`, "stream_resume", {
|
|
@@ -74124,6 +74459,10 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
|
|
|
74124
74459
|
});
|
|
74125
74460
|
}
|
|
74126
74461
|
}
|
|
74462
|
+
if (result.stopReason === "requires_approval" && (result.approvals?.length ?? 0) > 0 && buffers.interrupted) {
|
|
74463
|
+
buffers.interrupted = false;
|
|
74464
|
+
markCurrentLineAsFinished(buffers);
|
|
74465
|
+
}
|
|
74127
74466
|
result.apiDurationMs = performance.now() - overallStartTime;
|
|
74128
74467
|
return result;
|
|
74129
74468
|
}
|
|
@@ -75802,7 +76141,11 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
75802
76141
|
try {
|
|
75803
76142
|
const approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
75804
76143
|
abortSignal: recoveryAbortController.signal,
|
|
75805
|
-
workingDirectory: getConversationWorkingDirectory(runtime.listener, recovered.agentId, recovered.conversationId)
|
|
76144
|
+
workingDirectory: getConversationWorkingDirectory(runtime.listener, recovered.agentId, recovered.conversationId),
|
|
76145
|
+
parentScope: recovered.agentId && recovered.conversationId ? {
|
|
76146
|
+
agentId: recovered.agentId,
|
|
76147
|
+
conversationId: recovered.conversationId
|
|
76148
|
+
} : undefined
|
|
75806
76149
|
});
|
|
75807
76150
|
emitToolExecutionFinishedEvents(socket, runtime, {
|
|
75808
76151
|
approvals: approvalResults,
|
|
@@ -76142,7 +76485,11 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
76142
76485
|
try {
|
|
76143
76486
|
const approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
76144
76487
|
abortSignal,
|
|
76145
|
-
workingDirectory: recoveryWorkingDirectory
|
|
76488
|
+
workingDirectory: recoveryWorkingDirectory,
|
|
76489
|
+
parentScope: runtime.agentId && runtime.conversationId ? {
|
|
76490
|
+
agentId: runtime.agentId,
|
|
76491
|
+
conversationId: runtime.conversationId
|
|
76492
|
+
} : undefined
|
|
76146
76493
|
});
|
|
76147
76494
|
emitToolExecutionFinishedEvents(socket, runtime, {
|
|
76148
76495
|
approvals: approvalResults,
|
|
@@ -76198,7 +76545,6 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
76198
76545
|
let conversationBusyRetries = 0;
|
|
76199
76546
|
let preStreamRecoveryAttempts = 0;
|
|
76200
76547
|
const MAX_CONVERSATION_BUSY_RETRIES = 3;
|
|
76201
|
-
const requestStartedAtMs = Date.now();
|
|
76202
76548
|
while (true) {
|
|
76203
76549
|
if (abortSignal?.aborted) {
|
|
76204
76550
|
throw new Error("Cancelled by user");
|
|
@@ -76283,21 +76629,16 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
76283
76629
|
});
|
|
76284
76630
|
try {
|
|
76285
76631
|
const client = await getClient2();
|
|
76286
|
-
const
|
|
76287
|
-
|
|
76288
|
-
|
|
76289
|
-
agentId: runtime.agentId ?? null,
|
|
76290
|
-
requestStartedAtMs
|
|
76291
|
-
});
|
|
76292
|
-
if (discoveredRunId) {
|
|
76293
|
-
if (abortSignal?.aborted) {
|
|
76294
|
-
throw new Error("Cancelled by user");
|
|
76295
|
-
}
|
|
76296
|
-
return await client.runs.messages.stream(discoveredRunId, {
|
|
76297
|
-
starting_after: 0,
|
|
76298
|
-
batch_size: 1000
|
|
76299
|
-
});
|
|
76632
|
+
const messageOtid = messages.map((item) => item.otid).find((value) => typeof value === "string");
|
|
76633
|
+
if (abortSignal?.aborted) {
|
|
76634
|
+
throw new Error("Cancelled by user");
|
|
76300
76635
|
}
|
|
76636
|
+
return await client.conversations.messages.stream(conversationId, {
|
|
76637
|
+
agent_id: conversationId === "default" ? runtime.agentId ?? undefined : undefined,
|
|
76638
|
+
otid: messageOtid ?? undefined,
|
|
76639
|
+
starting_after: 0,
|
|
76640
|
+
batch_size: 1000
|
|
76641
|
+
});
|
|
76301
76642
|
} catch (resumeError) {
|
|
76302
76643
|
if (abortSignal?.aborted) {
|
|
76303
76644
|
throw new Error("Cancelled by user");
|
|
@@ -76337,7 +76678,6 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
76337
76678
|
let conversationBusyRetries = 0;
|
|
76338
76679
|
let preStreamRecoveryAttempts = 0;
|
|
76339
76680
|
const MAX_CONVERSATION_BUSY_RETRIES = 3;
|
|
76340
|
-
const requestStartedAtMs = Date.now();
|
|
76341
76681
|
while (true) {
|
|
76342
76682
|
if (abortSignal?.aborted) {
|
|
76343
76683
|
throw new Error("Cancelled by user");
|
|
@@ -76412,21 +76752,16 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
76412
76752
|
});
|
|
76413
76753
|
try {
|
|
76414
76754
|
const client = await getClient2();
|
|
76415
|
-
const
|
|
76416
|
-
|
|
76417
|
-
|
|
76418
|
-
agentId: runtime.agentId ?? null,
|
|
76419
|
-
requestStartedAtMs
|
|
76420
|
-
});
|
|
76421
|
-
if (discoveredRunId) {
|
|
76422
|
-
if (abortSignal?.aborted) {
|
|
76423
|
-
throw new Error("Cancelled by user");
|
|
76424
|
-
}
|
|
76425
|
-
return await client.runs.messages.stream(discoveredRunId, {
|
|
76426
|
-
starting_after: 0,
|
|
76427
|
-
batch_size: 1000
|
|
76428
|
-
});
|
|
76755
|
+
const messageOtid = messages.map((item) => item.otid).find((value) => typeof value === "string");
|
|
76756
|
+
if (abortSignal?.aborted) {
|
|
76757
|
+
throw new Error("Cancelled by user");
|
|
76429
76758
|
}
|
|
76759
|
+
return await client.conversations.messages.stream(conversationId, {
|
|
76760
|
+
agent_id: conversationId === "default" ? runtime.agentId ?? undefined : undefined,
|
|
76761
|
+
otid: messageOtid ?? undefined,
|
|
76762
|
+
starting_after: 0,
|
|
76763
|
+
batch_size: 1000
|
|
76764
|
+
});
|
|
76430
76765
|
} catch (resumeError) {
|
|
76431
76766
|
if (abortSignal?.aborted) {
|
|
76432
76767
|
throw new Error("Cancelled by user");
|
|
@@ -76466,7 +76801,6 @@ var init_send = __esm(async () => {
|
|
|
76466
76801
|
init_client2(),
|
|
76467
76802
|
init_message(),
|
|
76468
76803
|
init_approvalClassification(),
|
|
76469
|
-
init_stream(),
|
|
76470
76804
|
init_approval(),
|
|
76471
76805
|
init_interrupts(),
|
|
76472
76806
|
init_protocol_outbound(),
|
|
@@ -77414,7 +77748,8 @@ async function handleApprovalStop(params) {
|
|
|
77414
77748
|
const executionResults = await executeApprovalBatch(decisions, undefined, {
|
|
77415
77749
|
toolContextId: turnToolContextId ?? undefined,
|
|
77416
77750
|
abortSignal: abortController.signal,
|
|
77417
|
-
workingDirectory: turnWorkingDirectory
|
|
77751
|
+
workingDirectory: turnWorkingDirectory,
|
|
77752
|
+
parentScope: agentId && conversationId ? { agentId, conversationId } : undefined
|
|
77418
77753
|
});
|
|
77419
77754
|
const persistedExecutionResults = normalizeExecutionResultsForInterruptParity(runtime, executionResults, lastExecutingToolCallIds);
|
|
77420
77755
|
validateApprovalResultIds(decisions.map((decision) => ({
|
|
@@ -78039,7 +78374,7 @@ __export(exports_memoryScanner, {
|
|
|
78039
78374
|
getFileNodes: () => getFileNodes
|
|
78040
78375
|
});
|
|
78041
78376
|
import { readdirSync as readdirSync9, readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
|
|
78042
|
-
import { join as
|
|
78377
|
+
import { join as join24, relative as relative11 } from "node:path";
|
|
78043
78378
|
function scanMemoryFilesystem(memoryRoot) {
|
|
78044
78379
|
const nodes = [];
|
|
78045
78380
|
const scanDir = (dir, depth, parentIsLast) => {
|
|
@@ -78051,8 +78386,8 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
78051
78386
|
}
|
|
78052
78387
|
const filtered = entries.filter((name) => !name.startsWith("."));
|
|
78053
78388
|
const sorted = filtered.sort((a, b) => {
|
|
78054
|
-
const aPath =
|
|
78055
|
-
const bPath =
|
|
78389
|
+
const aPath = join24(dir, a);
|
|
78390
|
+
const bPath = join24(dir, b);
|
|
78056
78391
|
let aIsDir = false;
|
|
78057
78392
|
let bIsDir = false;
|
|
78058
78393
|
try {
|
|
@@ -78072,7 +78407,7 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
78072
78407
|
return a.localeCompare(b);
|
|
78073
78408
|
});
|
|
78074
78409
|
sorted.forEach((name, index) => {
|
|
78075
|
-
const fullPath =
|
|
78410
|
+
const fullPath = join24(dir, name);
|
|
78076
78411
|
let isDir = false;
|
|
78077
78412
|
try {
|
|
78078
78413
|
isDir = statSync5(fullPath).isDirectory();
|
|
@@ -78186,6 +78521,14 @@ function ensureConversationQueueRuntime(listener, runtime) {
|
|
|
78186
78521
|
function getOrCreateScopedRuntime(listener, agentId, conversationId) {
|
|
78187
78522
|
return ensureConversationQueueRuntime(listener, getOrCreateConversationRuntime(listener, agentId, conversationId));
|
|
78188
78523
|
}
|
|
78524
|
+
function findFallbackRuntime(listener) {
|
|
78525
|
+
for (const cr of listener.conversationRuntimes.values()) {
|
|
78526
|
+
if (cr.queueRuntime) {
|
|
78527
|
+
return cr;
|
|
78528
|
+
}
|
|
78529
|
+
}
|
|
78530
|
+
return null;
|
|
78531
|
+
}
|
|
78189
78532
|
function resolveRuntimeForApprovalRequest(listener, requestId) {
|
|
78190
78533
|
if (!requestId) {
|
|
78191
78534
|
return null;
|
|
@@ -78319,6 +78662,7 @@ function createRuntime() {
|
|
|
78319
78662
|
};
|
|
78320
78663
|
}
|
|
78321
78664
|
function stopRuntime(runtime, suppressCallbacks) {
|
|
78665
|
+
setMessageQueueAdder(null);
|
|
78322
78666
|
runtime.intentionallyClosed = true;
|
|
78323
78667
|
clearRuntimeTimers(runtime);
|
|
78324
78668
|
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
@@ -78418,6 +78762,30 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
78418
78762
|
emitLoopStatusUpdate(socket, conversationRuntime, scope);
|
|
78419
78763
|
}
|
|
78420
78764
|
}
|
|
78765
|
+
runtime._unsubscribeSubagentState?.();
|
|
78766
|
+
runtime._unsubscribeSubagentState = subscribe2(() => {
|
|
78767
|
+
emitSubagentStateIfOpen(runtime);
|
|
78768
|
+
});
|
|
78769
|
+
runtime._unsubscribeSubagentStreamEvents?.();
|
|
78770
|
+
runtime._unsubscribeSubagentStreamEvents = subscribeToStreamEvents((subagentId, event) => {
|
|
78771
|
+
if (socket.readyState !== WebSocket4.OPEN)
|
|
78772
|
+
return;
|
|
78773
|
+
emitStreamDelta(socket, runtime, event, undefined, subagentId);
|
|
78774
|
+
});
|
|
78775
|
+
setMessageQueueAdder((queuedMessage) => {
|
|
78776
|
+
const targetRuntime = queuedMessage.agentId && queuedMessage.conversationId ? getOrCreateScopedRuntime(runtime, queuedMessage.agentId, queuedMessage.conversationId) : findFallbackRuntime(runtime);
|
|
78777
|
+
if (!targetRuntime?.queueRuntime) {
|
|
78778
|
+
return;
|
|
78779
|
+
}
|
|
78780
|
+
targetRuntime.queueRuntime.enqueue({
|
|
78781
|
+
kind: "task_notification",
|
|
78782
|
+
source: "task_notification",
|
|
78783
|
+
text: queuedMessage.text,
|
|
78784
|
+
agentId: queuedMessage.agentId ?? targetRuntime.agentId ?? undefined,
|
|
78785
|
+
conversationId: queuedMessage.conversationId ?? targetRuntime.conversationId
|
|
78786
|
+
});
|
|
78787
|
+
scheduleQueuePump(targetRuntime, socket, opts, processQueuedTurn);
|
|
78788
|
+
});
|
|
78421
78789
|
runtime.heartbeatInterval = setInterval(() => {
|
|
78422
78790
|
if (socket.readyState === WebSocket4.OPEN) {
|
|
78423
78791
|
socket.send(JSON.stringify({ type: "ping" }));
|
|
@@ -78622,8 +78990,15 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
78622
78990
|
if (isSearchFilesCommand(parsed)) {
|
|
78623
78991
|
(async () => {
|
|
78624
78992
|
await ensureFileIndex2();
|
|
78993
|
+
let searchDir = ".";
|
|
78994
|
+
if (parsed.cwd) {
|
|
78995
|
+
const rel = path22.relative(process.cwd(), parsed.cwd);
|
|
78996
|
+
if (rel && !rel.startsWith("..")) {
|
|
78997
|
+
searchDir = rel;
|
|
78998
|
+
}
|
|
78999
|
+
}
|
|
78625
79000
|
const files = searchFileIndex({
|
|
78626
|
-
searchDir
|
|
79001
|
+
searchDir,
|
|
78627
79002
|
pattern: parsed.query,
|
|
78628
79003
|
deep: true,
|
|
78629
79004
|
maxResults: parsed.max_results ?? 5
|
|
@@ -78721,10 +79096,10 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
78721
79096
|
const { getMemoryFilesystemRoot: getMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
78722
79097
|
const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memoryScanner(), exports_memoryScanner));
|
|
78723
79098
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
|
|
78724
|
-
const { existsSync:
|
|
78725
|
-
const { join:
|
|
79099
|
+
const { existsSync: existsSync20 } = await import("node:fs");
|
|
79100
|
+
const { join: join25 } = await import("node:path");
|
|
78726
79101
|
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
78727
|
-
const memfsInitialized =
|
|
79102
|
+
const memfsInitialized = existsSync20(join25(memoryRoot, ".git"));
|
|
78728
79103
|
if (!memfsInitialized) {
|
|
78729
79104
|
socket.send(JSON.stringify({
|
|
78730
79105
|
type: "list_memory_response",
|
|
@@ -78844,6 +79219,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
78844
79219
|
code,
|
|
78845
79220
|
reason: reason.toString()
|
|
78846
79221
|
});
|
|
79222
|
+
setMessageQueueAdder(null);
|
|
78847
79223
|
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
78848
79224
|
conversationRuntime.queuedMessagesByItemId.clear();
|
|
78849
79225
|
if (conversationRuntime.queueRuntime) {
|
|
@@ -78855,6 +79231,10 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
78855
79231
|
}
|
|
78856
79232
|
clearRuntimeTimers(runtime);
|
|
78857
79233
|
killAllTerminals();
|
|
79234
|
+
runtime._unsubscribeSubagentState?.();
|
|
79235
|
+
runtime._unsubscribeSubagentState = undefined;
|
|
79236
|
+
runtime._unsubscribeSubagentStreamEvents?.();
|
|
79237
|
+
runtime._unsubscribeSubagentStreamEvents = undefined;
|
|
78858
79238
|
runtime.socket = null;
|
|
78859
79239
|
for (const conversationRuntime of runtime.conversationRuntimes.values()) {
|
|
78860
79240
|
rejectPendingApprovalResolvers(conversationRuntime, "WebSocket disconnected");
|
|
@@ -79052,7 +79432,9 @@ function createLegacyTestRuntime() {
|
|
|
79052
79432
|
var __listenClientTestUtils;
|
|
79053
79433
|
var init_client4 = __esm(async () => {
|
|
79054
79434
|
init_fileIndex();
|
|
79435
|
+
init_messageQueueBridge();
|
|
79055
79436
|
init_planName();
|
|
79437
|
+
init_subagentState();
|
|
79056
79438
|
init_constants();
|
|
79057
79439
|
init_queueRuntime();
|
|
79058
79440
|
init_debug();
|
|
@@ -79165,22 +79547,22 @@ __export(exports_skills2, {
|
|
|
79165
79547
|
SKILLS_DIR: () => SKILLS_DIR2,
|
|
79166
79548
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
|
|
79167
79549
|
});
|
|
79168
|
-
import { existsSync as
|
|
79550
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
79169
79551
|
import { readdir as readdir6, readFile as readFile7, realpath as realpath4, stat as stat6 } from "node:fs/promises";
|
|
79170
|
-
import { dirname as
|
|
79552
|
+
import { dirname as dirname12, join as join29 } from "node:path";
|
|
79171
79553
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
79172
79554
|
function getBundledSkillsPath2() {
|
|
79173
|
-
const thisDir =
|
|
79555
|
+
const thisDir = dirname12(fileURLToPath8(import.meta.url));
|
|
79174
79556
|
if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
|
|
79175
|
-
return
|
|
79557
|
+
return join29(thisDir, "../skills/builtin");
|
|
79176
79558
|
}
|
|
79177
|
-
return
|
|
79559
|
+
return join29(thisDir, "skills");
|
|
79178
79560
|
}
|
|
79179
79561
|
function compareSkills2(a, b) {
|
|
79180
79562
|
return a.id.localeCompare(b.id) || a.source.localeCompare(b.source) || a.path.localeCompare(b.path);
|
|
79181
79563
|
}
|
|
79182
79564
|
function getAgentSkillsDir2(agentId) {
|
|
79183
|
-
return
|
|
79565
|
+
return join29(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
|
|
79184
79566
|
}
|
|
79185
79567
|
async function getBundledSkills2() {
|
|
79186
79568
|
const bundledPath = getBundledSkillsPath2();
|
|
@@ -79189,7 +79571,7 @@ async function getBundledSkills2() {
|
|
|
79189
79571
|
}
|
|
79190
79572
|
async function discoverSkillsFromDir2(skillsPath, source) {
|
|
79191
79573
|
const errors = [];
|
|
79192
|
-
if (!
|
|
79574
|
+
if (!existsSync22(skillsPath)) {
|
|
79193
79575
|
return { skills: [], errors: [] };
|
|
79194
79576
|
}
|
|
79195
79577
|
const skills = [];
|
|
@@ -79203,7 +79585,7 @@ async function discoverSkillsFromDir2(skillsPath, source) {
|
|
|
79203
79585
|
}
|
|
79204
79586
|
return { skills, errors };
|
|
79205
79587
|
}
|
|
79206
|
-
async function discoverSkills2(projectSkillsPath =
|
|
79588
|
+
async function discoverSkills2(projectSkillsPath = join29(process.cwd(), SKILLS_DIR2), agentId, options) {
|
|
79207
79589
|
const allErrors = [];
|
|
79208
79590
|
const skillsById = new Map;
|
|
79209
79591
|
const sourceSet = new Set(options?.sources ?? ALL_SKILL_SOURCES);
|
|
@@ -79258,7 +79640,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors, source, vi
|
|
|
79258
79640
|
try {
|
|
79259
79641
|
const entries = await readdir6(currentPath, { withFileTypes: true });
|
|
79260
79642
|
for (const entry of entries) {
|
|
79261
|
-
const fullPath =
|
|
79643
|
+
const fullPath = join29(currentPath, entry.name);
|
|
79262
79644
|
try {
|
|
79263
79645
|
let isDirectory = entry.isDirectory();
|
|
79264
79646
|
let isFile = entry.isFile();
|
|
@@ -79347,7 +79729,7 @@ ${lines.join(`
|
|
|
79347
79729
|
var SKILLS_DIR2 = ".skills", GLOBAL_SKILLS_DIR2;
|
|
79348
79730
|
var init_skills2 = __esm(() => {
|
|
79349
79731
|
init_skillSources();
|
|
79350
|
-
GLOBAL_SKILLS_DIR2 =
|
|
79732
|
+
GLOBAL_SKILLS_DIR2 = join29(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
|
|
79351
79733
|
});
|
|
79352
79734
|
|
|
79353
79735
|
// src/utils/fs.ts
|
|
@@ -79361,27 +79743,27 @@ __export(exports_fs, {
|
|
|
79361
79743
|
exists: () => exists2
|
|
79362
79744
|
});
|
|
79363
79745
|
import {
|
|
79364
|
-
existsSync as
|
|
79746
|
+
existsSync as existsSync23,
|
|
79365
79747
|
readFileSync as fsReadFileSync2,
|
|
79366
79748
|
writeFileSync as fsWriteFileSync2,
|
|
79367
|
-
mkdirSync as
|
|
79749
|
+
mkdirSync as mkdirSync16
|
|
79368
79750
|
} from "node:fs";
|
|
79369
|
-
import { dirname as
|
|
79751
|
+
import { dirname as dirname13 } from "node:path";
|
|
79370
79752
|
async function readFile8(path23) {
|
|
79371
79753
|
return fsReadFileSync2(path23, { encoding: "utf-8" });
|
|
79372
79754
|
}
|
|
79373
79755
|
async function writeFile5(path23, content) {
|
|
79374
|
-
const dir =
|
|
79375
|
-
if (!
|
|
79376
|
-
|
|
79756
|
+
const dir = dirname13(path23);
|
|
79757
|
+
if (!existsSync23(dir)) {
|
|
79758
|
+
mkdirSync16(dir, { recursive: true });
|
|
79377
79759
|
}
|
|
79378
79760
|
fsWriteFileSync2(path23, content, { encoding: "utf-8", flush: true });
|
|
79379
79761
|
}
|
|
79380
79762
|
function exists2(path23) {
|
|
79381
|
-
return
|
|
79763
|
+
return existsSync23(path23);
|
|
79382
79764
|
}
|
|
79383
79765
|
async function mkdir5(path23, options) {
|
|
79384
|
-
|
|
79766
|
+
mkdirSync16(path23, options);
|
|
79385
79767
|
}
|
|
79386
79768
|
async function readJsonFile(path23) {
|
|
79387
79769
|
const text = await readFile8(path23);
|
|
@@ -79701,7 +80083,7 @@ __export(exports_auto_update, {
|
|
|
79701
80083
|
import { execFile as execFile11 } from "node:child_process";
|
|
79702
80084
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
79703
80085
|
import { readdir as readdir7, rm as rm3 } from "node:fs/promises";
|
|
79704
|
-
import { join as
|
|
80086
|
+
import { join as join30 } from "node:path";
|
|
79705
80087
|
import { promisify as promisify11 } from "node:util";
|
|
79706
80088
|
function debugLog3(...args) {
|
|
79707
80089
|
if (DEBUG) {
|
|
@@ -79861,12 +80243,12 @@ async function getNpmGlobalPath() {
|
|
|
79861
80243
|
}
|
|
79862
80244
|
}
|
|
79863
80245
|
async function cleanupOrphanedDirs(globalPath) {
|
|
79864
|
-
const lettaAiDir =
|
|
80246
|
+
const lettaAiDir = join30(globalPath, "lib/node_modules/@letta-ai");
|
|
79865
80247
|
try {
|
|
79866
80248
|
const entries = await readdir7(lettaAiDir);
|
|
79867
80249
|
for (const entry of entries) {
|
|
79868
80250
|
if (entry.startsWith(".letta-code-")) {
|
|
79869
|
-
const orphanPath =
|
|
80251
|
+
const orphanPath = join30(lettaAiDir, entry);
|
|
79870
80252
|
debugLog3("Cleaning orphaned temp directory:", orphanPath);
|
|
79871
80253
|
await rm3(orphanPath, { recursive: true, force: true });
|
|
79872
80254
|
}
|
|
@@ -81380,7 +81762,7 @@ __export(exports_import, {
|
|
|
81380
81762
|
});
|
|
81381
81763
|
import { createReadStream } from "node:fs";
|
|
81382
81764
|
import { chmod, mkdir as mkdir6, readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
|
|
81383
|
-
import { dirname as
|
|
81765
|
+
import { dirname as dirname14, resolve as resolve26 } from "node:path";
|
|
81384
81766
|
async function importAgentFromFile(options) {
|
|
81385
81767
|
const client = await getClient2();
|
|
81386
81768
|
const resolvedPath = resolve26(options.filePath);
|
|
@@ -81439,7 +81821,7 @@ async function writeSkillFiles(skillDir, files) {
|
|
|
81439
81821
|
}
|
|
81440
81822
|
async function writeSkillFile(skillDir, filePath, content) {
|
|
81441
81823
|
const fullPath = resolve26(skillDir, filePath);
|
|
81442
|
-
await mkdir6(
|
|
81824
|
+
await mkdir6(dirname14(fullPath), { recursive: true });
|
|
81443
81825
|
await writeFile6(fullPath, content, "utf-8");
|
|
81444
81826
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
81445
81827
|
if (isScript) {
|
|
@@ -81492,7 +81874,7 @@ function parseRegistryHandle(handle) {
|
|
|
81492
81874
|
}
|
|
81493
81875
|
async function importAgentFromRegistry(options) {
|
|
81494
81876
|
const { tmpdir: tmpdir3 } = await import("node:os");
|
|
81495
|
-
const { join:
|
|
81877
|
+
const { join: join32 } = await import("node:path");
|
|
81496
81878
|
const { writeFile: writeFile7, unlink: unlink3 } = await import("node:fs/promises");
|
|
81497
81879
|
const { author, name } = parseRegistryHandle(options.handle);
|
|
81498
81880
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
|
|
@@ -81504,7 +81886,7 @@ async function importAgentFromRegistry(options) {
|
|
|
81504
81886
|
throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
|
|
81505
81887
|
}
|
|
81506
81888
|
const afContent = await response.text();
|
|
81507
|
-
const tempPath =
|
|
81889
|
+
const tempPath = join32(tmpdir3(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
81508
81890
|
await writeFile7(tempPath, afContent, "utf-8");
|
|
81509
81891
|
try {
|
|
81510
81892
|
const result = await importAgentFromFile({
|
|
@@ -82279,11 +82661,7 @@ In headless mode, use:
|
|
|
82279
82661
|
setConversationId2(conversationId);
|
|
82280
82662
|
if (!isSubagent) {
|
|
82281
82663
|
await settingsManager.loadLocalProjectSettings();
|
|
82282
|
-
settingsManager.
|
|
82283
|
-
settingsManager.setGlobalLastSession({
|
|
82284
|
-
agentId: agent.id,
|
|
82285
|
-
conversationId
|
|
82286
|
-
});
|
|
82664
|
+
settingsManager.persistSession(agent.id, conversationId);
|
|
82287
82665
|
}
|
|
82288
82666
|
setAgentContext2(agent.id, skillsDirectory, resolvedSkillSources);
|
|
82289
82667
|
const outputFormat = values["output-format"] || "text";
|
|
@@ -82580,27 +82958,39 @@ ${loadedContents.join(`
|
|
|
82580
82958
|
continue;
|
|
82581
82959
|
}
|
|
82582
82960
|
if (preStreamAction === "retry_conversation_busy") {
|
|
82583
|
-
|
|
82584
|
-
|
|
82585
|
-
|
|
82586
|
-
|
|
82587
|
-
|
|
82588
|
-
|
|
82589
|
-
|
|
82590
|
-
|
|
82591
|
-
|
|
82592
|
-
|
|
82593
|
-
|
|
82594
|
-
|
|
82595
|
-
|
|
82596
|
-
|
|
82597
|
-
|
|
82598
|
-
|
|
82599
|
-
|
|
82600
|
-
|
|
82961
|
+
const messageOtid = currentInput.map((item) => item.otid).find((v) => typeof v === "string");
|
|
82962
|
+
try {
|
|
82963
|
+
const client2 = await getClient2();
|
|
82964
|
+
stream2 = await client2.conversations.messages.stream(conversationId, {
|
|
82965
|
+
agent_id: conversationId === "default" ? agent?.id ?? undefined : undefined,
|
|
82966
|
+
otid: messageOtid ?? undefined,
|
|
82967
|
+
starting_after: 0,
|
|
82968
|
+
batch_size: 1000
|
|
82969
|
+
});
|
|
82970
|
+
conversationBusyRetries = 0;
|
|
82971
|
+
} catch {
|
|
82972
|
+
conversationBusyRetries += 1;
|
|
82973
|
+
const retryDelayMs = getRetryDelayMs({
|
|
82974
|
+
category: "conversation_busy",
|
|
82975
|
+
attempt: conversationBusyRetries
|
|
82976
|
+
});
|
|
82977
|
+
if (outputFormat === "stream-json") {
|
|
82978
|
+
const retryMsg = {
|
|
82979
|
+
type: "retry",
|
|
82980
|
+
reason: "error",
|
|
82981
|
+
attempt: conversationBusyRetries,
|
|
82982
|
+
max_attempts: CONVERSATION_BUSY_MAX_RETRIES,
|
|
82983
|
+
delay_ms: retryDelayMs,
|
|
82984
|
+
session_id: sessionId,
|
|
82985
|
+
uuid: `retry-conversation-busy-${randomUUID8()}`
|
|
82986
|
+
};
|
|
82987
|
+
console.log(JSON.stringify(retryMsg));
|
|
82988
|
+
} else {
|
|
82989
|
+
console.error(`Conversation is busy, waiting ${Math.round(retryDelayMs / 1000)}s and retrying...`);
|
|
82990
|
+
}
|
|
82991
|
+
await new Promise((resolve27) => setTimeout(resolve27, retryDelayMs));
|
|
82992
|
+
continue;
|
|
82601
82993
|
}
|
|
82602
|
-
await new Promise((resolve27) => setTimeout(resolve27, retryDelayMs));
|
|
82603
|
-
continue;
|
|
82604
82994
|
}
|
|
82605
82995
|
if (preStreamAction === "retry_transient") {
|
|
82606
82996
|
const attempt = llmApiErrorRetries + 1;
|
|
@@ -84464,9 +84854,9 @@ __export(exports_settings, {
|
|
|
84464
84854
|
getSetting: () => getSetting
|
|
84465
84855
|
});
|
|
84466
84856
|
import { homedir as homedir27 } from "node:os";
|
|
84467
|
-
import { join as
|
|
84857
|
+
import { join as join33 } from "node:path";
|
|
84468
84858
|
function getSettingsPath() {
|
|
84469
|
-
return
|
|
84859
|
+
return join33(homedir27(), ".letta", "settings.json");
|
|
84470
84860
|
}
|
|
84471
84861
|
async function loadSettings() {
|
|
84472
84862
|
const settingsPath = getSettingsPath();
|
|
@@ -84503,7 +84893,7 @@ async function getSetting(key) {
|
|
|
84503
84893
|
return settings[key];
|
|
84504
84894
|
}
|
|
84505
84895
|
function getProjectSettingsPath() {
|
|
84506
|
-
return
|
|
84896
|
+
return join33(process.cwd(), ".letta", "settings.local.json");
|
|
84507
84897
|
}
|
|
84508
84898
|
async function loadProjectSettings() {
|
|
84509
84899
|
const settingsPath = getProjectSettingsPath();
|
|
@@ -84521,7 +84911,7 @@ async function loadProjectSettings() {
|
|
|
84521
84911
|
}
|
|
84522
84912
|
async function saveProjectSettings(settings) {
|
|
84523
84913
|
const settingsPath = getProjectSettingsPath();
|
|
84524
|
-
const dirPath =
|
|
84914
|
+
const dirPath = join33(process.cwd(), ".letta");
|
|
84525
84915
|
try {
|
|
84526
84916
|
if (!exists(dirPath)) {
|
|
84527
84917
|
await mkdir(dirPath, { recursive: true });
|
|
@@ -101168,9 +101558,9 @@ function getFileEditHeader(toolName, toolArgs) {
|
|
|
101168
101558
|
const relPath = relative15(cwd2, filePath);
|
|
101169
101559
|
const displayPath = relPath.startsWith("..") ? filePath : relPath;
|
|
101170
101560
|
if (t === "write" || t === "write_file" || t === "writefile" || t === "write_file_gemini" || t === "writefilegemini") {
|
|
101171
|
-
const { existsSync:
|
|
101561
|
+
const { existsSync: existsSync26 } = __require("node:fs");
|
|
101172
101562
|
try {
|
|
101173
|
-
if (
|
|
101563
|
+
if (existsSync26(filePath)) {
|
|
101174
101564
|
return `Overwrite ${displayPath}?`;
|
|
101175
101565
|
}
|
|
101176
101566
|
} catch {}
|
|
@@ -101879,9 +102269,9 @@ function getHeaderText(fileEdit) {
|
|
|
101879
102269
|
const relPath = relative15(cwd2, fileEdit.filePath);
|
|
101880
102270
|
const displayPath = relPath.startsWith("..") ? fileEdit.filePath : relPath;
|
|
101881
102271
|
if (t === "write" || t === "write_file" || t === "writefile" || t === "write_file_gemini" || t === "writefilegemini") {
|
|
101882
|
-
const { existsSync:
|
|
102272
|
+
const { existsSync: existsSync26 } = __require("node:fs");
|
|
101883
102273
|
try {
|
|
101884
|
-
if (
|
|
102274
|
+
if (existsSync26(fileEdit.filePath)) {
|
|
101885
102275
|
return `Overwrite ${displayPath}?`;
|
|
101886
102276
|
}
|
|
101887
102277
|
} catch {}
|
|
@@ -103519,9 +103909,9 @@ html.dark .agent-name { color: var(--text-dim); }
|
|
|
103519
103909
|
var init_plan_viewer_template = () => {};
|
|
103520
103910
|
|
|
103521
103911
|
// src/web/generate-plan-viewer.ts
|
|
103522
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
103912
|
+
import { chmodSync as chmodSync2, existsSync as existsSync26, mkdirSync as mkdirSync19, writeFileSync as writeFileSync13 } from "node:fs";
|
|
103523
103913
|
import { homedir as homedir28 } from "node:os";
|
|
103524
|
-
import { join as
|
|
103914
|
+
import { join as join34 } from "node:path";
|
|
103525
103915
|
async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
103526
103916
|
const data = {
|
|
103527
103917
|
agent: { name: options?.agentName ?? "" },
|
|
@@ -103531,14 +103921,14 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
|
103531
103921
|
};
|
|
103532
103922
|
const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
103533
103923
|
const html = plan_viewer_template_default.replace("<!--LETTA_PLAN_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
103534
|
-
if (!
|
|
103535
|
-
|
|
103924
|
+
if (!existsSync26(VIEWERS_DIR)) {
|
|
103925
|
+
mkdirSync19(VIEWERS_DIR, { recursive: true, mode: 448 });
|
|
103536
103926
|
}
|
|
103537
103927
|
try {
|
|
103538
103928
|
chmodSync2(VIEWERS_DIR, 448);
|
|
103539
103929
|
} catch {}
|
|
103540
|
-
const filePath =
|
|
103541
|
-
|
|
103930
|
+
const filePath = join34(VIEWERS_DIR, "plan.html");
|
|
103931
|
+
writeFileSync13(filePath, html);
|
|
103542
103932
|
chmodSync2(filePath, 384);
|
|
103543
103933
|
const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
|
|
103544
103934
|
if (!skipOpen) {
|
|
@@ -103554,7 +103944,7 @@ async function generateAndOpenPlanViewer(planContent, planFilePath, options) {
|
|
|
103554
103944
|
var VIEWERS_DIR;
|
|
103555
103945
|
var init_generate_plan_viewer = __esm(() => {
|
|
103556
103946
|
init_plan_viewer_template();
|
|
103557
|
-
VIEWERS_DIR =
|
|
103947
|
+
VIEWERS_DIR = join34(homedir28(), ".letta", "viewers");
|
|
103558
103948
|
});
|
|
103559
103949
|
|
|
103560
103950
|
// src/cli/components/StaticPlanApproval.tsx
|
|
@@ -105599,9 +105989,9 @@ var init_pasteRegistry = __esm(() => {
|
|
|
105599
105989
|
|
|
105600
105990
|
// src/cli/helpers/clipboard.ts
|
|
105601
105991
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
105602
|
-
import { existsSync as
|
|
105992
|
+
import { existsSync as existsSync27, readFileSync as readFileSync12, statSync as statSync8, unlinkSync as unlinkSync8 } from "node:fs";
|
|
105603
105993
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
105604
|
-
import { basename as basename4, extname as extname5, isAbsolute as isAbsolute18, join as
|
|
105994
|
+
import { basename as basename4, extname as extname5, isAbsolute as isAbsolute18, join as join35, resolve as resolve27 } from "node:path";
|
|
105605
105995
|
function countLines2(text) {
|
|
105606
105996
|
return (text.match(/\r\n|\r|\n/g) || []).length + 1;
|
|
105607
105997
|
}
|
|
@@ -105651,7 +106041,7 @@ function translatePasteForImages(paste) {
|
|
|
105651
106041
|
if (!isAbsolute18(filePath))
|
|
105652
106042
|
filePath = resolve27(process.cwd(), filePath);
|
|
105653
106043
|
const ext3 = extname5(filePath || "").toLowerCase();
|
|
105654
|
-
if (IMAGE_EXTS.has(ext3) &&
|
|
106044
|
+
if (IMAGE_EXTS.has(ext3) && existsSync27(filePath) && statSync8(filePath).isFile()) {
|
|
105655
106045
|
const buf = readFileSync12(filePath);
|
|
105656
106046
|
const b64 = buf.toString("base64");
|
|
105657
106047
|
const mt = ext3 === ".png" ? "image/png" : ext3 === ".jpg" || ext3 === ".jpeg" ? "image/jpeg" : ext3 === ".gif" ? "image/gif" : ext3 === ".webp" ? "image/webp" : ext3 === ".bmp" ? "image/bmp" : ext3 === ".svg" ? "image/svg+xml" : ext3 === ".tif" || ext3 === ".tiff" ? "image/tiff" : ext3 === ".heic" ? "image/heic" : ext3 === ".heif" ? "image/heif" : ext3 === ".avif" ? "image/avif" : "application/octet-stream";
|
|
@@ -105669,7 +106059,7 @@ function translatePasteForImages(paste) {
|
|
|
105669
106059
|
function getClipboardImageToTempFile() {
|
|
105670
106060
|
if (process.platform !== "darwin")
|
|
105671
106061
|
return null;
|
|
105672
|
-
const tempPath =
|
|
106062
|
+
const tempPath = join35(tmpdir3(), `letta-clipboard-${Date.now()}.bin`);
|
|
105673
106063
|
try {
|
|
105674
106064
|
const jxa = `
|
|
105675
106065
|
ObjC.import('AppKit');
|
|
@@ -105692,11 +106082,11 @@ function getClipboardImageToTempFile() {
|
|
|
105692
106082
|
encoding: "utf8",
|
|
105693
106083
|
stdio: ["ignore", "pipe", "ignore"]
|
|
105694
106084
|
}).trim();
|
|
105695
|
-
if (!uti || !
|
|
106085
|
+
if (!uti || !existsSync27(tempPath))
|
|
105696
106086
|
return null;
|
|
105697
106087
|
return { tempPath, uti };
|
|
105698
106088
|
} catch {
|
|
105699
|
-
if (
|
|
106089
|
+
if (existsSync27(tempPath)) {
|
|
105700
106090
|
try {
|
|
105701
106091
|
unlinkSync8(tempPath);
|
|
105702
106092
|
} catch {}
|
|
@@ -105729,7 +106119,7 @@ async function tryImportClipboardImageMac() {
|
|
|
105729
106119
|
height: resized.height
|
|
105730
106120
|
};
|
|
105731
106121
|
} catch (err) {
|
|
105732
|
-
if (
|
|
106122
|
+
if (existsSync27(tempPath)) {
|
|
105733
106123
|
try {
|
|
105734
106124
|
unlinkSync8(tempPath);
|
|
105735
106125
|
} catch {}
|
|
@@ -106028,6 +106418,15 @@ function PasteAwareTextInput({
|
|
|
106028
106418
|
setNudgeCursorOffset(nextCaret);
|
|
106029
106419
|
caretOffsetRef.current = nextCaret;
|
|
106030
106420
|
};
|
|
106421
|
+
const moveCursorToStart = () => {
|
|
106422
|
+
setNudgeCursorOffset(0);
|
|
106423
|
+
caretOffsetRef.current = 0;
|
|
106424
|
+
};
|
|
106425
|
+
const moveCursorToEnd = () => {
|
|
106426
|
+
const endPos = displayValueRef.current.length;
|
|
106427
|
+
setNudgeCursorOffset(endPos);
|
|
106428
|
+
caretOffsetRef.current = endPos;
|
|
106429
|
+
};
|
|
106031
106430
|
const handleRawInput = (payload) => {
|
|
106032
106431
|
if (!focusRef.current)
|
|
106033
106432
|
return;
|
|
@@ -106052,6 +106451,14 @@ function PasteAwareTextInput({
|
|
|
106052
106451
|
insertNewlineAtCursor();
|
|
106053
106452
|
return;
|
|
106054
106453
|
}
|
|
106454
|
+
if (sequence === "\x1B[H" || sequence === "\x1B[1~" || sequence === "\x1BOH") {
|
|
106455
|
+
moveCursorToStart();
|
|
106456
|
+
return;
|
|
106457
|
+
}
|
|
106458
|
+
if (sequence === "\x1B[F" || sequence === "\x1B[4~" || sequence === "\x1BOF") {
|
|
106459
|
+
moveCursorToEnd();
|
|
106460
|
+
return;
|
|
106461
|
+
}
|
|
106055
106462
|
if (sequence === "\x1B[3~" || /^\x1b\[3;\d+~$/.test(sequence)) {
|
|
106056
106463
|
globalThis.__lettaForwardDeleteTimestamp = Date.now();
|
|
106057
106464
|
forwardDeleteAtCursor(caretOffsetRef.current);
|
|
@@ -106288,6 +106695,102 @@ var init_FeedbackDialog = __esm(async () => {
|
|
|
106288
106695
|
jsx_dev_runtime39 = __toESM(require_jsx_dev_runtime(), 1);
|
|
106289
106696
|
});
|
|
106290
106697
|
|
|
106698
|
+
// src/cli/commands/secret.ts
|
|
106699
|
+
async function handleSecretCommand(args) {
|
|
106700
|
+
const [subcommand, key, value] = args;
|
|
106701
|
+
switch (subcommand) {
|
|
106702
|
+
case "set": {
|
|
106703
|
+
if (!key) {
|
|
106704
|
+
return { output: "Usage: /secret set KEY value" };
|
|
106705
|
+
}
|
|
106706
|
+
if (!value) {
|
|
106707
|
+
return {
|
|
106708
|
+
output: `Usage: /secret set KEY value
|
|
106709
|
+
Provide a value for the secret.`
|
|
106710
|
+
};
|
|
106711
|
+
}
|
|
106712
|
+
const normalizedKey = key.toUpperCase();
|
|
106713
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(normalizedKey)) {
|
|
106714
|
+
return {
|
|
106715
|
+
output: `Invalid secret name '${key}'. Use uppercase letters, numbers, and underscores only. Must start with a letter or underscore.`
|
|
106716
|
+
};
|
|
106717
|
+
}
|
|
106718
|
+
try {
|
|
106719
|
+
await setSecretOnServer(normalizedKey, value);
|
|
106720
|
+
return { output: `Secret '$${normalizedKey}' set.` };
|
|
106721
|
+
} catch (error) {
|
|
106722
|
+
return {
|
|
106723
|
+
output: `Failed to set secret: ${error instanceof Error ? error.message : String(error)}`
|
|
106724
|
+
};
|
|
106725
|
+
}
|
|
106726
|
+
}
|
|
106727
|
+
case "list": {
|
|
106728
|
+
const names = listSecretNames();
|
|
106729
|
+
if (names.length === 0) {
|
|
106730
|
+
return {
|
|
106731
|
+
output: `No secrets stored.
|
|
106732
|
+
Use /secret set KEY value to add a secret.`
|
|
106733
|
+
};
|
|
106734
|
+
}
|
|
106735
|
+
const lines = names.map((n) => ` $${n}`);
|
|
106736
|
+
return {
|
|
106737
|
+
output: `Available secrets (${names.length}):
|
|
106738
|
+
${lines.join(`
|
|
106739
|
+
`)}
|
|
106740
|
+
|
|
106741
|
+
Use $SECRET_NAME in shell commands to reference them.`
|
|
106742
|
+
};
|
|
106743
|
+
}
|
|
106744
|
+
case "unset":
|
|
106745
|
+
case "delete":
|
|
106746
|
+
case "remove":
|
|
106747
|
+
case "rm": {
|
|
106748
|
+
if (!key) {
|
|
106749
|
+
return { output: "Usage: /secret unset KEY" };
|
|
106750
|
+
}
|
|
106751
|
+
const normalizedKey = key.toUpperCase();
|
|
106752
|
+
try {
|
|
106753
|
+
const deleted = await deleteSecretOnServer(normalizedKey);
|
|
106754
|
+
if (deleted) {
|
|
106755
|
+
return { output: `Secret '$${normalizedKey}' unset.` };
|
|
106756
|
+
}
|
|
106757
|
+
return {
|
|
106758
|
+
output: `Secret '$${normalizedKey}' not found.
|
|
106759
|
+
Use /secret list to see available secrets.`
|
|
106760
|
+
};
|
|
106761
|
+
} catch (error) {
|
|
106762
|
+
return {
|
|
106763
|
+
output: `Failed to unset secret: ${error instanceof Error ? error.message : String(error)}`
|
|
106764
|
+
};
|
|
106765
|
+
}
|
|
106766
|
+
}
|
|
106767
|
+
case undefined:
|
|
106768
|
+
case "":
|
|
106769
|
+
case "help": {
|
|
106770
|
+
return {
|
|
106771
|
+
output: `Secret management commands:
|
|
106772
|
+
|
|
106773
|
+
/secret set KEY value Set a secret (KEY is normalized to uppercase)
|
|
106774
|
+
/secret list List available secret names
|
|
106775
|
+
/secret unset KEY Unset a secret
|
|
106776
|
+
|
|
106777
|
+
Secrets are stored on the Letta server and available to the agent via /memory/system/secrets.md.
|
|
106778
|
+
The key must be all caps and can include underscores and numbers, but must start with a letter or underscore.
|
|
106779
|
+
Your agent can use $SECRET_NAME in shell commands and the value will be substituted at runtime, without the secret value being leaked into agent context.`
|
|
106780
|
+
};
|
|
106781
|
+
}
|
|
106782
|
+
default: {
|
|
106783
|
+
return {
|
|
106784
|
+
output: `Unknown subcommand '${subcommand}'.
|
|
106785
|
+
Use /secret help for usage.`
|
|
106786
|
+
};
|
|
106787
|
+
}
|
|
106788
|
+
}
|
|
106789
|
+
}
|
|
106790
|
+
var init_secret = __esm(async () => {
|
|
106791
|
+
await init_secretsStore();
|
|
106792
|
+
});
|
|
106793
|
+
|
|
106291
106794
|
// src/cli/utils/terminalKeybindingInstaller.ts
|
|
106292
106795
|
var exports_terminalKeybindingInstaller = {};
|
|
106293
106796
|
__export(exports_terminalKeybindingInstaller, {
|
|
@@ -106306,13 +106809,13 @@ __export(exports_terminalKeybindingInstaller, {
|
|
|
106306
106809
|
});
|
|
106307
106810
|
import {
|
|
106308
106811
|
copyFileSync,
|
|
106309
|
-
existsSync as
|
|
106310
|
-
mkdirSync as
|
|
106812
|
+
existsSync as existsSync28,
|
|
106813
|
+
mkdirSync as mkdirSync20,
|
|
106311
106814
|
readFileSync as readFileSync13,
|
|
106312
|
-
writeFileSync as
|
|
106815
|
+
writeFileSync as writeFileSync14
|
|
106313
106816
|
} from "node:fs";
|
|
106314
106817
|
import { homedir as homedir29, platform as platform5 } from "node:os";
|
|
106315
|
-
import { dirname as
|
|
106818
|
+
import { dirname as dirname15, join as join36 } from "node:path";
|
|
106316
106819
|
function detectTerminalType() {
|
|
106317
106820
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
106318
106821
|
return "cursor";
|
|
@@ -106344,16 +106847,16 @@ function getKeybindingsPath(terminal) {
|
|
|
106344
106847
|
}[terminal];
|
|
106345
106848
|
const os7 = platform5();
|
|
106346
106849
|
if (os7 === "darwin") {
|
|
106347
|
-
return
|
|
106850
|
+
return join36(homedir29(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
106348
106851
|
}
|
|
106349
106852
|
if (os7 === "win32") {
|
|
106350
106853
|
const appData = process.env.APPDATA;
|
|
106351
106854
|
if (!appData)
|
|
106352
106855
|
return null;
|
|
106353
|
-
return
|
|
106856
|
+
return join36(appData, appName, "User", "keybindings.json");
|
|
106354
106857
|
}
|
|
106355
106858
|
if (os7 === "linux") {
|
|
106356
|
-
return
|
|
106859
|
+
return join36(homedir29(), ".config", appName, "User", "keybindings.json");
|
|
106357
106860
|
}
|
|
106358
106861
|
return null;
|
|
106359
106862
|
}
|
|
@@ -106375,7 +106878,7 @@ function parseKeybindings(content) {
|
|
|
106375
106878
|
}
|
|
106376
106879
|
}
|
|
106377
106880
|
function keybindingExists(keybindingsPath) {
|
|
106378
|
-
if (!
|
|
106881
|
+
if (!existsSync28(keybindingsPath))
|
|
106379
106882
|
return false;
|
|
106380
106883
|
try {
|
|
106381
106884
|
const content = readFileSync13(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -106388,7 +106891,7 @@ function keybindingExists(keybindingsPath) {
|
|
|
106388
106891
|
}
|
|
106389
106892
|
}
|
|
106390
106893
|
function createBackup(keybindingsPath) {
|
|
106391
|
-
if (!
|
|
106894
|
+
if (!existsSync28(keybindingsPath))
|
|
106392
106895
|
return null;
|
|
106393
106896
|
const backupPath = `${keybindingsPath}.letta-backup`;
|
|
106394
106897
|
try {
|
|
@@ -106403,13 +106906,13 @@ function installKeybinding(keybindingsPath) {
|
|
|
106403
106906
|
if (keybindingExists(keybindingsPath)) {
|
|
106404
106907
|
return { success: true, alreadyExists: true };
|
|
106405
106908
|
}
|
|
106406
|
-
const parentDir =
|
|
106407
|
-
if (!
|
|
106408
|
-
|
|
106909
|
+
const parentDir = dirname15(keybindingsPath);
|
|
106910
|
+
if (!existsSync28(parentDir)) {
|
|
106911
|
+
mkdirSync20(parentDir, { recursive: true });
|
|
106409
106912
|
}
|
|
106410
106913
|
let keybindings = [];
|
|
106411
106914
|
let backupPath = null;
|
|
106412
|
-
if (
|
|
106915
|
+
if (existsSync28(keybindingsPath)) {
|
|
106413
106916
|
backupPath = createBackup(keybindingsPath);
|
|
106414
106917
|
const content = readFileSync13(keybindingsPath, { encoding: "utf-8" });
|
|
106415
106918
|
const parsed = parseKeybindings(content);
|
|
@@ -106424,7 +106927,7 @@ function installKeybinding(keybindingsPath) {
|
|
|
106424
106927
|
keybindings.push(SHIFT_ENTER_KEYBINDING);
|
|
106425
106928
|
const newContent = `${JSON.stringify(keybindings, null, 2)}
|
|
106426
106929
|
`;
|
|
106427
|
-
|
|
106930
|
+
writeFileSync14(keybindingsPath, newContent, { encoding: "utf-8" });
|
|
106428
106931
|
return {
|
|
106429
106932
|
success: true,
|
|
106430
106933
|
backupPath: backupPath ?? undefined
|
|
@@ -106439,7 +106942,7 @@ function installKeybinding(keybindingsPath) {
|
|
|
106439
106942
|
}
|
|
106440
106943
|
function removeKeybinding(keybindingsPath) {
|
|
106441
106944
|
try {
|
|
106442
|
-
if (!
|
|
106945
|
+
if (!existsSync28(keybindingsPath)) {
|
|
106443
106946
|
return { success: true };
|
|
106444
106947
|
}
|
|
106445
106948
|
const content = readFileSync13(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -106453,7 +106956,7 @@ function removeKeybinding(keybindingsPath) {
|
|
|
106453
106956
|
const filtered = keybindings.filter((kb) => !(kb.key?.toLowerCase() === "shift+enter" && kb.command === "workbench.action.terminal.sendSequence" && kb.when?.includes("terminalFocus")));
|
|
106454
106957
|
const newContent = `${JSON.stringify(filtered, null, 2)}
|
|
106455
106958
|
`;
|
|
106456
|
-
|
|
106959
|
+
writeFileSync14(keybindingsPath, newContent, { encoding: "utf-8" });
|
|
106457
106960
|
return { success: true };
|
|
106458
106961
|
} catch (error) {
|
|
106459
106962
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -106506,17 +107009,17 @@ function getWezTermConfigPath() {
|
|
|
106506
107009
|
}
|
|
106507
107010
|
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
106508
107011
|
if (xdgConfig) {
|
|
106509
|
-
const xdgPath =
|
|
106510
|
-
if (
|
|
107012
|
+
const xdgPath = join36(xdgConfig, "wezterm", "wezterm.lua");
|
|
107013
|
+
if (existsSync28(xdgPath))
|
|
106511
107014
|
return xdgPath;
|
|
106512
107015
|
}
|
|
106513
|
-
const configPath =
|
|
106514
|
-
if (
|
|
107016
|
+
const configPath = join36(homedir29(), ".config", "wezterm", "wezterm.lua");
|
|
107017
|
+
if (existsSync28(configPath))
|
|
106515
107018
|
return configPath;
|
|
106516
|
-
return
|
|
107019
|
+
return join36(homedir29(), ".wezterm.lua");
|
|
106517
107020
|
}
|
|
106518
107021
|
function wezTermDeleteFixExists(configPath) {
|
|
106519
|
-
if (!
|
|
107022
|
+
if (!existsSync28(configPath))
|
|
106520
107023
|
return false;
|
|
106521
107024
|
try {
|
|
106522
107025
|
const content = readFileSync13(configPath, { encoding: "utf-8" });
|
|
@@ -106533,7 +107036,7 @@ function installWezTermDeleteFix() {
|
|
|
106533
107036
|
}
|
|
106534
107037
|
let content = "";
|
|
106535
107038
|
let backupPath = null;
|
|
106536
|
-
if (
|
|
107039
|
+
if (existsSync28(configPath)) {
|
|
106537
107040
|
backupPath = `${configPath}.letta-backup`;
|
|
106538
107041
|
copyFileSync(configPath, backupPath);
|
|
106539
107042
|
content = readFileSync13(configPath, { encoding: "utf-8" });
|
|
@@ -106562,11 +107065,11 @@ return config`);
|
|
|
106562
107065
|
${WEZTERM_DELETE_FIX}
|
|
106563
107066
|
`;
|
|
106564
107067
|
}
|
|
106565
|
-
const parentDir =
|
|
106566
|
-
if (!
|
|
106567
|
-
|
|
107068
|
+
const parentDir = dirname15(configPath);
|
|
107069
|
+
if (!existsSync28(parentDir)) {
|
|
107070
|
+
mkdirSync20(parentDir, { recursive: true });
|
|
106568
107071
|
}
|
|
106569
|
-
|
|
107072
|
+
writeFileSync14(configPath, content, { encoding: "utf-8" });
|
|
106570
107073
|
return {
|
|
106571
107074
|
success: true,
|
|
106572
107075
|
backupPath: backupPath ?? undefined
|
|
@@ -106639,7 +107142,8 @@ async function executeCommand(input) {
|
|
|
106639
107142
|
}
|
|
106640
107143
|
}
|
|
106641
107144
|
var commands;
|
|
106642
|
-
var init_registry = __esm(() => {
|
|
107145
|
+
var init_registry = __esm(async () => {
|
|
107146
|
+
await init_secret();
|
|
106643
107147
|
commands = {
|
|
106644
107148
|
"/agents": {
|
|
106645
107149
|
desc: "Browse agents (pinned, Letta Code, all)",
|
|
@@ -106774,6 +107278,14 @@ var init_registry = __esm(() => {
|
|
|
106774
107278
|
return "Starting new conversation...";
|
|
106775
107279
|
}
|
|
106776
107280
|
},
|
|
107281
|
+
"/fork": {
|
|
107282
|
+
desc: "Fork the current conversation",
|
|
107283
|
+
order: 20.5,
|
|
107284
|
+
noArgs: true,
|
|
107285
|
+
handler: () => {
|
|
107286
|
+
return "Forking conversation...";
|
|
107287
|
+
}
|
|
107288
|
+
},
|
|
106777
107289
|
"/pin": {
|
|
106778
107290
|
desc: "Pin current agent globally, or use -l for local only",
|
|
106779
107291
|
order: 22,
|
|
@@ -106849,6 +107361,15 @@ var init_registry = __esm(() => {
|
|
|
106849
107361
|
return "Opening MCP server manager...";
|
|
106850
107362
|
}
|
|
106851
107363
|
},
|
|
107364
|
+
"/secret": {
|
|
107365
|
+
desc: "Manage secrets for shell commands",
|
|
107366
|
+
order: 33,
|
|
107367
|
+
args: "<set|list|unset> [key] [value]",
|
|
107368
|
+
handler: async (args) => {
|
|
107369
|
+
const result = await handleSecretCommand(args);
|
|
107370
|
+
return result.output;
|
|
107371
|
+
}
|
|
107372
|
+
},
|
|
106852
107373
|
"/usage": {
|
|
106853
107374
|
desc: "Show session usage statistics and balance",
|
|
106854
107375
|
order: 33,
|
|
@@ -107110,9 +107631,9 @@ __export(exports_custom, {
|
|
|
107110
107631
|
GLOBAL_COMMANDS_DIR: () => GLOBAL_COMMANDS_DIR,
|
|
107111
107632
|
COMMANDS_DIR: () => COMMANDS_DIR
|
|
107112
107633
|
});
|
|
107113
|
-
import { existsSync as
|
|
107634
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
107114
107635
|
import { readdir as readdir8, readFile as readFile10 } from "node:fs/promises";
|
|
107115
|
-
import { basename as basename5, dirname as
|
|
107636
|
+
import { basename as basename5, dirname as dirname16, join as join37 } from "node:path";
|
|
107116
107637
|
async function getCustomCommands() {
|
|
107117
107638
|
if (cachedCommands !== null) {
|
|
107118
107639
|
return cachedCommands;
|
|
@@ -107123,7 +107644,7 @@ async function getCustomCommands() {
|
|
|
107123
107644
|
function refreshCustomCommands() {
|
|
107124
107645
|
cachedCommands = null;
|
|
107125
107646
|
}
|
|
107126
|
-
async function discoverCustomCommands(projectPath =
|
|
107647
|
+
async function discoverCustomCommands(projectPath = join37(process.cwd(), COMMANDS_DIR)) {
|
|
107127
107648
|
const commandsById = new Map;
|
|
107128
107649
|
const userCommands = await discoverFromDirectory(GLOBAL_COMMANDS_DIR, "user");
|
|
107129
107650
|
for (const cmd of userCommands) {
|
|
@@ -107144,7 +107665,7 @@ async function discoverCustomCommands(projectPath = join36(process.cwd(), COMMAN
|
|
|
107144
107665
|
return result;
|
|
107145
107666
|
}
|
|
107146
107667
|
async function discoverFromDirectory(dirPath, source2) {
|
|
107147
|
-
if (!
|
|
107668
|
+
if (!existsSync29(dirPath)) {
|
|
107148
107669
|
return [];
|
|
107149
107670
|
}
|
|
107150
107671
|
const commands2 = [];
|
|
@@ -107155,7 +107676,7 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
|
|
|
107155
107676
|
try {
|
|
107156
107677
|
const entries = await readdir8(currentPath, { withFileTypes: true });
|
|
107157
107678
|
for (const entry of entries) {
|
|
107158
|
-
const fullPath =
|
|
107679
|
+
const fullPath = join37(currentPath, entry.name);
|
|
107159
107680
|
if (entry.isDirectory()) {
|
|
107160
107681
|
await findCommandFiles(fullPath, rootPath, commands2, source2);
|
|
107161
107682
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -107173,7 +107694,7 @@ async function parseCommandFile(filePath, rootPath, source2) {
|
|
|
107173
107694
|
const content = await readFile10(filePath, "utf-8");
|
|
107174
107695
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
107175
107696
|
const id = basename5(filePath, ".md");
|
|
107176
|
-
const relativePath =
|
|
107697
|
+
const relativePath = dirname16(filePath).slice(rootPath.length);
|
|
107177
107698
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
107178
107699
|
let description = getStringField(frontmatter, "description");
|
|
107179
107700
|
if (!description) {
|
|
@@ -107240,7 +107761,7 @@ async function findCustomCommand(commandName) {
|
|
|
107240
107761
|
}
|
|
107241
107762
|
var COMMANDS_DIR = ".commands", GLOBAL_COMMANDS_DIR, cachedCommands = null;
|
|
107242
107763
|
var init_custom = __esm(() => {
|
|
107243
|
-
GLOBAL_COMMANDS_DIR =
|
|
107764
|
+
GLOBAL_COMMANDS_DIR = join37(process.env.HOME || process.env.USERPROFILE || "~", ".letta/commands");
|
|
107244
107765
|
});
|
|
107245
107766
|
|
|
107246
107767
|
// src/cli/components/HelpDialog.tsx
|
|
@@ -107509,10 +108030,10 @@ function HelpDialog({ onClose }) {
|
|
|
107509
108030
|
var import_react63, jsx_dev_runtime40, PAGE_SIZE = 10, HELP_TABS;
|
|
107510
108031
|
var init_HelpDialog = __esm(async () => {
|
|
107511
108032
|
init_version();
|
|
107512
|
-
init_registry();
|
|
107513
108033
|
init_colors();
|
|
107514
108034
|
await __promiseAll([
|
|
107515
108035
|
init_build2(),
|
|
108036
|
+
init_registry(),
|
|
107516
108037
|
init_Text2()
|
|
107517
108038
|
]);
|
|
107518
108039
|
import_react63 = __toESM(require_react(), 1);
|
|
@@ -110160,7 +110681,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
110160
110681
|
|
|
110161
110682
|
// src/cli/helpers/fileSearch.ts
|
|
110162
110683
|
import { readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
|
|
110163
|
-
import { join as
|
|
110684
|
+
import { join as join38, relative as relative15, resolve as resolve29 } from "node:path";
|
|
110164
110685
|
function searchDirectoryRecursive(dir, pattern, maxResults = 200, results = [], depth = 0, maxDepth = 10, lowerPattern = pattern.toLowerCase()) {
|
|
110165
110686
|
if (results.length >= maxResults || depth >= maxDepth) {
|
|
110166
110687
|
return results;
|
|
@@ -110169,7 +110690,7 @@ function searchDirectoryRecursive(dir, pattern, maxResults = 200, results = [],
|
|
|
110169
110690
|
const entries = readdirSync12(dir);
|
|
110170
110691
|
for (const entry of entries) {
|
|
110171
110692
|
try {
|
|
110172
|
-
const fullPath =
|
|
110693
|
+
const fullPath = join38(dir, entry);
|
|
110173
110694
|
const relativePath = relative15(process.cwd(), fullPath);
|
|
110174
110695
|
if (shouldHardExcludeEntry(entry)) {
|
|
110175
110696
|
continue;
|
|
@@ -110247,7 +110768,7 @@ async function searchFiles(query, deep = false) {
|
|
|
110247
110768
|
const matchingEntries = entries.filter((entry) => !shouldHardExcludeEntry(entry) && (searchPattern.length === 0 || entry.toLowerCase().includes(lowerPattern)));
|
|
110248
110769
|
for (const entry of matchingEntries.slice(0, 50)) {
|
|
110249
110770
|
try {
|
|
110250
|
-
const fullPath =
|
|
110771
|
+
const fullPath = join38(searchDir, entry);
|
|
110251
110772
|
const stats = statSync9(fullPath);
|
|
110252
110773
|
const relativePath = relative15(process.cwd(), fullPath);
|
|
110253
110774
|
results.push({
|
|
@@ -110749,10 +111270,10 @@ function SlashCommandAutocomplete({
|
|
|
110749
111270
|
}
|
|
110750
111271
|
var import_react69, jsx_dev_runtime46, VISIBLE_COMMANDS = 7, CMD_COL_WIDTH = 14, _allCommands;
|
|
110751
111272
|
var init_SlashCommandAutocomplete = __esm(async () => {
|
|
110752
|
-
init_registry();
|
|
110753
111273
|
init_useTerminalWidth();
|
|
110754
111274
|
await __promiseAll([
|
|
110755
111275
|
init_settings_manager(),
|
|
111276
|
+
init_registry(),
|
|
110756
111277
|
init_useAutocompleteNavigation(),
|
|
110757
111278
|
init_Autocomplete(),
|
|
110758
111279
|
init_Text2()
|
|
@@ -111148,6 +111669,7 @@ function Input({
|
|
|
111148
111669
|
agentName,
|
|
111149
111670
|
currentModel,
|
|
111150
111671
|
currentModelProvider,
|
|
111672
|
+
hasTemporaryModelOverride = false,
|
|
111151
111673
|
currentReasoningEffort,
|
|
111152
111674
|
messageQueue,
|
|
111153
111675
|
onEnterQueueEditMode,
|
|
@@ -111749,6 +112271,7 @@ function Input({
|
|
|
111749
112271
|
currentReasoningEffort,
|
|
111750
112272
|
isOpenAICodexProvider: currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
|
|
111751
112273
|
isByokProvider: currentModelProvider?.startsWith("lc-") || currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
|
|
112274
|
+
hasTemporaryModelOverride,
|
|
111752
112275
|
hideFooter,
|
|
111753
112276
|
rightColumnWidth: footerRightColumnWidth,
|
|
111754
112277
|
statusLineText,
|
|
@@ -111793,6 +112316,7 @@ function Input({
|
|
|
111793
112316
|
currentModel,
|
|
111794
112317
|
currentReasoningEffort,
|
|
111795
112318
|
currentModelProvider,
|
|
112319
|
+
hasTemporaryModelOverride,
|
|
111796
112320
|
hideFooter,
|
|
111797
112321
|
footerRightColumnWidth,
|
|
111798
112322
|
reserveInputSpace,
|
|
@@ -111888,6 +112412,7 @@ var init_InputRich = __esm(async () => {
|
|
|
111888
112412
|
currentReasoningEffort,
|
|
111889
112413
|
isOpenAICodexProvider,
|
|
111890
112414
|
isByokProvider,
|
|
112415
|
+
hasTemporaryModelOverride,
|
|
111891
112416
|
hideFooter,
|
|
111892
112417
|
rightColumnWidth,
|
|
111893
112418
|
statusLineText,
|
|
@@ -111936,11 +112461,12 @@ var init_InputRich = __esm(async () => {
|
|
|
111936
112461
|
const displayAgentName = truncateEnd(agentName || "Unnamed", maxAgentChars);
|
|
111937
112462
|
const reasoningTag = getReasoningEffortTag(currentReasoningEffort);
|
|
111938
112463
|
const byokExtraChars = isByokProvider ? 2 : 0;
|
|
111939
|
-
const
|
|
112464
|
+
const tempOverrideExtraChars = hasTemporaryModelOverride ? 2 : 0;
|
|
112465
|
+
const baseReservedChars = displayAgentName.length + byokExtraChars + tempOverrideExtraChars + 4;
|
|
111940
112466
|
const modelWithReasoning = (currentModel ?? "unknown") + (reasoningTag ? ` (${reasoningTag})` : "");
|
|
111941
112467
|
const maxModelChars = Math.max(8, rightColumnWidth - baseReservedChars);
|
|
111942
112468
|
const displayModel = truncateEnd(modelWithReasoning, maxModelChars);
|
|
111943
|
-
const rightTextLength = displayAgentName.length + displayModel.length + byokExtraChars + 3;
|
|
112469
|
+
const rightTextLength = displayAgentName.length + displayModel.length + byokExtraChars + tempOverrideExtraChars + 3;
|
|
111944
112470
|
const rightPrefixSpaces = Math.max(0, rightColumnWidth - rightTextLength);
|
|
111945
112471
|
const bgIndicatorWidth = backgroundAgents.length > 0 ? 3 + bgAgentParts.reduce((acc, p, i) => acc + (i > 0 ? 3 : 0) + p.typeLabel.length + 1 + p.elapsed.length + 2, 0) + 3 : 0;
|
|
111946
112472
|
const effectiveRightWidth = backgroundAgents.length > 0 ? Math.max(rightColumnWidth, bgIndicatorWidth + rightTextLength) : rightColumnWidth;
|
|
@@ -111953,9 +112479,19 @@ var init_InputRich = __esm(async () => {
|
|
|
111953
112479
|
parts.push(source_default.dim(" "));
|
|
111954
112480
|
parts.push(isOpenAICodexProvider ? source_default.hex("#74AA9C")("▲") : source_default.yellow("▲"));
|
|
111955
112481
|
}
|
|
112482
|
+
if (hasTemporaryModelOverride) {
|
|
112483
|
+
parts.push(source_default.dim(" "));
|
|
112484
|
+
parts.push(source_default.yellow("▲"));
|
|
112485
|
+
}
|
|
111956
112486
|
parts.push(source_default.dim("]"));
|
|
111957
112487
|
return parts.join("");
|
|
111958
|
-
}, [
|
|
112488
|
+
}, [
|
|
112489
|
+
displayAgentName,
|
|
112490
|
+
displayModel,
|
|
112491
|
+
isByokProvider,
|
|
112492
|
+
isOpenAICodexProvider,
|
|
112493
|
+
hasTemporaryModelOverride
|
|
112494
|
+
]);
|
|
111959
112495
|
const rightLabel = import_react73.useMemo(() => " ".repeat(rightPrefixSpaces) + rightLabelCore, [rightPrefixSpaces, rightLabelCore]);
|
|
111960
112496
|
return /* @__PURE__ */ jsx_dev_runtime50.jsxDEV(Box_default, {
|
|
111961
112497
|
flexDirection: "row",
|
|
@@ -112299,15 +112835,15 @@ var init_InputRich = __esm(async () => {
|
|
|
112299
112835
|
// src/cli/commands/install-github-app.ts
|
|
112300
112836
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
112301
112837
|
import {
|
|
112302
|
-
existsSync as
|
|
112303
|
-
mkdirSync as
|
|
112838
|
+
existsSync as existsSync30,
|
|
112839
|
+
mkdirSync as mkdirSync21,
|
|
112304
112840
|
mkdtempSync,
|
|
112305
112841
|
readFileSync as readFileSync14,
|
|
112306
112842
|
rmSync as rmSync3,
|
|
112307
|
-
writeFileSync as
|
|
112843
|
+
writeFileSync as writeFileSync15
|
|
112308
112844
|
} from "node:fs";
|
|
112309
112845
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
112310
|
-
import { dirname as
|
|
112846
|
+
import { dirname as dirname17, join as join39 } from "node:path";
|
|
112311
112847
|
function runCommand(command, args, cwd2, input) {
|
|
112312
112848
|
try {
|
|
112313
112849
|
return execFileSync4(command, args, {
|
|
@@ -112541,8 +113077,8 @@ async function createLettaAgent(apiKey, name) {
|
|
|
112541
113077
|
return { id: data.id, name: data.name };
|
|
112542
113078
|
}
|
|
112543
113079
|
function cloneRepoToTemp(repo) {
|
|
112544
|
-
const tempDir = mkdtempSync(
|
|
112545
|
-
const repoDir =
|
|
113080
|
+
const tempDir = mkdtempSync(join39(tmpdir4(), "letta-install-github-app-"));
|
|
113081
|
+
const repoDir = join39(tempDir, "repo");
|
|
112546
113082
|
runCommand("gh", ["repo", "clone", repo, repoDir, "--", "--depth=1"]);
|
|
112547
113083
|
return { tempDir, repoDir };
|
|
112548
113084
|
}
|
|
@@ -112553,19 +113089,19 @@ function runGit5(args, cwd2) {
|
|
|
112553
113089
|
return runCommand("git", args, cwd2);
|
|
112554
113090
|
}
|
|
112555
113091
|
function writeWorkflow(repoDir, workflowPath, content) {
|
|
112556
|
-
const absolutePath =
|
|
112557
|
-
if (!
|
|
112558
|
-
|
|
113092
|
+
const absolutePath = join39(repoDir, workflowPath);
|
|
113093
|
+
if (!existsSync30(dirname17(absolutePath))) {
|
|
113094
|
+
mkdirSync21(dirname17(absolutePath), { recursive: true });
|
|
112559
113095
|
}
|
|
112560
113096
|
const next = `${content.trimEnd()}
|
|
112561
113097
|
`;
|
|
112562
|
-
if (
|
|
113098
|
+
if (existsSync30(absolutePath)) {
|
|
112563
113099
|
const previous = readFileSync14(absolutePath, "utf8");
|
|
112564
113100
|
if (previous === next) {
|
|
112565
113101
|
return false;
|
|
112566
113102
|
}
|
|
112567
113103
|
}
|
|
112568
|
-
|
|
113104
|
+
writeFileSync15(absolutePath, next, "utf8");
|
|
112569
113105
|
return true;
|
|
112570
113106
|
}
|
|
112571
113107
|
function getDefaultBaseBranch(repoDir) {
|
|
@@ -116460,9 +116996,9 @@ __export(exports_generate_memory_viewer, {
|
|
|
116460
116996
|
generateAndOpenMemoryViewer: () => generateAndOpenMemoryViewer
|
|
116461
116997
|
});
|
|
116462
116998
|
import { execFile as execFileCb4 } from "node:child_process";
|
|
116463
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
116999
|
+
import { chmodSync as chmodSync3, existsSync as existsSync31, mkdirSync as mkdirSync22, writeFileSync as writeFileSync16 } from "node:fs";
|
|
116464
117000
|
import { homedir as homedir31 } from "node:os";
|
|
116465
|
-
import { join as
|
|
117001
|
+
import { join as join40 } from "node:path";
|
|
116466
117002
|
import { promisify as promisify12 } from "node:util";
|
|
116467
117003
|
async function runGitSafe(cwd2, args) {
|
|
116468
117004
|
try {
|
|
@@ -116745,14 +117281,14 @@ async function generateAndOpenMemoryViewer(agentId, options) {
|
|
|
116745
117281
|
}
|
|
116746
117282
|
const jsonPayload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
116747
117283
|
const html = memory_viewer_template_default.replace("<!--LETTA_DATA_PLACEHOLDER-->", () => jsonPayload);
|
|
116748
|
-
if (!
|
|
116749
|
-
|
|
117284
|
+
if (!existsSync31(VIEWERS_DIR2)) {
|
|
117285
|
+
mkdirSync22(VIEWERS_DIR2, { recursive: true, mode: 448 });
|
|
116750
117286
|
}
|
|
116751
117287
|
try {
|
|
116752
117288
|
chmodSync3(VIEWERS_DIR2, 448);
|
|
116753
117289
|
} catch {}
|
|
116754
|
-
const filePath =
|
|
116755
|
-
|
|
117290
|
+
const filePath = join40(VIEWERS_DIR2, `memory-${encodeURIComponent(agentId)}.html`);
|
|
117291
|
+
writeFileSync16(filePath, html);
|
|
116756
117292
|
chmodSync3(filePath, 384);
|
|
116757
117293
|
const skipOpen = Boolean(process.env.TMUX) || Boolean(process.env.SSH_CONNECTION) || Boolean(process.env.SSH_TTY);
|
|
116758
117294
|
if (!skipOpen) {
|
|
@@ -116775,12 +117311,12 @@ var init_generate_memory_viewer = __esm(async () => {
|
|
|
116775
117311
|
init_memoryGit()
|
|
116776
117312
|
]);
|
|
116777
117313
|
execFile12 = promisify12(execFileCb4);
|
|
116778
|
-
VIEWERS_DIR2 =
|
|
117314
|
+
VIEWERS_DIR2 = join40(homedir31(), ".letta", "viewers");
|
|
116779
117315
|
REFLECTION_PATTERN = /\(reflection\)|🔮|reflection:/i;
|
|
116780
117316
|
});
|
|
116781
117317
|
|
|
116782
117318
|
// src/cli/components/MemfsTreeViewer.tsx
|
|
116783
|
-
import { existsSync as
|
|
117319
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
116784
117320
|
function renderTreePrefix(node) {
|
|
116785
117321
|
let prefix = "";
|
|
116786
117322
|
for (let i = 0;i < node.depth; i++) {
|
|
@@ -116806,7 +117342,7 @@ function MemfsTreeViewer({
|
|
|
116806
117342
|
const [status, setStatus] = import_react77.useState(null);
|
|
116807
117343
|
const statusTimerRef = import_react77.useRef(null);
|
|
116808
117344
|
const memoryRoot = getMemoryFilesystemRoot(agentId);
|
|
116809
|
-
const memoryExists =
|
|
117345
|
+
const memoryExists = existsSync32(memoryRoot);
|
|
116810
117346
|
const hasGitRepo = import_react77.useMemo(() => isGitRepo(agentId), [agentId]);
|
|
116811
117347
|
function showStatus(msg, durationMs) {
|
|
116812
117348
|
if (statusTimerRef.current)
|
|
@@ -117599,6 +118135,9 @@ function truncateText4(text, maxWidth) {
|
|
|
117599
118135
|
return text;
|
|
117600
118136
|
return `${text.slice(0, maxWidth - 3)}...`;
|
|
117601
118137
|
}
|
|
118138
|
+
function escapeRegExp(text) {
|
|
118139
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, (match3) => `\\${match3}`);
|
|
118140
|
+
}
|
|
117602
118141
|
function getMessageText(msg) {
|
|
117603
118142
|
if ("content" in msg) {
|
|
117604
118143
|
const content = msg.content;
|
|
@@ -117629,6 +118168,34 @@ function getMessageText(msg) {
|
|
|
117629
118168
|
}
|
|
117630
118169
|
return `[${msg.message_type || "unknown"}]`;
|
|
117631
118170
|
}
|
|
118171
|
+
function HighlightedText({ text, query }) {
|
|
118172
|
+
if (!query.trim())
|
|
118173
|
+
return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118174
|
+
children: text
|
|
118175
|
+
}, undefined, false, undefined, this);
|
|
118176
|
+
const highlightTerms = [
|
|
118177
|
+
...new Set(query.trim().split(/\s+/).filter(Boolean))
|
|
118178
|
+
].sort((a, b) => b.length - a.length);
|
|
118179
|
+
if (highlightTerms.length === 0)
|
|
118180
|
+
return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118181
|
+
children: text
|
|
118182
|
+
}, undefined, false, undefined, this);
|
|
118183
|
+
const parts = text.split(new RegExp(`(${highlightTerms.map(escapeRegExp).join("|")})`, "gi"));
|
|
118184
|
+
let offset = 0;
|
|
118185
|
+
return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118186
|
+
children: parts.map((part) => {
|
|
118187
|
+
const key = `${offset}-${part}`;
|
|
118188
|
+
offset += part.length;
|
|
118189
|
+
return highlightTerms.some((term) => part.toLowerCase() === term.toLowerCase()) ? /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118190
|
+
bold: true,
|
|
118191
|
+
color: colors.selector.itemHighlighted,
|
|
118192
|
+
children: part
|
|
118193
|
+
}, key, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118194
|
+
children: part
|
|
118195
|
+
}, key, false, undefined, this);
|
|
118196
|
+
})
|
|
118197
|
+
}, undefined, false, undefined, this);
|
|
118198
|
+
}
|
|
117632
118199
|
function MessageSearch({
|
|
117633
118200
|
onClose,
|
|
117634
118201
|
initialQuery,
|
|
@@ -117856,24 +118423,23 @@ function MessageSearch({
|
|
|
117856
118423
|
const isAssistant = msgType === "assistant_message" || msgType === "reasoning_message";
|
|
117857
118424
|
const typeLabel = isAssistant ? "Agent message" : "User message";
|
|
117858
118425
|
const timestamp = formatLocalTime(msgData.created_at || msgData.date);
|
|
117859
|
-
return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(
|
|
118426
|
+
return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
118427
|
+
flexDirection: "column",
|
|
118428
|
+
paddingX: 1,
|
|
117860
118429
|
children: [
|
|
117861
118430
|
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
117862
118431
|
paddingLeft: 2,
|
|
117863
|
-
|
|
117864
|
-
|
|
117865
|
-
|
|
117866
|
-
|
|
117867
|
-
|
|
117868
|
-
|
|
117869
|
-
}, undefined, true, undefined, this)
|
|
117870
|
-
}, undefined, false, undefined, this),
|
|
117871
|
-
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
117872
|
-
height: 1
|
|
118432
|
+
paddingY: 1,
|
|
118433
|
+
marginBottom: 1,
|
|
118434
|
+
children: /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(HighlightedText, {
|
|
118435
|
+
text: fullText,
|
|
118436
|
+
query: activeQuery
|
|
118437
|
+
}, undefined, false, undefined, this)
|
|
117873
118438
|
}, undefined, false, undefined, this),
|
|
117874
118439
|
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
117875
118440
|
flexDirection: "column",
|
|
117876
118441
|
paddingLeft: 2,
|
|
118442
|
+
gap: 0,
|
|
117877
118443
|
children: [
|
|
117878
118444
|
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
117879
118445
|
dimColor: true,
|
|
@@ -117883,18 +118449,30 @@ function MessageSearch({
|
|
|
117883
118449
|
timestamp
|
|
117884
118450
|
]
|
|
117885
118451
|
}, undefined, true, undefined, this),
|
|
117886
|
-
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(
|
|
117887
|
-
|
|
118452
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
118453
|
+
flexDirection: "row",
|
|
117888
118454
|
children: [
|
|
117889
|
-
|
|
117890
|
-
|
|
118455
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118456
|
+
dimColor: true,
|
|
118457
|
+
children: "Agent ID: "
|
|
118458
|
+
}, undefined, false, undefined, this),
|
|
118459
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118460
|
+
dimColor: true,
|
|
118461
|
+
children: msgData.agent_id || "unknown"
|
|
118462
|
+
}, undefined, false, undefined, this)
|
|
117891
118463
|
]
|
|
117892
118464
|
}, undefined, true, undefined, this),
|
|
117893
|
-
msgData.conversation_id && /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(
|
|
117894
|
-
|
|
118465
|
+
msgData.conversation_id && /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
|
|
118466
|
+
flexDirection: "row",
|
|
117895
118467
|
children: [
|
|
117896
|
-
|
|
117897
|
-
|
|
118468
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118469
|
+
dimColor: true,
|
|
118470
|
+
children: "Conversation ID: "
|
|
118471
|
+
}, undefined, false, undefined, this),
|
|
118472
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118473
|
+
dimColor: true,
|
|
118474
|
+
children: msgData.conversation_id
|
|
118475
|
+
}, undefined, false, undefined, this)
|
|
117898
118476
|
]
|
|
117899
118477
|
}, undefined, true, undefined, this)
|
|
117900
118478
|
]
|
|
@@ -117906,7 +118484,21 @@ function MessageSearch({
|
|
|
117906
118484
|
paddingLeft: 2,
|
|
117907
118485
|
children: /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
117908
118486
|
dimColor: true,
|
|
117909
|
-
children: onOpenConversation ?
|
|
118487
|
+
children: onOpenConversation ? /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(jsx_dev_runtime56.Fragment, {
|
|
118488
|
+
children: [
|
|
118489
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118490
|
+
children: "Enter to open conversation"
|
|
118491
|
+
}, undefined, false, undefined, this),
|
|
118492
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118493
|
+
children: " · "
|
|
118494
|
+
}, undefined, false, undefined, this),
|
|
118495
|
+
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118496
|
+
children: "Esc cancel"
|
|
118497
|
+
}, undefined, false, undefined, this)
|
|
118498
|
+
]
|
|
118499
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118500
|
+
children: "Esc cancel"
|
|
118501
|
+
}, undefined, false, undefined, this)
|
|
117910
118502
|
}, undefined, false, undefined, this)
|
|
117911
118503
|
}, undefined, false, undefined, this)
|
|
117912
118504
|
]
|
|
@@ -118072,9 +118664,11 @@ function MessageSearch({
|
|
|
118072
118664
|
}, undefined, true, undefined, this),
|
|
118073
118665
|
/* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Text2, {
|
|
118074
118666
|
bold: isSelected,
|
|
118075
|
-
italic: true,
|
|
118076
118667
|
color: isSelected ? colors.selector.itemHighlighted : undefined,
|
|
118077
|
-
children:
|
|
118668
|
+
children: /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(HighlightedText, {
|
|
118669
|
+
text: displayText,
|
|
118670
|
+
query: activeQuery
|
|
118671
|
+
}, undefined, false, undefined, this)
|
|
118078
118672
|
}, undefined, false, undefined, this)
|
|
118079
118673
|
]
|
|
118080
118674
|
}, undefined, true, undefined, this),
|
|
@@ -119326,10 +119920,10 @@ var init_PendingApprovalStub = __esm(async () => {
|
|
|
119326
119920
|
// src/utils/aws-credentials.ts
|
|
119327
119921
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
119328
119922
|
import { homedir as homedir32 } from "node:os";
|
|
119329
|
-
import { join as
|
|
119923
|
+
import { join as join41 } from "node:path";
|
|
119330
119924
|
async function parseAwsCredentials() {
|
|
119331
|
-
const credentialsPath =
|
|
119332
|
-
const configPath =
|
|
119925
|
+
const credentialsPath = join41(homedir32(), ".aws", "credentials");
|
|
119926
|
+
const configPath = join41(homedir32(), ".aws", "config");
|
|
119333
119927
|
const profiles = new Map;
|
|
119334
119928
|
try {
|
|
119335
119929
|
const content = await readFile11(credentialsPath, "utf-8");
|
|
@@ -120437,8 +121031,8 @@ function SkillsDialog({ onClose, agentId }) {
|
|
|
120437
121031
|
try {
|
|
120438
121032
|
const { discoverSkills: discoverSkills3, SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
|
|
120439
121033
|
const { getSkillsDirectory: getSkillsDirectory2, getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
|
|
120440
|
-
const { join:
|
|
120441
|
-
const skillsDir = getSkillsDirectory2() ||
|
|
121034
|
+
const { join: join42 } = await import("node:path");
|
|
121035
|
+
const skillsDir = getSkillsDirectory2() || join42(process.cwd(), SKILLS_DIR3);
|
|
120442
121036
|
const result = await discoverSkills3(skillsDir, agentId, {
|
|
120443
121037
|
sources: getSkillSources2()
|
|
120444
121038
|
});
|
|
@@ -124346,8 +124940,8 @@ var init_contextChart = __esm(() => {
|
|
|
124346
124940
|
|
|
124347
124941
|
// src/cli/helpers/initCommand.ts
|
|
124348
124942
|
import { execSync as execSync2 } from "node:child_process";
|
|
124349
|
-
import { existsSync as
|
|
124350
|
-
import { join as
|
|
124943
|
+
import { existsSync as existsSync33, readdirSync as readdirSync13, readFileSync as readFileSync15 } from "node:fs";
|
|
124944
|
+
import { join as join42 } from "node:path";
|
|
124351
124945
|
function hasActiveInitSubagent() {
|
|
124352
124946
|
const snapshot = getSnapshot2();
|
|
124353
124947
|
return snapshot.agents.some((agent) => agent.type.toLowerCase() === "init" && (agent.status === "pending" || agent.status === "running"));
|
|
@@ -124382,7 +124976,7 @@ ${git.recentCommits || "No commits yet"}
|
|
|
124382
124976
|
}
|
|
124383
124977
|
function gatherExistingMemory(agentId) {
|
|
124384
124978
|
const systemDir = getMemorySystemDir(agentId);
|
|
124385
|
-
if (!
|
|
124979
|
+
if (!existsSync33(systemDir))
|
|
124386
124980
|
return { paths: [], contents: "" };
|
|
124387
124981
|
const paths = [];
|
|
124388
124982
|
const sections = [];
|
|
@@ -124391,10 +124985,10 @@ function gatherExistingMemory(agentId) {
|
|
|
124391
124985
|
for (const entry of readdirSync13(dir, { withFileTypes: true })) {
|
|
124392
124986
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
124393
124987
|
if (entry.isDirectory()) {
|
|
124394
|
-
walk(
|
|
124988
|
+
walk(join42(dir, entry.name), rel);
|
|
124395
124989
|
} else if (entry.name.endsWith(".md")) {
|
|
124396
124990
|
try {
|
|
124397
|
-
const content = readFileSync15(
|
|
124991
|
+
const content = readFileSync15(join42(dir, entry.name), "utf-8");
|
|
124398
124992
|
paths.push(rel);
|
|
124399
124993
|
sections.push(`── ${rel}
|
|
124400
124994
|
${content.slice(0, 2000)}`);
|
|
@@ -124447,7 +125041,7 @@ function gatherDirListing() {
|
|
|
124447
125041
|
if (entry.isDirectory()) {
|
|
124448
125042
|
lines.push(`${prefix}${entry.name}/`);
|
|
124449
125043
|
try {
|
|
124450
|
-
const dirPath =
|
|
125044
|
+
const dirPath = join42(cwd2, entry.name);
|
|
124451
125045
|
const childEntries = readdirSync13(dirPath, {
|
|
124452
125046
|
withFileTypes: true
|
|
124453
125047
|
}).filter((e) => !e.name.startsWith("."));
|
|
@@ -124723,7 +125317,7 @@ import {
|
|
|
124723
125317
|
writeFile as writeFile7
|
|
124724
125318
|
} from "node:fs/promises";
|
|
124725
125319
|
import { homedir as homedir33, tmpdir as tmpdir5 } from "node:os";
|
|
124726
|
-
import { join as
|
|
125320
|
+
import { join as join43 } from "node:path";
|
|
124727
125321
|
function buildReflectionSubagentPrompt(input) {
|
|
124728
125322
|
const lines = [];
|
|
124729
125323
|
if (input.cwd) {
|
|
@@ -124756,7 +125350,7 @@ async function collectParentMemoryFiles(memoryDir) {
|
|
|
124756
125350
|
return a.name.localeCompare(b.name);
|
|
124757
125351
|
});
|
|
124758
125352
|
for (const entry of sortedEntries) {
|
|
124759
|
-
const entryPath =
|
|
125353
|
+
const entryPath = join43(currentDir, entry.name);
|
|
124760
125354
|
const relativePath = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;
|
|
124761
125355
|
if (entry.isDirectory()) {
|
|
124762
125356
|
await walk(entryPath, relativePath);
|
|
@@ -124916,7 +125510,7 @@ function getTranscriptRoot() {
|
|
|
124916
125510
|
if (envRoot) {
|
|
124917
125511
|
return envRoot;
|
|
124918
125512
|
}
|
|
124919
|
-
return
|
|
125513
|
+
return join43(homedir33(), ".letta", DEFAULT_TRANSCRIPT_DIR);
|
|
124920
125514
|
}
|
|
124921
125515
|
function defaultState() {
|
|
124922
125516
|
return { auto_cursor_line: 0 };
|
|
@@ -125028,14 +125622,14 @@ async function readTranscriptLines(paths) {
|
|
|
125028
125622
|
}
|
|
125029
125623
|
function buildPayloadPath(kind) {
|
|
125030
125624
|
const nonce = Math.random().toString(36).slice(2, 8);
|
|
125031
|
-
return
|
|
125625
|
+
return join43(tmpdir5(), `letta-${kind}-${nonce}.txt`);
|
|
125032
125626
|
}
|
|
125033
125627
|
function getReflectionTranscriptPaths(agentId, conversationId) {
|
|
125034
|
-
const rootDir =
|
|
125628
|
+
const rootDir = join43(getTranscriptRoot(), sanitizePathSegment(agentId), sanitizePathSegment(conversationId));
|
|
125035
125629
|
return {
|
|
125036
125630
|
rootDir,
|
|
125037
|
-
transcriptPath:
|
|
125038
|
-
statePath:
|
|
125631
|
+
transcriptPath: join43(rootDir, "transcript.jsonl"),
|
|
125632
|
+
statePath: join43(rootDir, "state.json")
|
|
125039
125633
|
};
|
|
125040
125634
|
}
|
|
125041
125635
|
async function appendTranscriptDeltaJsonl(agentId, conversationId, lines) {
|
|
@@ -125865,12 +126459,12 @@ __export(exports_shellAliases, {
|
|
|
125865
126459
|
expandAliases: () => expandAliases,
|
|
125866
126460
|
clearAliasCache: () => clearAliasCache
|
|
125867
126461
|
});
|
|
125868
|
-
import { existsSync as
|
|
126462
|
+
import { existsSync as existsSync34, readFileSync as readFileSync16 } from "node:fs";
|
|
125869
126463
|
import { homedir as homedir34 } from "node:os";
|
|
125870
|
-
import { join as
|
|
126464
|
+
import { join as join44 } from "node:path";
|
|
125871
126465
|
function parseAliasesFromFile(filePath) {
|
|
125872
126466
|
const aliases = new Map;
|
|
125873
|
-
if (!
|
|
126467
|
+
if (!existsSync34(filePath)) {
|
|
125874
126468
|
return aliases;
|
|
125875
126469
|
}
|
|
125876
126470
|
try {
|
|
@@ -125939,7 +126533,7 @@ function loadAliases(forceReload = false) {
|
|
|
125939
126533
|
const home = homedir34();
|
|
125940
126534
|
const allAliases = new Map;
|
|
125941
126535
|
for (const file of ALIAS_FILES) {
|
|
125942
|
-
const filePath =
|
|
126536
|
+
const filePath = join44(home, file);
|
|
125943
126537
|
const fileAliases = parseAliasesFromFile(filePath);
|
|
125944
126538
|
for (const [name, value] of fileAliases) {
|
|
125945
126539
|
allAliases.set(name, value);
|
|
@@ -126699,7 +127293,10 @@ __export(exports_conversationSwitchAlert, {
|
|
|
126699
127293
|
});
|
|
126700
127294
|
function buildConversationSwitchAlert(ctx) {
|
|
126701
127295
|
const parts = [];
|
|
126702
|
-
if (ctx.origin === "
|
|
127296
|
+
if (ctx.origin === "fork") {
|
|
127297
|
+
parts.push("Forked conversation. This is a copy of the previous conversation with a freshly compiled system message.");
|
|
127298
|
+
parts.push(`Conversation: ${ctx.conversationId}`);
|
|
127299
|
+
} else if (ctx.origin === "new" || ctx.origin === "clear") {
|
|
126703
127300
|
parts.push("New conversation started. This is a fresh conversation thread with no prior messages.");
|
|
126704
127301
|
parts.push(`Conversation: ${ctx.conversationId}`);
|
|
126705
127302
|
} else if (ctx.origin === "search") {
|
|
@@ -126786,9 +127383,9 @@ __export(exports_App, {
|
|
|
126786
127383
|
default: () => App2
|
|
126787
127384
|
});
|
|
126788
127385
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
126789
|
-
import { existsSync as
|
|
127386
|
+
import { existsSync as existsSync35, readFileSync as readFileSync17, renameSync as renameSync2, writeFileSync as writeFileSync17 } from "node:fs";
|
|
126790
127387
|
import { homedir as homedir35, tmpdir as tmpdir6 } from "node:os";
|
|
126791
|
-
import { join as
|
|
127388
|
+
import { join as join45, relative as relative17 } from "node:path";
|
|
126792
127389
|
function deriveReasoningEffort(modelSettings, llmConfig) {
|
|
126793
127390
|
if (modelSettings && "provider_type" in modelSettings) {
|
|
126794
127391
|
if (modelSettings.provider_type === "openai" && "reasoning" in modelSettings && modelSettings.reasoning) {
|
|
@@ -126951,23 +127548,27 @@ async function isRetriableError(stopReason, lastRunId) {
|
|
|
126951
127548
|
}
|
|
126952
127549
|
return false;
|
|
126953
127550
|
}
|
|
126954
|
-
function
|
|
127551
|
+
function saveLastSessionBeforeExit(conversationId) {
|
|
126955
127552
|
try {
|
|
126956
127553
|
const currentAgentId = getCurrentAgentId();
|
|
126957
|
-
|
|
126958
|
-
|
|
127554
|
+
if (conversationId && conversationId !== "default") {
|
|
127555
|
+
settingsManager.persistSession(currentAgentId, conversationId);
|
|
127556
|
+
} else {
|
|
127557
|
+
settingsManager.updateLocalProjectSettings({ lastAgent: currentAgentId });
|
|
127558
|
+
settingsManager.updateSettings({ lastAgent: currentAgentId });
|
|
127559
|
+
}
|
|
126959
127560
|
} catch {}
|
|
126960
127561
|
}
|
|
126961
127562
|
function planFileExists(fallbackPlanFilePath) {
|
|
126962
127563
|
const planFilePath = permissionMode.getPlanFilePath() ?? fallbackPlanFilePath;
|
|
126963
|
-
return !!planFilePath &&
|
|
127564
|
+
return !!planFilePath && existsSync35(planFilePath);
|
|
126964
127565
|
}
|
|
126965
127566
|
function _readPlanFile(fallbackPlanFilePath) {
|
|
126966
127567
|
const planFilePath = permissionMode.getPlanFilePath() ?? fallbackPlanFilePath;
|
|
126967
127568
|
if (!planFilePath) {
|
|
126968
127569
|
return "No plan file path set.";
|
|
126969
127570
|
}
|
|
126970
|
-
if (!
|
|
127571
|
+
if (!existsSync35(planFilePath)) {
|
|
126971
127572
|
return `Plan file not found at ${planFilePath}`;
|
|
126972
127573
|
}
|
|
126973
127574
|
try {
|
|
@@ -127334,11 +127935,26 @@ function App2({
|
|
|
127334
127935
|
agentStateRef.current = agentState;
|
|
127335
127936
|
}, [agentState]);
|
|
127336
127937
|
const [currentModelId, setCurrentModelId] = import_react101.useState(null);
|
|
127938
|
+
const [tempModelOverride, _setTempModelOverride] = import_react101.useState(null);
|
|
127939
|
+
const [tempModelOverrideContext, setTempModelOverrideContext] = import_react101.useState({ agentId, conversationId });
|
|
127940
|
+
const tempModelOverrideRef = import_react101.useRef(null);
|
|
127941
|
+
const setTempModelOverride = import_react101.useCallback((next) => {
|
|
127942
|
+
tempModelOverrideRef.current = next;
|
|
127943
|
+
_setTempModelOverride(next);
|
|
127944
|
+
}, []);
|
|
127945
|
+
if (tempModelOverrideContext.agentId !== agentId || tempModelOverrideContext.conversationId !== conversationId) {
|
|
127946
|
+
setTempModelOverrideContext({ agentId, conversationId });
|
|
127947
|
+
if (tempModelOverride !== null) {
|
|
127948
|
+
setTempModelOverride(null);
|
|
127949
|
+
} else if (tempModelOverrideRef.current !== null) {
|
|
127950
|
+
tempModelOverrideRef.current = null;
|
|
127951
|
+
}
|
|
127952
|
+
}
|
|
127337
127953
|
const [currentModelHandle, setCurrentModelHandle] = import_react101.useState(null);
|
|
127338
127954
|
const agentName = agentState?.name ?? null;
|
|
127339
127955
|
const [agentDescription, setAgentDescription] = import_react101.useState(null);
|
|
127340
127956
|
const [agentLastRunAt, setAgentLastRunAt] = import_react101.useState(null);
|
|
127341
|
-
const currentModelLabel = currentModelHandle || agentState?.model || (llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : llmConfig?.model ?? null) || null;
|
|
127957
|
+
const currentModelLabel = tempModelOverride || currentModelHandle || agentState?.model || (llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : llmConfig?.model ?? null) || null;
|
|
127342
127958
|
const effectiveModelSettings = hasConversationModelOverride ? conversationOverrideModelSettings : agentState?.model_settings;
|
|
127343
127959
|
const derivedReasoningEffort = deriveReasoningEffort(effectiveModelSettings, llmConfig);
|
|
127344
127960
|
const currentModelDisplay = import_react101.useMemo(() => {
|
|
@@ -127355,6 +127971,7 @@ function App2({
|
|
|
127355
127971
|
}, [currentModelLabel, derivedReasoningEffort, llmConfig]);
|
|
127356
127972
|
const currentModelProvider = llmConfig?.provider_name ?? null;
|
|
127357
127973
|
const currentReasoningEffort = currentModelLabel?.startsWith("letta/auto") ? null : derivedReasoningEffort ?? inferReasoningEffortFromModelPreset(currentModelId, currentModelLabel);
|
|
127974
|
+
const hasTemporaryModelOverride = tempModelOverride !== null;
|
|
127358
127975
|
const [billingTier, setBillingTier] = import_react101.useState(null);
|
|
127359
127976
|
import_react101.useEffect(() => {
|
|
127360
127977
|
setErrorContext({
|
|
@@ -127504,6 +128121,7 @@ function App2({
|
|
|
127504
128121
|
const abortControllerRef = import_react101.useRef(null);
|
|
127505
128122
|
const userCancelledRef = import_react101.useRef(false);
|
|
127506
128123
|
const llmApiErrorRetriesRef = import_react101.useRef(0);
|
|
128124
|
+
const quotaAutoSwapAttemptedRef = import_react101.useRef(false);
|
|
127507
128125
|
const emptyResponseRetriesRef = import_react101.useRef(0);
|
|
127508
128126
|
const conversationBusyRetriesRef = import_react101.useRef(0);
|
|
127509
128127
|
const [queueDisplay, setQueueDisplay] = import_react101.useState([]);
|
|
@@ -128112,10 +128730,16 @@ function App2({
|
|
|
128112
128730
|
}, [commitEligibleLines]);
|
|
128113
128731
|
refreshDerivedRef.current = refreshDerived;
|
|
128114
128732
|
const recordCommandReminder = import_react101.useCallback((event) => {
|
|
128115
|
-
|
|
128733
|
+
let input = event.input.trim();
|
|
128116
128734
|
if (!input.startsWith("/")) {
|
|
128117
128735
|
return;
|
|
128118
128736
|
}
|
|
128737
|
+
if (/^\/secret\s+set\s+/i.test(input)) {
|
|
128738
|
+
const parts = input.split(/\s+/);
|
|
128739
|
+
if (parts.length >= 4) {
|
|
128740
|
+
input = `${parts[0]} ${parts[1]} ${parts[2]} ***`;
|
|
128741
|
+
}
|
|
128742
|
+
}
|
|
128119
128743
|
enqueueCommandIoReminder(sharedReminderStateRef.current, {
|
|
128120
128744
|
input,
|
|
128121
128745
|
output: event.output,
|
|
@@ -128263,8 +128887,8 @@ function App2({
|
|
|
128263
128887
|
if (!planFilePath)
|
|
128264
128888
|
return;
|
|
128265
128889
|
try {
|
|
128266
|
-
const { readFileSync: readFileSync18, existsSync:
|
|
128267
|
-
if (!
|
|
128890
|
+
const { readFileSync: readFileSync18, existsSync: existsSync36 } = __require("node:fs");
|
|
128891
|
+
if (!existsSync36(planFilePath))
|
|
128268
128892
|
return;
|
|
128269
128893
|
const planContent = readFileSync18(planFilePath, "utf-8");
|
|
128270
128894
|
const previewItem = {
|
|
@@ -128674,9 +129298,9 @@ Memory may be stale. Try running: git -C ~/.letta/agents/${agentId}/memory pull`
|
|
|
128674
129298
|
(async () => {
|
|
128675
129299
|
try {
|
|
128676
129300
|
const { watch } = await import("node:fs");
|
|
128677
|
-
const { existsSync:
|
|
129301
|
+
const { existsSync: existsSync36 } = await import("node:fs");
|
|
128678
129302
|
const memRoot = getMemoryFilesystemRoot(agentId);
|
|
128679
|
-
if (!
|
|
129303
|
+
if (!existsSync36(memRoot))
|
|
128680
129304
|
return;
|
|
128681
129305
|
watcher = watch(memRoot, { recursive: true }, () => {});
|
|
128682
129306
|
memfsWatcherRef.current = watcher;
|
|
@@ -128834,6 +129458,7 @@ ${newState.originalPrompt}`,
|
|
|
128834
129458
|
llmApiErrorRetriesRef.current = 0;
|
|
128835
129459
|
emptyResponseRetriesRef.current = 0;
|
|
128836
129460
|
conversationBusyRetriesRef.current = 0;
|
|
129461
|
+
quotaAutoSwapAttemptedRef.current = false;
|
|
128837
129462
|
}
|
|
128838
129463
|
let currentRunId;
|
|
128839
129464
|
let preserveTranscriptStartForApproval = false;
|
|
@@ -128883,7 +129508,6 @@ ${newState.originalPrompt}`,
|
|
|
128883
129508
|
if (shouldClearCompletedSubagentsOnTurnStart(allowReentry, hasActiveSubagents())) {
|
|
128884
129509
|
clearCompletedSubagents();
|
|
128885
129510
|
}
|
|
128886
|
-
const requestStartedAtMs = Date.now();
|
|
128887
129511
|
let highestSeqIdSeen = null;
|
|
128888
129512
|
while (true) {
|
|
128889
129513
|
const signal = abortControllerRef.current?.signal;
|
|
@@ -128911,8 +129535,12 @@ ${newState.originalPrompt}`,
|
|
|
128911
129535
|
}
|
|
128912
129536
|
let stream2 = null;
|
|
128913
129537
|
let turnToolContextId = null;
|
|
129538
|
+
let preStreamResumeResult = null;
|
|
128914
129539
|
try {
|
|
128915
|
-
const nextStream = await sendMessageStream(conversationIdRef.current, currentInput, {
|
|
129540
|
+
const nextStream = await sendMessageStream(conversationIdRef.current, currentInput, {
|
|
129541
|
+
agentId: agentIdRef.current,
|
|
129542
|
+
overrideModel: tempModelOverrideRef.current ?? undefined
|
|
129543
|
+
});
|
|
128916
129544
|
stream2 = nextStream;
|
|
128917
129545
|
turnToolContextId = getStreamToolContextId(nextStream);
|
|
128918
129546
|
} catch (preStreamError) {
|
|
@@ -128950,30 +129578,64 @@ ${newState.originalPrompt}`,
|
|
|
128950
129578
|
httpStatus: preStreamError instanceof APIError2 ? preStreamError.status : undefined,
|
|
128951
129579
|
modelId: currentModelId || undefined
|
|
128952
129580
|
});
|
|
128953
|
-
|
|
128954
|
-
|
|
128955
|
-
|
|
128956
|
-
|
|
128957
|
-
|
|
128958
|
-
|
|
128959
|
-
|
|
128960
|
-
|
|
128961
|
-
|
|
128962
|
-
|
|
128963
|
-
while (Date.now() - startTime < retryDelayMs) {
|
|
128964
|
-
if (abortControllerRef.current?.signal.aborted || userCancelledRef.current) {
|
|
128965
|
-
cancelled = true;
|
|
128966
|
-
break;
|
|
129581
|
+
try {
|
|
129582
|
+
const client = await getClient2();
|
|
129583
|
+
const messageOtid = currentInput.map((item) => item.otid).find((v) => typeof v === "string");
|
|
129584
|
+
debugLog("stream", "Conversation busy: resuming via stream endpoint (otid=%s)", messageOtid ?? "none");
|
|
129585
|
+
if (signal?.aborted || userCancelledRef.current) {
|
|
129586
|
+
const isStaleAtAbort = myGeneration !== conversationGenerationRef.current;
|
|
129587
|
+
if (!isStaleAtAbort) {
|
|
129588
|
+
setStreaming(false);
|
|
129589
|
+
}
|
|
129590
|
+
return;
|
|
128967
129591
|
}
|
|
128968
|
-
|
|
128969
|
-
|
|
128970
|
-
|
|
128971
|
-
|
|
128972
|
-
|
|
128973
|
-
|
|
129592
|
+
const conversationId2 = conversationIdRef.current ?? "default";
|
|
129593
|
+
const resumeStream = await client.conversations.messages.stream(conversationId2, {
|
|
129594
|
+
agent_id: conversationId2 === "default" ? agentIdRef.current ?? undefined : undefined,
|
|
129595
|
+
otid: messageOtid ?? undefined,
|
|
129596
|
+
starting_after: 0,
|
|
129597
|
+
batch_size: 1000
|
|
129598
|
+
});
|
|
128974
129599
|
buffersRef.current.interrupted = false;
|
|
128975
|
-
|
|
128976
|
-
|
|
129600
|
+
buffersRef.current.commitGeneration = (buffersRef.current.commitGeneration || 0) + 1;
|
|
129601
|
+
preStreamResumeResult = await drainStream(resumeStream, buffersRef.current, refreshDerivedThrottled, signal, undefined, undefined, contextTrackerRef.current, highestSeqIdSeen);
|
|
129602
|
+
debugLog("stream", "Pre-stream resume succeeded (stopReason=%s)", preStreamResumeResult.stopReason);
|
|
129603
|
+
} catch (resumeError) {
|
|
129604
|
+
if (signal?.aborted || userCancelledRef.current) {
|
|
129605
|
+
const isStaleAtAbort = myGeneration !== conversationGenerationRef.current;
|
|
129606
|
+
if (!isStaleAtAbort) {
|
|
129607
|
+
setStreaming(false);
|
|
129608
|
+
}
|
|
129609
|
+
return;
|
|
129610
|
+
}
|
|
129611
|
+
debugLog("stream", "Pre-stream resume failed, falling back to wait/retry: %s", resumeError instanceof Error ? resumeError.message : String(resumeError));
|
|
129612
|
+
}
|
|
129613
|
+
if (!preStreamResumeResult) {
|
|
129614
|
+
const statusId = uid5("status");
|
|
129615
|
+
buffersRef.current.byId.set(statusId, {
|
|
129616
|
+
kind: "status",
|
|
129617
|
+
id: statusId,
|
|
129618
|
+
lines: ["Conversation is busy, waiting and retrying…"]
|
|
129619
|
+
});
|
|
129620
|
+
buffersRef.current.order.push(statusId);
|
|
129621
|
+
refreshDerived();
|
|
129622
|
+
let cancelled = false;
|
|
129623
|
+
const startTime = Date.now();
|
|
129624
|
+
while (Date.now() - startTime < retryDelayMs) {
|
|
129625
|
+
if (abortControllerRef.current?.signal.aborted || userCancelledRef.current) {
|
|
129626
|
+
cancelled = true;
|
|
129627
|
+
break;
|
|
129628
|
+
}
|
|
129629
|
+
await new Promise((resolve31) => setTimeout(resolve31, 100));
|
|
129630
|
+
}
|
|
129631
|
+
buffersRef.current.byId.delete(statusId);
|
|
129632
|
+
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
129633
|
+
refreshDerived();
|
|
129634
|
+
if (!cancelled) {
|
|
129635
|
+
buffersRef.current.interrupted = false;
|
|
129636
|
+
restorePinnedPermissionMode();
|
|
129637
|
+
continue;
|
|
129638
|
+
}
|
|
128977
129639
|
}
|
|
128978
129640
|
}
|
|
128979
129641
|
if (preStreamAction === "retry_transient") {
|
|
@@ -129118,10 +129780,12 @@ ${newState.originalPrompt}`,
|
|
|
129118
129780
|
if (hasUserMessage) {
|
|
129119
129781
|
contextTrackerRef.current.currentTurnId++;
|
|
129120
129782
|
}
|
|
129121
|
-
|
|
129122
|
-
|
|
129123
|
-
|
|
129124
|
-
|
|
129783
|
+
const drainResult = preStreamResumeResult ? preStreamResumeResult : (() => {
|
|
129784
|
+
if (!stream2) {
|
|
129785
|
+
throw new Error("Expected stream when pre-stream resume did not succeed");
|
|
129786
|
+
}
|
|
129787
|
+
return drainStreamWithResume(stream2, buffersRef.current, refreshDerivedThrottled, signal, handleFirstMessage, undefined, contextTrackerRef.current, highestSeqIdSeen);
|
|
129788
|
+
})();
|
|
129125
129789
|
const {
|
|
129126
129790
|
stopReason,
|
|
129127
129791
|
approval,
|
|
@@ -129703,6 +130367,37 @@ ${feedback}
|
|
|
129703
130367
|
buffersRef.current.interrupted = false;
|
|
129704
130368
|
continue;
|
|
129705
130369
|
}
|
|
130370
|
+
const autoSwapOnQuotaLimitEnabled = settingsManager.getSetting("autoSwapOnQuotaLimit") !== false;
|
|
130371
|
+
const isQuotaLimit = isQuotaLimitErrorDetail(detailFromRun ?? fallbackError);
|
|
130372
|
+
const alreadyOnTempAuto = tempModelOverrideRef.current === TEMP_QUOTA_OVERRIDE_MODEL;
|
|
130373
|
+
const canAttemptQuotaAutoSwap = autoSwapOnQuotaLimitEnabled && isQuotaLimit && !alreadyOnTempAuto && !quotaAutoSwapAttemptedRef.current;
|
|
130374
|
+
if (canAttemptQuotaAutoSwap) {
|
|
130375
|
+
quotaAutoSwapAttemptedRef.current = true;
|
|
130376
|
+
setTempModelOverride(TEMP_QUOTA_OVERRIDE_MODEL);
|
|
130377
|
+
const statusId = uid5("status");
|
|
130378
|
+
buffersRef.current.byId.set(statusId, {
|
|
130379
|
+
kind: "status",
|
|
130380
|
+
id: statusId,
|
|
130381
|
+
lines: [
|
|
130382
|
+
"Quota limit reached; temporarily switching to Auto and continuing..."
|
|
130383
|
+
]
|
|
130384
|
+
});
|
|
130385
|
+
buffersRef.current.order.push(statusId);
|
|
130386
|
+
refreshDerived();
|
|
130387
|
+
currentInput = [
|
|
130388
|
+
...currentInput,
|
|
130389
|
+
{
|
|
130390
|
+
type: "message",
|
|
130391
|
+
role: "user",
|
|
130392
|
+
content: "Keep going."
|
|
130393
|
+
}
|
|
130394
|
+
];
|
|
130395
|
+
buffersRef.current.byId.delete(statusId);
|
|
130396
|
+
buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
|
|
130397
|
+
refreshDerived();
|
|
130398
|
+
buffersRef.current.interrupted = false;
|
|
130399
|
+
continue;
|
|
130400
|
+
}
|
|
129706
130401
|
if (isEmptyResponseRetryable(stopReasonToHandle === "llm_api_error" ? "llm_error" : undefined, detailFromRun, emptyResponseRetriesRef.current, EMPTY_RESPONSE_MAX_RETRIES3)) {
|
|
129707
130402
|
emptyResponseRetriesRef.current += 1;
|
|
129708
130403
|
const attempt = emptyResponseRetriesRef.current;
|
|
@@ -129780,6 +130475,7 @@ ${feedback}
|
|
|
129780
130475
|
}
|
|
129781
130476
|
if (!cancelled) {
|
|
129782
130477
|
refreshCurrentInputOtids();
|
|
130478
|
+
highestSeqIdSeen = null;
|
|
129783
130479
|
buffersRef.current.interrupted = false;
|
|
129784
130480
|
continue;
|
|
129785
130481
|
}
|
|
@@ -129939,7 +130635,7 @@ ${feedback}
|
|
|
129939
130635
|
setUiPermissionMode
|
|
129940
130636
|
]);
|
|
129941
130637
|
const handleExit = import_react101.useCallback(async () => {
|
|
129942
|
-
|
|
130638
|
+
saveLastSessionBeforeExit(conversationIdRef.current);
|
|
129943
130639
|
await runEndHooks();
|
|
129944
130640
|
const stats = sessionStatsRef.current.getSnapshot();
|
|
129945
130641
|
telemetry.trackSessionEnd(stats, "exit_command");
|
|
@@ -130199,11 +130895,7 @@ ${feedback}
|
|
|
130199
130895
|
const agent = await client.agents.retrieve(targetAgentId);
|
|
130200
130896
|
const targetConversationId = opts?.conversationId ?? "default";
|
|
130201
130897
|
await updateProjectSettings({ lastAgent: targetAgentId });
|
|
130202
|
-
settingsManager.
|
|
130203
|
-
settingsManager.setGlobalLastSession({
|
|
130204
|
-
agentId: targetAgentId,
|
|
130205
|
-
conversationId: targetConversationId
|
|
130206
|
-
});
|
|
130898
|
+
settingsManager.persistSession(targetAgentId, targetConversationId);
|
|
130207
130899
|
buffersRef.current.byId.clear();
|
|
130208
130900
|
buffersRef.current.order = [];
|
|
130209
130901
|
buffersRef.current.tokenCount = 0;
|
|
@@ -130291,11 +130983,7 @@ ${feedback}
|
|
|
130291
130983
|
}
|
|
130292
130984
|
await updateProjectSettings({ lastAgent: agent.id });
|
|
130293
130985
|
const targetConversationId = "default";
|
|
130294
|
-
settingsManager.
|
|
130295
|
-
settingsManager.setGlobalLastSession({
|
|
130296
|
-
agentId: agent.id,
|
|
130297
|
-
conversationId: targetConversationId
|
|
130298
|
-
});
|
|
130986
|
+
settingsManager.persistSession(agent.id, targetConversationId);
|
|
130299
130987
|
const agentUrl = buildChatUrl(agent.id);
|
|
130300
130988
|
const memfsTip = settingsManager.isMemfsEnabled(agent.id) ? "Memory will be auto-initialized on your first message." : "Tip: use /init to initialize your agent's memory system!";
|
|
130301
130989
|
const successOutput = [
|
|
@@ -130641,14 +131329,14 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
|
|
|
130641
131329
|
setDequeueEpoch((e) => e + 1);
|
|
130642
131330
|
}
|
|
130643
131331
|
const isSlashCommand = userTextForInput.startsWith("/");
|
|
130644
|
-
|
|
131332
|
+
const shouldBypassQueue = isSlashCommand && (isInteractiveCommand(userTextForInput) || isNonStateCommand(userTextForInput));
|
|
131333
|
+
if (isAgentBusy() && isSlashCommand && !shouldBypassQueue) {
|
|
130645
131334
|
const attemptedCommand = userTextForInput.split(/\s+/)[0] || "/";
|
|
130646
131335
|
const disabledMessage = `'${attemptedCommand}' is disabled while the agent is running.`;
|
|
130647
131336
|
const cmd = commandRunner.start(userTextForInput, disabledMessage);
|
|
130648
131337
|
cmd.fail(disabledMessage);
|
|
130649
131338
|
return { submitted: true };
|
|
130650
131339
|
}
|
|
130651
|
-
const shouldBypassQueue = isInteractiveCommand(userTextForInput) || isNonStateCommand(userTextForInput);
|
|
130652
131340
|
if (isAgentBusy() && !shouldBypassQueue) {
|
|
130653
131341
|
tuiQueueRef.current?.enqueue({
|
|
130654
131342
|
kind: "message",
|
|
@@ -131144,7 +131832,7 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
|
|
|
131144
131832
|
}
|
|
131145
131833
|
await settingsManager3.logout();
|
|
131146
131834
|
cmd.finish("✓ Logged out successfully. Run 'letta' to re-authenticate.", true);
|
|
131147
|
-
|
|
131835
|
+
saveLastSessionBeforeExit(conversationIdRef.current);
|
|
131148
131836
|
const stats = sessionStatsRef.current.getSnapshot();
|
|
131149
131837
|
telemetry.trackSessionEnd(stats, "logout");
|
|
131150
131838
|
try {
|
|
@@ -131278,21 +131966,60 @@ Type your task to begin the loop.`, true);
|
|
|
131278
131966
|
conversationId: conversation.id,
|
|
131279
131967
|
isDefault: false
|
|
131280
131968
|
};
|
|
131281
|
-
settingsManager.
|
|
131969
|
+
settingsManager.persistSession(agentId, conversation.id);
|
|
131970
|
+
resetContextHistory(contextTrackerRef.current);
|
|
131971
|
+
resetBootstrapReminderState();
|
|
131972
|
+
sessionHooksRanRef.current = false;
|
|
131973
|
+
runSessionStartHooks(true, agentId, agentName ?? undefined, conversation.id).then((result2) => {
|
|
131974
|
+
if (result2.feedback.length > 0) {
|
|
131975
|
+
sessionStartFeedbackRef.current = result2.feedback;
|
|
131976
|
+
}
|
|
131977
|
+
}).catch(() => {});
|
|
131978
|
+
sessionHooksRanRef.current = true;
|
|
131979
|
+
cmd.finish("Started new conversation (use /resume to change convos)", true);
|
|
131980
|
+
} catch (error) {
|
|
131981
|
+
const errorDetails = formatErrorDetails2(error, agentId);
|
|
131982
|
+
cmd.fail(`Failed: ${errorDetails}`);
|
|
131983
|
+
} finally {
|
|
131984
|
+
setCommandRunning(false);
|
|
131985
|
+
}
|
|
131986
|
+
return { submitted: true };
|
|
131987
|
+
}
|
|
131988
|
+
if (msg.trim() === "/fork") {
|
|
131989
|
+
if (conversationIdRef.current === "default") {
|
|
131990
|
+
const cmd2 = commandRunner.start(msg.trim(), "Forking conversation...");
|
|
131991
|
+
cmd2.fail("Cannot fork the default conversation — use /new instead");
|
|
131992
|
+
return { submitted: true };
|
|
131993
|
+
}
|
|
131994
|
+
const cmd = commandRunner.start(msg.trim(), "Forking conversation...");
|
|
131995
|
+
resetPendingReasoningCycle();
|
|
131996
|
+
setCommandRunning(true);
|
|
131997
|
+
await runEndHooks();
|
|
131998
|
+
try {
|
|
131999
|
+
const client = await getClient2();
|
|
132000
|
+
const forked = await client.post(`/v1/conversations/${conversationIdRef.current}/fork`);
|
|
132001
|
+
await maybeCarryOverActiveConversationModel(forked.id);
|
|
132002
|
+
setConversationId3(forked.id);
|
|
132003
|
+
pendingConversationSwitchRef.current = {
|
|
132004
|
+
origin: "fork",
|
|
132005
|
+
conversationId: forked.id,
|
|
132006
|
+
isDefault: false
|
|
132007
|
+
};
|
|
132008
|
+
settingsManager.setLocalLastSession({ agentId, conversationId: forked.id }, process.cwd());
|
|
131282
132009
|
settingsManager.setGlobalLastSession({
|
|
131283
132010
|
agentId,
|
|
131284
|
-
conversationId:
|
|
132011
|
+
conversationId: forked.id
|
|
131285
132012
|
});
|
|
131286
132013
|
resetContextHistory(contextTrackerRef.current);
|
|
131287
132014
|
resetBootstrapReminderState();
|
|
131288
132015
|
sessionHooksRanRef.current = false;
|
|
131289
|
-
runSessionStartHooks(true, agentId, agentName ?? undefined,
|
|
132016
|
+
runSessionStartHooks(true, agentId, agentName ?? undefined, forked.id).then((result2) => {
|
|
131290
132017
|
if (result2.feedback.length > 0) {
|
|
131291
132018
|
sessionStartFeedbackRef.current = result2.feedback;
|
|
131292
132019
|
}
|
|
131293
132020
|
}).catch(() => {});
|
|
131294
132021
|
sessionHooksRanRef.current = true;
|
|
131295
|
-
cmd.finish("
|
|
132022
|
+
cmd.finish("Forked conversation (use /resume to switch back)", true);
|
|
131296
132023
|
} catch (error) {
|
|
131297
132024
|
const errorDetails = formatErrorDetails2(error, agentId);
|
|
131298
132025
|
cmd.fail(`Failed: ${errorDetails}`);
|
|
@@ -131324,11 +132051,7 @@ Type your task to begin the loop.`, true);
|
|
|
131324
132051
|
conversationId: conversation.id,
|
|
131325
132052
|
isDefault: false
|
|
131326
132053
|
};
|
|
131327
|
-
settingsManager.
|
|
131328
|
-
settingsManager.setGlobalLastSession({
|
|
131329
|
-
agentId,
|
|
131330
|
-
conversationId: conversation.id
|
|
131331
|
-
});
|
|
132054
|
+
settingsManager.persistSession(agentId, conversation.id);
|
|
131332
132055
|
resetContextHistory(contextTrackerRef.current);
|
|
131333
132056
|
resetBootstrapReminderState();
|
|
131334
132057
|
sessionHooksRanRef.current = false;
|
|
@@ -131591,11 +132314,7 @@ Type your task to begin the loop.`, true);
|
|
|
131591
132314
|
messageCount: resumeData.messageHistory.length,
|
|
131592
132315
|
messageHistory: resumeData.messageHistory
|
|
131593
132316
|
};
|
|
131594
|
-
settingsManager.
|
|
131595
|
-
settingsManager.setGlobalLastSession({
|
|
131596
|
-
agentId,
|
|
131597
|
-
conversationId: targetConvId
|
|
131598
|
-
});
|
|
132317
|
+
settingsManager.persistSession(agentId, targetConvId);
|
|
131599
132318
|
const currentAgentName = agentState.name || "Unnamed Agent";
|
|
131600
132319
|
const successLines = resumeData.messageHistory.length > 0 ? [
|
|
131601
132320
|
`Resumed conversation with "${currentAgentName}"`,
|
|
@@ -131904,7 +132623,7 @@ Press Enter to continue, or type anything to cancel.`, false, "running");
|
|
|
131904
132623
|
fileContent = await client.agents.exportFile(agentId, exportParams);
|
|
131905
132624
|
}
|
|
131906
132625
|
const fileName = exportParams.conversation_id ? `${exportParams.conversation_id}.af` : `${agentId}.af`;
|
|
131907
|
-
|
|
132626
|
+
writeFileSync17(fileName, JSON.stringify(fileContent, null, 2));
|
|
131908
132627
|
let summary = `AgentFile exported to ${fileName}`;
|
|
131909
132628
|
if (skills.length > 0) {
|
|
131910
132629
|
summary += `
|
|
@@ -131994,11 +132713,11 @@ Path: ${result2.memoryDir}`, true, msg);
|
|
|
131994
132713
|
setCommandRunning(true);
|
|
131995
132714
|
try {
|
|
131996
132715
|
const memoryDir = getMemoryFilesystemRoot(agentId);
|
|
131997
|
-
if (!
|
|
132716
|
+
if (!existsSync35(memoryDir)) {
|
|
131998
132717
|
updateMemorySyncCommand(cmdId, "No local memory filesystem found to reset.", true, msg);
|
|
131999
132718
|
return { submitted: true };
|
|
132000
132719
|
}
|
|
132001
|
-
const backupDir =
|
|
132720
|
+
const backupDir = join45(tmpdir6(), `letta-memfs-reset-${agentId}-${Date.now()}`);
|
|
132002
132721
|
renameSync2(memoryDir, backupDir);
|
|
132003
132722
|
ensureMemoryFilesystemDirs(agentId);
|
|
132004
132723
|
updateMemorySyncCommand(cmdId, `Memory filesystem reset.
|
|
@@ -132026,8 +132745,8 @@ Run \`/memfs sync\` to repopulate from API.`, true, msg);
|
|
|
132026
132745
|
await removeGitMemoryTag2(agentId);
|
|
132027
132746
|
let backupInfo = "";
|
|
132028
132747
|
const memoryDir = getMemoryFilesystemRoot(agentId);
|
|
132029
|
-
if (
|
|
132030
|
-
const backupDir =
|
|
132748
|
+
if (existsSync35(memoryDir)) {
|
|
132749
|
+
const backupDir = join45(tmpdir6(), `letta-memfs-disable-${agentId}-${Date.now()}`);
|
|
132031
132750
|
renameSync2(memoryDir, backupDir);
|
|
132032
132751
|
backupInfo = `
|
|
132033
132752
|
Local files backed up to ${backupDir}`;
|
|
@@ -132295,7 +133014,7 @@ ${SYSTEM_REMINDER_CLOSE}`),
|
|
|
132295
133014
|
}
|
|
132296
133015
|
return { submitted: true };
|
|
132297
133016
|
}
|
|
132298
|
-
const { commands: commands2, executeCommand: executeCommand2 } = await
|
|
133017
|
+
const { commands: commands2, executeCommand: executeCommand2 } = await init_registry().then(() => exports_registry);
|
|
132299
133018
|
const registryCommandName = trimmed.split(/\s+/)[0] ?? "";
|
|
132300
133019
|
const isRegistryCommand = Boolean(commands2[registryCommandName]);
|
|
132301
133020
|
const registryCmd = isRegistryCommand ? commandRunner.start(msg, `Running ${registryCommandName}...`) : null;
|
|
@@ -132884,7 +133603,8 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
132884
133603
|
if (isQueuedValid) {
|
|
132885
133604
|
initialInput.push({
|
|
132886
133605
|
type: "approval",
|
|
132887
|
-
approvals: queuedApprovalResults
|
|
133606
|
+
approvals: queuedApprovalResults,
|
|
133607
|
+
otid: randomUUID9()
|
|
132888
133608
|
});
|
|
132889
133609
|
} else {
|
|
132890
133610
|
debugWarn("queue", "Dropping stale queued approval results for mismatched conversation or generation");
|
|
@@ -133103,7 +133823,11 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
133103
133823
|
const queuedNotifications = queuedItemsToAppend ? getQueuedNotificationSummaries(queuedItemsToAppend) : [];
|
|
133104
133824
|
const hadNotifications = appendTaskNotificationEvents(queuedNotifications);
|
|
133105
133825
|
const input = [
|
|
133106
|
-
{
|
|
133826
|
+
{
|
|
133827
|
+
type: "approval",
|
|
133828
|
+
approvals: allResults,
|
|
133829
|
+
otid: randomUUID9()
|
|
133830
|
+
}
|
|
133107
133831
|
];
|
|
133108
133832
|
if (queuedItemsToAppend && queuedItemsToAppend.length > 0) {
|
|
133109
133833
|
const queuedUserText = buildQueuedUserText(queuedItemsToAppend);
|
|
@@ -133492,6 +134216,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
133492
134216
|
} : {}
|
|
133493
134217
|
});
|
|
133494
134218
|
setCurrentModelId(modelId);
|
|
134219
|
+
setTempModelOverride(null);
|
|
133495
134220
|
resetContextHistory(contextTrackerRef.current);
|
|
133496
134221
|
setCurrentModelHandle(modelHandle);
|
|
133497
134222
|
const persistedToolsetPreference = settingsManager.getToolsetPreference(agentId);
|
|
@@ -133554,7 +134279,8 @@ ${guidance}`);
|
|
|
133554
134279
|
maybeRecordToolsetChangeReminder,
|
|
133555
134280
|
resetPendingReasoningCycle,
|
|
133556
134281
|
withCommandLock,
|
|
133557
|
-
setHasConversationModelOverride
|
|
134282
|
+
setHasConversationModelOverride,
|
|
134283
|
+
setTempModelOverride
|
|
133558
134284
|
]);
|
|
133559
134285
|
const handleSystemPromptSelect = import_react101.useCallback(async (promptId, commandId) => {
|
|
133560
134286
|
const overlayCommand = commandId ? commandRunner.getHandle(commandId, "/system") : consumeOverlayCommand("system");
|
|
@@ -133811,11 +134537,7 @@ ${guidance}`);
|
|
|
133811
134537
|
messageCount: resumeData.messageHistory.length,
|
|
133812
134538
|
messageHistory: resumeData.messageHistory
|
|
133813
134539
|
};
|
|
133814
|
-
settingsManager.
|
|
133815
|
-
settingsManager.setGlobalLastSession({
|
|
133816
|
-
agentId,
|
|
133817
|
-
conversationId: action.conversationId
|
|
133818
|
-
});
|
|
134540
|
+
settingsManager.persistSession(agentId, action.conversationId);
|
|
133819
134541
|
resetContextHistory(contextTrackerRef.current);
|
|
133820
134542
|
resetBootstrapReminderState();
|
|
133821
134543
|
cmd.finish(`Switched to conversation (${resumeData.messageHistory.length} messages)`, true);
|
|
@@ -134249,7 +134971,7 @@ ${guidance}`);
|
|
|
134249
134971
|
}
|
|
134250
134972
|
if (mode === "bypassPermissions") {
|
|
134251
134973
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
134252
|
-
const plansDir =
|
|
134974
|
+
const plansDir = join45(homedir35(), ".letta", "plans");
|
|
134253
134975
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
134254
134976
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
134255
134977
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -134284,7 +135006,7 @@ ${guidance}`);
|
|
|
134284
135006
|
if (!hasUsablePlan) {
|
|
134285
135007
|
lastAutoHandledExitPlanToolCallIdRef.current = approval.toolCallId;
|
|
134286
135008
|
const planFilePath = activePlanPath ?? fallbackPlanPath;
|
|
134287
|
-
const plansDir =
|
|
135009
|
+
const plansDir = join45(homedir35(), ".letta", "plans");
|
|
134288
135010
|
handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
|
|
134289
135011
|
` + (planFilePath ? `Plan file path: ${planFilePath}
|
|
134290
135012
|
` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
|
|
@@ -134883,6 +135605,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
134883
135605
|
agentName,
|
|
134884
135606
|
currentModel: currentModelDisplay,
|
|
134885
135607
|
currentModelProvider,
|
|
135608
|
+
hasTemporaryModelOverride,
|
|
134886
135609
|
currentReasoningEffort,
|
|
134887
135610
|
messageQueue: queueDisplay,
|
|
134888
135611
|
onEnterQueueEditMode: handleEnterQueueEditMode,
|
|
@@ -135092,11 +135815,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
135092
135815
|
if (selectorContext?.summary) {
|
|
135093
135816
|
hasSetConversationSummaryRef.current = true;
|
|
135094
135817
|
}
|
|
135095
|
-
settingsManager.
|
|
135096
|
-
settingsManager.setGlobalLastSession({
|
|
135097
|
-
agentId,
|
|
135098
|
-
conversationId: convId
|
|
135099
|
-
});
|
|
135818
|
+
settingsManager.persistSession(agentId, convId);
|
|
135100
135819
|
const currentAgentName = agentState.name || "Unnamed Agent";
|
|
135101
135820
|
const successLines = resumeData.messageHistory.length > 0 ? [
|
|
135102
135821
|
`Resumed conversation with "${currentAgentName}"`,
|
|
@@ -135206,11 +135925,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
135206
135925
|
});
|
|
135207
135926
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
135208
135927
|
setConversationId3(conversation.id);
|
|
135209
|
-
settingsManager.
|
|
135210
|
-
settingsManager.setGlobalLastSession({
|
|
135211
|
-
agentId,
|
|
135212
|
-
conversationId: conversation.id
|
|
135213
|
-
});
|
|
135928
|
+
settingsManager.persistSession(agentId, conversation.id);
|
|
135214
135929
|
const currentAgentName = agentState?.name || "Unnamed Agent";
|
|
135215
135930
|
const shortConvId = conversation.id.slice(0, 20);
|
|
135216
135931
|
const successLines = [
|
|
@@ -135303,11 +136018,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
135303
136018
|
searchQuery: searchContext?.query,
|
|
135304
136019
|
searchMessage: searchContext?.message
|
|
135305
136020
|
};
|
|
135306
|
-
settingsManager.
|
|
135307
|
-
settingsManager.setGlobalLastSession({
|
|
135308
|
-
agentId,
|
|
135309
|
-
conversationId: actualTargetConv
|
|
135310
|
-
});
|
|
136021
|
+
settingsManager.persistSession(agentId, actualTargetConv);
|
|
135311
136022
|
const currentAgentName = agentState.name || "Unnamed Agent";
|
|
135312
136023
|
const successOutput = [
|
|
135313
136024
|
`Switched to conversation with "${currentAgentName}"`,
|
|
@@ -135488,7 +136199,7 @@ Open /mcp to attach or detach tools for this server.`, true);
|
|
|
135488
136199
|
]
|
|
135489
136200
|
}, resumeKey, true, undefined, this);
|
|
135490
136201
|
}
|
|
135491
|
-
var import_react101, jsx_dev_runtime78, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, CONVERSATION_BUSY_MAX_RETRIES2 = 3, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", OPUS_BEDROCK_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to Bedrock Opus 4.5", PROVIDER_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to another provider", INTERACTIVE_SLASH_COMMANDS, NON_STATE_COMMANDS, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12, SHELL_PREVIEW_MAX_LINES = 3, AUTO_REFLECTION_DESCRIPTION = "Reflect on recent conversations";
|
|
136202
|
+
var import_react101, jsx_dev_runtime78, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, TEMP_QUOTA_OVERRIDE_MODEL = "letta/auto", CONVERSATION_BUSY_MAX_RETRIES2 = 3, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", OPUS_BEDROCK_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to Bedrock Opus 4.5", PROVIDER_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to another provider", INTERACTIVE_SLASH_COMMANDS, NON_STATE_COMMANDS, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12, SHELL_PREVIEW_MAX_LINES = 3, AUTO_REFLECTION_DESCRIPTION = "Reflect on recent conversations";
|
|
135492
136203
|
var init_App2 = __esm(async () => {
|
|
135493
136204
|
init_error();
|
|
135494
136205
|
init_check_approval();
|
|
@@ -135636,7 +136347,8 @@ var init_App2 = __esm(async () => {
|
|
|
135636
136347
|
"/export",
|
|
135637
136348
|
"/download",
|
|
135638
136349
|
"/statusline",
|
|
135639
|
-
"/reasoning-tab"
|
|
136350
|
+
"/reasoning-tab",
|
|
136351
|
+
"/secret"
|
|
135640
136352
|
]);
|
|
135641
136353
|
});
|
|
135642
136354
|
|
|
@@ -135658,13 +136370,13 @@ __export(exports_terminalKeybindingInstaller2, {
|
|
|
135658
136370
|
});
|
|
135659
136371
|
import {
|
|
135660
136372
|
copyFileSync as copyFileSync2,
|
|
135661
|
-
existsSync as
|
|
135662
|
-
mkdirSync as
|
|
136373
|
+
existsSync as existsSync36,
|
|
136374
|
+
mkdirSync as mkdirSync23,
|
|
135663
136375
|
readFileSync as readFileSync18,
|
|
135664
|
-
writeFileSync as
|
|
136376
|
+
writeFileSync as writeFileSync18
|
|
135665
136377
|
} from "node:fs";
|
|
135666
136378
|
import { homedir as homedir36, platform as platform6 } from "node:os";
|
|
135667
|
-
import { dirname as
|
|
136379
|
+
import { dirname as dirname18, join as join46 } from "node:path";
|
|
135668
136380
|
function detectTerminalType2() {
|
|
135669
136381
|
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
|
|
135670
136382
|
return "cursor";
|
|
@@ -135696,16 +136408,16 @@ function getKeybindingsPath2(terminal) {
|
|
|
135696
136408
|
}[terminal];
|
|
135697
136409
|
const os8 = platform6();
|
|
135698
136410
|
if (os8 === "darwin") {
|
|
135699
|
-
return
|
|
136411
|
+
return join46(homedir36(), "Library", "Application Support", appName, "User", "keybindings.json");
|
|
135700
136412
|
}
|
|
135701
136413
|
if (os8 === "win32") {
|
|
135702
136414
|
const appData = process.env.APPDATA;
|
|
135703
136415
|
if (!appData)
|
|
135704
136416
|
return null;
|
|
135705
|
-
return
|
|
136417
|
+
return join46(appData, appName, "User", "keybindings.json");
|
|
135706
136418
|
}
|
|
135707
136419
|
if (os8 === "linux") {
|
|
135708
|
-
return
|
|
136420
|
+
return join46(homedir36(), ".config", appName, "User", "keybindings.json");
|
|
135709
136421
|
}
|
|
135710
136422
|
return null;
|
|
135711
136423
|
}
|
|
@@ -135727,7 +136439,7 @@ function parseKeybindings2(content) {
|
|
|
135727
136439
|
}
|
|
135728
136440
|
}
|
|
135729
136441
|
function keybindingExists2(keybindingsPath) {
|
|
135730
|
-
if (!
|
|
136442
|
+
if (!existsSync36(keybindingsPath))
|
|
135731
136443
|
return false;
|
|
135732
136444
|
try {
|
|
135733
136445
|
const content = readFileSync18(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -135740,7 +136452,7 @@ function keybindingExists2(keybindingsPath) {
|
|
|
135740
136452
|
}
|
|
135741
136453
|
}
|
|
135742
136454
|
function createBackup2(keybindingsPath) {
|
|
135743
|
-
if (!
|
|
136455
|
+
if (!existsSync36(keybindingsPath))
|
|
135744
136456
|
return null;
|
|
135745
136457
|
const backupPath = `${keybindingsPath}.letta-backup`;
|
|
135746
136458
|
try {
|
|
@@ -135755,13 +136467,13 @@ function installKeybinding2(keybindingsPath) {
|
|
|
135755
136467
|
if (keybindingExists2(keybindingsPath)) {
|
|
135756
136468
|
return { success: true, alreadyExists: true };
|
|
135757
136469
|
}
|
|
135758
|
-
const parentDir =
|
|
135759
|
-
if (!
|
|
135760
|
-
|
|
136470
|
+
const parentDir = dirname18(keybindingsPath);
|
|
136471
|
+
if (!existsSync36(parentDir)) {
|
|
136472
|
+
mkdirSync23(parentDir, { recursive: true });
|
|
135761
136473
|
}
|
|
135762
136474
|
let keybindings = [];
|
|
135763
136475
|
let backupPath = null;
|
|
135764
|
-
if (
|
|
136476
|
+
if (existsSync36(keybindingsPath)) {
|
|
135765
136477
|
backupPath = createBackup2(keybindingsPath);
|
|
135766
136478
|
const content = readFileSync18(keybindingsPath, { encoding: "utf-8" });
|
|
135767
136479
|
const parsed = parseKeybindings2(content);
|
|
@@ -135776,7 +136488,7 @@ function installKeybinding2(keybindingsPath) {
|
|
|
135776
136488
|
keybindings.push(SHIFT_ENTER_KEYBINDING2);
|
|
135777
136489
|
const newContent = `${JSON.stringify(keybindings, null, 2)}
|
|
135778
136490
|
`;
|
|
135779
|
-
|
|
136491
|
+
writeFileSync18(keybindingsPath, newContent, { encoding: "utf-8" });
|
|
135780
136492
|
return {
|
|
135781
136493
|
success: true,
|
|
135782
136494
|
backupPath: backupPath ?? undefined
|
|
@@ -135791,7 +136503,7 @@ function installKeybinding2(keybindingsPath) {
|
|
|
135791
136503
|
}
|
|
135792
136504
|
function removeKeybinding2(keybindingsPath) {
|
|
135793
136505
|
try {
|
|
135794
|
-
if (!
|
|
136506
|
+
if (!existsSync36(keybindingsPath)) {
|
|
135795
136507
|
return { success: true };
|
|
135796
136508
|
}
|
|
135797
136509
|
const content = readFileSync18(keybindingsPath, { encoding: "utf-8" });
|
|
@@ -135805,7 +136517,7 @@ function removeKeybinding2(keybindingsPath) {
|
|
|
135805
136517
|
const filtered = keybindings.filter((kb) => !(kb.key?.toLowerCase() === "shift+enter" && kb.command === "workbench.action.terminal.sendSequence" && kb.when?.includes("terminalFocus")));
|
|
135806
136518
|
const newContent = `${JSON.stringify(filtered, null, 2)}
|
|
135807
136519
|
`;
|
|
135808
|
-
|
|
136520
|
+
writeFileSync18(keybindingsPath, newContent, { encoding: "utf-8" });
|
|
135809
136521
|
return { success: true };
|
|
135810
136522
|
} catch (error) {
|
|
135811
136523
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -135858,17 +136570,17 @@ function getWezTermConfigPath2() {
|
|
|
135858
136570
|
}
|
|
135859
136571
|
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
135860
136572
|
if (xdgConfig) {
|
|
135861
|
-
const xdgPath =
|
|
135862
|
-
if (
|
|
136573
|
+
const xdgPath = join46(xdgConfig, "wezterm", "wezterm.lua");
|
|
136574
|
+
if (existsSync36(xdgPath))
|
|
135863
136575
|
return xdgPath;
|
|
135864
136576
|
}
|
|
135865
|
-
const configPath =
|
|
135866
|
-
if (
|
|
136577
|
+
const configPath = join46(homedir36(), ".config", "wezterm", "wezterm.lua");
|
|
136578
|
+
if (existsSync36(configPath))
|
|
135867
136579
|
return configPath;
|
|
135868
|
-
return
|
|
136580
|
+
return join46(homedir36(), ".wezterm.lua");
|
|
135869
136581
|
}
|
|
135870
136582
|
function wezTermDeleteFixExists2(configPath) {
|
|
135871
|
-
if (!
|
|
136583
|
+
if (!existsSync36(configPath))
|
|
135872
136584
|
return false;
|
|
135873
136585
|
try {
|
|
135874
136586
|
const content = readFileSync18(configPath, { encoding: "utf-8" });
|
|
@@ -135885,7 +136597,7 @@ function installWezTermDeleteFix2() {
|
|
|
135885
136597
|
}
|
|
135886
136598
|
let content = "";
|
|
135887
136599
|
let backupPath = null;
|
|
135888
|
-
if (
|
|
136600
|
+
if (existsSync36(configPath)) {
|
|
135889
136601
|
backupPath = `${configPath}.letta-backup`;
|
|
135890
136602
|
copyFileSync2(configPath, backupPath);
|
|
135891
136603
|
content = readFileSync18(configPath, { encoding: "utf-8" });
|
|
@@ -135914,11 +136626,11 @@ return config`);
|
|
|
135914
136626
|
${WEZTERM_DELETE_FIX2}
|
|
135915
136627
|
`;
|
|
135916
136628
|
}
|
|
135917
|
-
const parentDir =
|
|
135918
|
-
if (!
|
|
135919
|
-
|
|
136629
|
+
const parentDir = dirname18(configPath);
|
|
136630
|
+
if (!existsSync36(parentDir)) {
|
|
136631
|
+
mkdirSync23(parentDir, { recursive: true });
|
|
135920
136632
|
}
|
|
135921
|
-
|
|
136633
|
+
writeFileSync18(configPath, content, { encoding: "utf-8" });
|
|
135922
136634
|
return {
|
|
135923
136635
|
success: true,
|
|
135924
136636
|
backupPath: backupPath ?? undefined
|
|
@@ -135964,9 +136676,9 @@ __export(exports_settings2, {
|
|
|
135964
136676
|
getSetting: () => getSetting2
|
|
135965
136677
|
});
|
|
135966
136678
|
import { homedir as homedir37 } from "node:os";
|
|
135967
|
-
import { join as
|
|
136679
|
+
import { join as join47 } from "node:path";
|
|
135968
136680
|
function getSettingsPath2() {
|
|
135969
|
-
return
|
|
136681
|
+
return join47(homedir37(), ".letta", "settings.json");
|
|
135970
136682
|
}
|
|
135971
136683
|
async function loadSettings2() {
|
|
135972
136684
|
const settingsPath = getSettingsPath2();
|
|
@@ -136003,7 +136715,7 @@ async function getSetting2(key) {
|
|
|
136003
136715
|
return settings[key];
|
|
136004
136716
|
}
|
|
136005
136717
|
function getProjectSettingsPath2() {
|
|
136006
|
-
return
|
|
136718
|
+
return join47(process.cwd(), ".letta", "settings.local.json");
|
|
136007
136719
|
}
|
|
136008
136720
|
async function loadProjectSettings2() {
|
|
136009
136721
|
const settingsPath = getProjectSettingsPath2();
|
|
@@ -136021,7 +136733,7 @@ async function loadProjectSettings2() {
|
|
|
136021
136733
|
}
|
|
136022
136734
|
async function saveProjectSettings2(settings) {
|
|
136023
136735
|
const settingsPath = getProjectSettingsPath2();
|
|
136024
|
-
const dirPath =
|
|
136736
|
+
const dirPath = join47(process.cwd(), ".letta");
|
|
136025
136737
|
try {
|
|
136026
136738
|
if (!exists(dirPath)) {
|
|
136027
136739
|
await mkdir(dirPath, { recursive: true });
|
|
@@ -136484,7 +137196,7 @@ __export(exports_import2, {
|
|
|
136484
137196
|
});
|
|
136485
137197
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
136486
137198
|
import { chmod as chmod2, mkdir as mkdir8, readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
|
|
136487
|
-
import { dirname as
|
|
137199
|
+
import { dirname as dirname19, resolve as resolve31 } from "node:path";
|
|
136488
137200
|
async function importAgentFromFile2(options) {
|
|
136489
137201
|
const client = await getClient2();
|
|
136490
137202
|
const resolvedPath = resolve31(options.filePath);
|
|
@@ -136543,7 +137255,7 @@ async function writeSkillFiles2(skillDir, files) {
|
|
|
136543
137255
|
}
|
|
136544
137256
|
async function writeSkillFile2(skillDir, filePath, content) {
|
|
136545
137257
|
const fullPath = resolve31(skillDir, filePath);
|
|
136546
|
-
await mkdir8(
|
|
137258
|
+
await mkdir8(dirname19(fullPath), { recursive: true });
|
|
136547
137259
|
await writeFile8(fullPath, content, "utf-8");
|
|
136548
137260
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
136549
137261
|
if (isScript) {
|
|
@@ -136596,7 +137308,7 @@ function parseRegistryHandle2(handle) {
|
|
|
136596
137308
|
}
|
|
136597
137309
|
async function importAgentFromRegistry2(options) {
|
|
136598
137310
|
const { tmpdir: tmpdir7 } = await import("node:os");
|
|
136599
|
-
const { join:
|
|
137311
|
+
const { join: join48 } = await import("node:path");
|
|
136600
137312
|
const { writeFile: writeFile9, unlink: unlink3 } = await import("node:fs/promises");
|
|
136601
137313
|
const { author, name } = parseRegistryHandle2(options.handle);
|
|
136602
137314
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
|
|
@@ -136608,7 +137320,7 @@ async function importAgentFromRegistry2(options) {
|
|
|
136608
137320
|
throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
|
|
136609
137321
|
}
|
|
136610
137322
|
const afContent = await response.text();
|
|
136611
|
-
const tempPath =
|
|
137323
|
+
const tempPath = join48(tmpdir7(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
136612
137324
|
await writeFile9(tempPath, afContent, "utf-8");
|
|
136613
137325
|
try {
|
|
136614
137326
|
const result = await importAgentFromFile2({
|
|
@@ -136652,23 +137364,23 @@ __export(exports_memoryFilesystem2, {
|
|
|
136652
137364
|
MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR2,
|
|
136653
137365
|
MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR2
|
|
136654
137366
|
});
|
|
136655
|
-
import { existsSync as
|
|
137367
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync24 } from "node:fs";
|
|
136656
137368
|
import { homedir as homedir38 } from "node:os";
|
|
136657
|
-
import { join as
|
|
137369
|
+
import { join as join48 } from "node:path";
|
|
136658
137370
|
function getMemoryFilesystemRoot2(agentId, homeDir = homedir38()) {
|
|
136659
|
-
return
|
|
137371
|
+
return join48(homeDir, MEMORY_FS_ROOT2, MEMORY_FS_AGENTS_DIR2, agentId, MEMORY_FS_MEMORY_DIR2);
|
|
136660
137372
|
}
|
|
136661
137373
|
function getMemorySystemDir2(agentId, homeDir = homedir38()) {
|
|
136662
|
-
return
|
|
137374
|
+
return join48(getMemoryFilesystemRoot2(agentId, homeDir), MEMORY_SYSTEM_DIR2);
|
|
136663
137375
|
}
|
|
136664
137376
|
function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir38()) {
|
|
136665
137377
|
const root = getMemoryFilesystemRoot2(agentId, homeDir);
|
|
136666
137378
|
const systemDir = getMemorySystemDir2(agentId, homeDir);
|
|
136667
|
-
if (!
|
|
136668
|
-
|
|
137379
|
+
if (!existsSync37(root)) {
|
|
137380
|
+
mkdirSync24(root, { recursive: true });
|
|
136669
137381
|
}
|
|
136670
|
-
if (!
|
|
136671
|
-
|
|
137382
|
+
if (!existsSync37(systemDir)) {
|
|
137383
|
+
mkdirSync24(systemDir, { recursive: true });
|
|
136672
137384
|
}
|
|
136673
137385
|
}
|
|
136674
137386
|
function labelFromRelativePath2(relativePath) {
|
|
@@ -136836,6 +137548,10 @@ async function applyMemfsFlags2(agentId, memfsFlag, noMemfsFlag, options) {
|
|
|
136836
137548
|
const result = await pullMemory2(agentId);
|
|
136837
137549
|
pullSummary = result.summary;
|
|
136838
137550
|
}
|
|
137551
|
+
const { initSecretsFromServer: initSecretsFromServer2 } = await init_secretsStore().then(() => exports_secretsStore);
|
|
137552
|
+
try {
|
|
137553
|
+
await initSecretsFromServer2(agentId, getMemoryFilesystemRoot2(agentId));
|
|
137554
|
+
} catch {}
|
|
136839
137555
|
}
|
|
136840
137556
|
const action = memfsFlag || shouldAutoEnableFromTag ? "enabled" : noMemfsFlag ? "disabled" : "unchanged";
|
|
136841
137557
|
return {
|
|
@@ -140845,10 +141561,10 @@ async function runListenSubcommand(argv) {
|
|
|
140845
141561
|
|
|
140846
141562
|
// src/cli/subcommands/memfs.ts
|
|
140847
141563
|
await init_memoryGit();
|
|
140848
|
-
import { cpSync, existsSync as
|
|
141564
|
+
import { cpSync, existsSync as existsSync20, mkdirSync as mkdirSync14, rmSync as rmSync2, statSync as statSync6 } from "node:fs";
|
|
140849
141565
|
import { readdir as readdir5 } from "node:fs/promises";
|
|
140850
141566
|
import { homedir as homedir21 } from "node:os";
|
|
140851
|
-
import { join as
|
|
141567
|
+
import { join as join25 } from "node:path";
|
|
140852
141568
|
import { parseArgs as parseArgs6 } from "node:util";
|
|
140853
141569
|
function printUsage3() {
|
|
140854
141570
|
console.log(`
|
|
@@ -140873,7 +141589,7 @@ Examples:
|
|
|
140873
141589
|
letta memfs export --agent agent-123 --out /tmp/letta-memfs-agent-123
|
|
140874
141590
|
`.trim());
|
|
140875
141591
|
}
|
|
140876
|
-
function
|
|
141592
|
+
function getAgentId4(agentFromArgs, agentIdFromArgs) {
|
|
140877
141593
|
return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
|
|
140878
141594
|
}
|
|
140879
141595
|
var MEMFS_OPTIONS = {
|
|
@@ -140893,10 +141609,10 @@ function parseMemfsArgs(argv) {
|
|
|
140893
141609
|
});
|
|
140894
141610
|
}
|
|
140895
141611
|
function getMemoryRoot(agentId) {
|
|
140896
|
-
return
|
|
141612
|
+
return join25(homedir21(), ".letta", "agents", agentId, "memory");
|
|
140897
141613
|
}
|
|
140898
141614
|
function getAgentRoot(agentId) {
|
|
140899
|
-
return
|
|
141615
|
+
return join25(homedir21(), ".letta", "agents", agentId);
|
|
140900
141616
|
}
|
|
140901
141617
|
function formatBackupTimestamp(date = new Date) {
|
|
140902
141618
|
const pad = (value) => String(value).padStart(2, "0");
|
|
@@ -140910,7 +141626,7 @@ function formatBackupTimestamp(date = new Date) {
|
|
|
140910
141626
|
}
|
|
140911
141627
|
async function listBackups(agentId) {
|
|
140912
141628
|
const agentRoot = getAgentRoot(agentId);
|
|
140913
|
-
if (!
|
|
141629
|
+
if (!existsSync20(agentRoot)) {
|
|
140914
141630
|
return [];
|
|
140915
141631
|
}
|
|
140916
141632
|
const entries = await readdir5(agentRoot, { withFileTypes: true });
|
|
@@ -140920,7 +141636,7 @@ async function listBackups(agentId) {
|
|
|
140920
141636
|
continue;
|
|
140921
141637
|
if (!entry.name.startsWith("memory-backup-"))
|
|
140922
141638
|
continue;
|
|
140923
|
-
const path23 =
|
|
141639
|
+
const path23 = join25(agentRoot, entry.name);
|
|
140924
141640
|
let createdAt = null;
|
|
140925
141641
|
try {
|
|
140926
141642
|
const stat6 = statSync6(path23);
|
|
@@ -140937,7 +141653,7 @@ function resolveBackupPath(agentId, from) {
|
|
|
140937
141653
|
if (from.startsWith("/") || /^[A-Za-z]:[/\\]/.test(from)) {
|
|
140938
141654
|
return from;
|
|
140939
141655
|
}
|
|
140940
|
-
return
|
|
141656
|
+
return join25(getAgentRoot(agentId), from);
|
|
140941
141657
|
}
|
|
140942
141658
|
async function runMemfsSubcommand(argv) {
|
|
140943
141659
|
let parsed;
|
|
@@ -140954,7 +141670,7 @@ async function runMemfsSubcommand(argv) {
|
|
|
140954
141670
|
printUsage3();
|
|
140955
141671
|
return 0;
|
|
140956
141672
|
}
|
|
140957
|
-
const agentId =
|
|
141673
|
+
const agentId = getAgentId4(parsed.values.agent, parsed.values["agent-id"]);
|
|
140958
141674
|
if (!agentId) {
|
|
140959
141675
|
console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
|
|
140960
141676
|
return 1;
|
|
@@ -140997,14 +141713,14 @@ async function runMemfsSubcommand(argv) {
|
|
|
140997
141713
|
}
|
|
140998
141714
|
if (action === "backup") {
|
|
140999
141715
|
const root = getMemoryRoot(agentId);
|
|
141000
|
-
if (!
|
|
141716
|
+
if (!existsSync20(root)) {
|
|
141001
141717
|
console.error(`Memory directory not found for agent ${agentId}.`);
|
|
141002
141718
|
return 1;
|
|
141003
141719
|
}
|
|
141004
141720
|
const agentRoot = getAgentRoot(agentId);
|
|
141005
141721
|
const backupName = `memory-backup-${formatBackupTimestamp()}`;
|
|
141006
|
-
const backupPath =
|
|
141007
|
-
if (
|
|
141722
|
+
const backupPath = join25(agentRoot, backupName);
|
|
141723
|
+
if (existsSync20(backupPath)) {
|
|
141008
141724
|
console.error(`Backup already exists at ${backupPath}`);
|
|
141009
141725
|
return 1;
|
|
141010
141726
|
}
|
|
@@ -141028,7 +141744,7 @@ async function runMemfsSubcommand(argv) {
|
|
|
141028
141744
|
return 1;
|
|
141029
141745
|
}
|
|
141030
141746
|
const backupPath = resolveBackupPath(agentId, from);
|
|
141031
|
-
if (!
|
|
141747
|
+
if (!existsSync20(backupPath)) {
|
|
141032
141748
|
console.error(`Backup not found: ${backupPath}`);
|
|
141033
141749
|
return 1;
|
|
141034
141750
|
}
|
|
@@ -141050,11 +141766,11 @@ async function runMemfsSubcommand(argv) {
|
|
|
141050
141766
|
return 1;
|
|
141051
141767
|
}
|
|
141052
141768
|
const root = getMemoryRoot(agentId);
|
|
141053
|
-
if (!
|
|
141769
|
+
if (!existsSync20(root)) {
|
|
141054
141770
|
console.error(`Memory directory not found for agent ${agentId}.`);
|
|
141055
141771
|
return 1;
|
|
141056
141772
|
}
|
|
141057
|
-
if (
|
|
141773
|
+
if (existsSync20(out)) {
|
|
141058
141774
|
const stat6 = statSync6(out);
|
|
141059
141775
|
if (stat6.isDirectory()) {
|
|
141060
141776
|
const contents = await readdir5(out);
|
|
@@ -141067,7 +141783,7 @@ async function runMemfsSubcommand(argv) {
|
|
|
141067
141783
|
return 1;
|
|
141068
141784
|
}
|
|
141069
141785
|
} else {
|
|
141070
|
-
|
|
141786
|
+
mkdirSync14(out, { recursive: true });
|
|
141071
141787
|
}
|
|
141072
141788
|
cpSync(root, out, { recursive: true });
|
|
141073
141789
|
console.log(JSON.stringify({ exportedFrom: root, exportedTo: out, agentId }, null, 2));
|
|
@@ -141137,7 +141853,7 @@ function parseOrder(value) {
|
|
|
141137
141853
|
}
|
|
141138
141854
|
return;
|
|
141139
141855
|
}
|
|
141140
|
-
function
|
|
141856
|
+
function getAgentId5(agentFromArgs, agentIdFromArgs) {
|
|
141141
141857
|
return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
|
|
141142
141858
|
}
|
|
141143
141859
|
var MESSAGES_OPTIONS = {
|
|
@@ -141186,7 +141902,7 @@ async function runMessagesSubcommand(argv) {
|
|
|
141186
141902
|
return 1;
|
|
141187
141903
|
}
|
|
141188
141904
|
const allAgents = parsed.values["all-agents"] ?? false;
|
|
141189
|
-
const agentId =
|
|
141905
|
+
const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
|
|
141190
141906
|
if (!allAgents && !agentId) {
|
|
141191
141907
|
console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
|
|
141192
141908
|
return 1;
|
|
@@ -141203,7 +141919,7 @@ async function runMessagesSubcommand(argv) {
|
|
|
141203
141919
|
return 0;
|
|
141204
141920
|
}
|
|
141205
141921
|
if (action === "list") {
|
|
141206
|
-
const agentId =
|
|
141922
|
+
const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
|
|
141207
141923
|
if (!agentId) {
|
|
141208
141924
|
console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
|
|
141209
141925
|
return 1;
|
|
@@ -141281,7 +141997,7 @@ async function runSubcommand(argv) {
|
|
|
141281
141997
|
init_readOnlyShell();
|
|
141282
141998
|
init_shell_command_normalization();
|
|
141283
141999
|
import { homedir as homedir22 } from "node:os";
|
|
141284
|
-
import { isAbsolute as isAbsolute16, join as
|
|
142000
|
+
import { isAbsolute as isAbsolute16, join as join26, relative as relative12, resolve as resolve23 } from "node:path";
|
|
141285
142001
|
var MODE_KEY2 = Symbol.for("@letta/permissionMode");
|
|
141286
142002
|
var PLAN_FILE_KEY2 = Symbol.for("@letta/planFilePath");
|
|
141287
142003
|
var MODE_BEFORE_PLAN_KEY2 = Symbol.for("@letta/permissionModeBeforePlan");
|
|
@@ -141510,7 +142226,7 @@ class PermissionModeManager2 {
|
|
|
141510
142226
|
return "allow";
|
|
141511
142227
|
}
|
|
141512
142228
|
if (writeTools.includes(toolName)) {
|
|
141513
|
-
const plansDir =
|
|
142229
|
+
const plansDir = join26(homedir22(), ".letta", "plans");
|
|
141514
142230
|
const targetPath = toolArgs?.file_path || toolArgs?.path;
|
|
141515
142231
|
let candidatePaths = [];
|
|
141516
142232
|
if ((toolName === "ApplyPatch" || toolName === "apply_patch" || toolName === "memory_apply_patch") && toolArgs?.input) {
|
|
@@ -141561,7 +142277,7 @@ class PermissionModeManager2 {
|
|
|
141561
142277
|
}
|
|
141562
142278
|
const planWritePath = extractPlanFileWritePathFromShellCommand2(command);
|
|
141563
142279
|
if (planWritePath) {
|
|
141564
|
-
const plansDir =
|
|
142280
|
+
const plansDir = join26(homedir22(), ".letta", "plans");
|
|
141565
142281
|
const resolvedPath = resolvePlanTargetPath2(planWritePath, workingDirectory);
|
|
141566
142282
|
if (resolvedPath && isPathInPlansDir2(resolvedPath, plansDir)) {
|
|
141567
142283
|
return "allow";
|
|
@@ -141590,7 +142306,7 @@ init_fs();
|
|
|
141590
142306
|
await init_secrets();
|
|
141591
142307
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
141592
142308
|
import { homedir as homedir23 } from "node:os";
|
|
141593
|
-
import { join as
|
|
142309
|
+
import { join as join27, resolve as resolve24 } from "node:path";
|
|
141594
142310
|
var DEFAULT_SETTINGS3 = {
|
|
141595
142311
|
lastAgent: null,
|
|
141596
142312
|
tokenStreaming: false,
|
|
@@ -141599,6 +142315,7 @@ var DEFAULT_SETTINGS3 = {
|
|
|
141599
142315
|
enableSleeptime: false,
|
|
141600
142316
|
conversationSwitchAlertEnabled: false,
|
|
141601
142317
|
sessionContextEnabled: true,
|
|
142318
|
+
autoSwapOnQuotaLimit: true,
|
|
141602
142319
|
memoryReminderInterval: 25,
|
|
141603
142320
|
reflectionTrigger: "step-count",
|
|
141604
142321
|
reflectionStepCount: 25,
|
|
@@ -141958,7 +142675,7 @@ class SettingsManager2 {
|
|
|
141958
142675
|
return;
|
|
141959
142676
|
const settingsPath = this.getSettingsPath();
|
|
141960
142677
|
const home = process.env.HOME || homedir23();
|
|
141961
|
-
const dirPath =
|
|
142678
|
+
const dirPath = join27(home, ".letta");
|
|
141962
142679
|
try {
|
|
141963
142680
|
if (!exists(dirPath)) {
|
|
141964
142681
|
await mkdir(dirPath, { recursive: true });
|
|
@@ -141997,7 +142714,7 @@ class SettingsManager2 {
|
|
|
141997
142714
|
if (!settings)
|
|
141998
142715
|
return;
|
|
141999
142716
|
const settingsPath = this.getProjectSettingsPath(workingDirectory);
|
|
142000
|
-
const dirPath =
|
|
142717
|
+
const dirPath = join27(workingDirectory, ".letta");
|
|
142001
142718
|
try {
|
|
142002
142719
|
let existingSettings = {};
|
|
142003
142720
|
if (exists(settingsPath)) {
|
|
@@ -142019,16 +142736,16 @@ class SettingsManager2 {
|
|
|
142019
142736
|
}
|
|
142020
142737
|
getSettingsPath() {
|
|
142021
142738
|
const home = process.env.HOME || homedir23();
|
|
142022
|
-
return
|
|
142739
|
+
return join27(home, ".letta", "settings.json");
|
|
142023
142740
|
}
|
|
142024
142741
|
getProjectSettingsPath(workingDirectory) {
|
|
142025
|
-
return
|
|
142742
|
+
return join27(workingDirectory, ".letta", "settings.json");
|
|
142026
142743
|
}
|
|
142027
142744
|
isProjectSettingsPathCollidingWithGlobal(workingDirectory) {
|
|
142028
142745
|
return resolve24(this.getProjectSettingsPath(workingDirectory)) === resolve24(this.getSettingsPath());
|
|
142029
142746
|
}
|
|
142030
142747
|
getLocalProjectSettingsPath(workingDirectory) {
|
|
142031
|
-
return
|
|
142748
|
+
return join27(workingDirectory, ".letta", "settings.local.json");
|
|
142032
142749
|
}
|
|
142033
142750
|
async loadLocalProjectSettings(workingDirectory = process.cwd()) {
|
|
142034
142751
|
const cached = this.localProjectSettings.get(workingDirectory);
|
|
@@ -142089,7 +142806,7 @@ class SettingsManager2 {
|
|
|
142089
142806
|
if (!settings)
|
|
142090
142807
|
return;
|
|
142091
142808
|
const settingsPath = this.getLocalProjectSettingsPath(workingDirectory);
|
|
142092
|
-
const dirPath =
|
|
142809
|
+
const dirPath = join27(workingDirectory, ".letta");
|
|
142093
142810
|
try {
|
|
142094
142811
|
if (!exists(dirPath)) {
|
|
142095
142812
|
await mkdir(dirPath, { recursive: true });
|
|
@@ -142199,6 +142916,11 @@ class SettingsManager2 {
|
|
|
142199
142916
|
}
|
|
142200
142917
|
return this.getGlobalLastAgentId();
|
|
142201
142918
|
}
|
|
142919
|
+
persistSession(agentId, conversationId, workingDirectory = process.cwd()) {
|
|
142920
|
+
const session = { agentId, conversationId };
|
|
142921
|
+
this.setLocalLastSession(session, workingDirectory);
|
|
142922
|
+
this.setGlobalLastSession(session);
|
|
142923
|
+
}
|
|
142202
142924
|
getGlobalPinnedAgents() {
|
|
142203
142925
|
const settings = this.getSettings();
|
|
142204
142926
|
const serverKey = getCurrentServerKey2(settings);
|
|
@@ -142438,7 +143160,7 @@ class SettingsManager2 {
|
|
|
142438
143160
|
this.upsertAgentSettings(agentId, { systemPromptPreset: "" });
|
|
142439
143161
|
}
|
|
142440
143162
|
hasLocalLettaDir(workingDirectory = process.cwd()) {
|
|
142441
|
-
const dirPath =
|
|
143163
|
+
const dirPath = join27(workingDirectory, ".letta");
|
|
142442
143164
|
return exists(dirPath);
|
|
142443
143165
|
}
|
|
142444
143166
|
storeOAuthState(state, codeVerifier, redirectUri, provider) {
|
|
@@ -142827,6 +143549,7 @@ await __promiseAll([
|
|
|
142827
143549
|
init_hooks(),
|
|
142828
143550
|
init_openai_codex_provider(),
|
|
142829
143551
|
init_telemetry(),
|
|
143552
|
+
init_secret_substitution(),
|
|
142830
143553
|
init_toolDefinitions()
|
|
142831
143554
|
]);
|
|
142832
143555
|
var FILE_MODIFYING_TOOLS2 = new Set([
|
|
@@ -143113,14 +143836,14 @@ async function clearPersistedClientToolRules2(agentId) {
|
|
|
143113
143836
|
// src/utils/debug.ts
|
|
143114
143837
|
import {
|
|
143115
143838
|
appendFileSync as appendFileSync3,
|
|
143116
|
-
existsSync as
|
|
143117
|
-
mkdirSync as
|
|
143839
|
+
existsSync as existsSync21,
|
|
143840
|
+
mkdirSync as mkdirSync15,
|
|
143118
143841
|
readdirSync as readdirSync10,
|
|
143119
143842
|
readFileSync as readFileSync10,
|
|
143120
143843
|
unlinkSync as unlinkSync6
|
|
143121
143844
|
} from "node:fs";
|
|
143122
143845
|
import { homedir as homedir24 } from "node:os";
|
|
143123
|
-
import { join as
|
|
143846
|
+
import { join as join28 } from "node:path";
|
|
143124
143847
|
import { format as format2 } from "node:util";
|
|
143125
143848
|
function isDebugEnabled2() {
|
|
143126
143849
|
const lettaDebug = process.env.LETTA_DEBUG;
|
|
@@ -143142,7 +143865,7 @@ function printDebugLine2(line, level = "log") {
|
|
|
143142
143865
|
const colored = level === "warn" ? `\x1B[38;5;167m${line.trimEnd()}\x1B[0m` : `\x1B[38;5;179m${line.trimEnd()}\x1B[0m`;
|
|
143143
143866
|
console.error(colored);
|
|
143144
143867
|
}
|
|
143145
|
-
var DEBUG_LOG_DIR2 =
|
|
143868
|
+
var DEBUG_LOG_DIR2 = join28(homedir24(), ".letta", "logs", "debug");
|
|
143146
143869
|
var MAX_SESSION_FILES3 = 5;
|
|
143147
143870
|
var DEFAULT_TAIL_LINES2 = 50;
|
|
143148
143871
|
|
|
@@ -143154,8 +143877,8 @@ class DebugLogFile2 {
|
|
|
143154
143877
|
const telem = process.env.LETTA_CODE_TELEM;
|
|
143155
143878
|
if (telem === "0" || telem === "false")
|
|
143156
143879
|
return;
|
|
143157
|
-
this.agentDir =
|
|
143158
|
-
this.logPath =
|
|
143880
|
+
this.agentDir = join28(DEBUG_LOG_DIR2, agentId);
|
|
143881
|
+
this.logPath = join28(this.agentDir, `${sessionId}.log`);
|
|
143159
143882
|
this.dirCreated = false;
|
|
143160
143883
|
this.pruneOldSessions();
|
|
143161
143884
|
}
|
|
@@ -143171,7 +143894,7 @@ class DebugLogFile2 {
|
|
|
143171
143894
|
if (!this.logPath)
|
|
143172
143895
|
return;
|
|
143173
143896
|
try {
|
|
143174
|
-
if (!
|
|
143897
|
+
if (!existsSync21(this.logPath))
|
|
143175
143898
|
return;
|
|
143176
143899
|
const content = readFileSync10(this.logPath, "utf8");
|
|
143177
143900
|
const lines = content.trimEnd().split(`
|
|
@@ -143186,8 +143909,8 @@ class DebugLogFile2 {
|
|
|
143186
143909
|
if (this.dirCreated || !this.agentDir)
|
|
143187
143910
|
return;
|
|
143188
143911
|
try {
|
|
143189
|
-
if (!
|
|
143190
|
-
|
|
143912
|
+
if (!existsSync21(this.agentDir)) {
|
|
143913
|
+
mkdirSync15(this.agentDir, { recursive: true });
|
|
143191
143914
|
}
|
|
143192
143915
|
this.dirCreated = true;
|
|
143193
143916
|
} catch {}
|
|
@@ -143196,14 +143919,14 @@ class DebugLogFile2 {
|
|
|
143196
143919
|
if (!this.agentDir)
|
|
143197
143920
|
return;
|
|
143198
143921
|
try {
|
|
143199
|
-
if (!
|
|
143922
|
+
if (!existsSync21(this.agentDir))
|
|
143200
143923
|
return;
|
|
143201
143924
|
const files = readdirSync10(this.agentDir).filter((f) => f.endsWith(".log")).sort();
|
|
143202
143925
|
if (files.length >= MAX_SESSION_FILES3) {
|
|
143203
143926
|
const toDelete = files.slice(0, files.length - MAX_SESSION_FILES3 + 1);
|
|
143204
143927
|
for (const file of toDelete) {
|
|
143205
143928
|
try {
|
|
143206
|
-
unlinkSync6(
|
|
143929
|
+
unlinkSync6(join28(this.agentDir, file));
|
|
143207
143930
|
} catch {}
|
|
143208
143931
|
}
|
|
143209
143932
|
}
|
|
@@ -143334,12 +144057,12 @@ EXAMPLES
|
|
|
143334
144057
|
console.log(usage);
|
|
143335
144058
|
}
|
|
143336
144059
|
async function printInfo() {
|
|
143337
|
-
const { join:
|
|
144060
|
+
const { join: join49 } = await import("path");
|
|
143338
144061
|
const { getVersion: getVersion3 } = await Promise.resolve().then(() => (init_version2(), exports_version));
|
|
143339
144062
|
const { SKILLS_DIR: SKILLS_DIR3 } = await Promise.resolve().then(() => (init_skills2(), exports_skills2));
|
|
143340
144063
|
const { exists: exists3 } = await Promise.resolve().then(() => (init_fs2(), exports_fs));
|
|
143341
144064
|
const cwd2 = process.cwd();
|
|
143342
|
-
const skillsDir =
|
|
144065
|
+
const skillsDir = join49(cwd2, SKILLS_DIR3);
|
|
143343
144066
|
const skillsExist = exists3(skillsDir);
|
|
143344
144067
|
await settingsManager2.loadLocalProjectSettings(cwd2);
|
|
143345
144068
|
const localPinned = settingsManager2.getLocalPinnedAgents(cwd2);
|
|
@@ -143724,9 +144447,9 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
143724
144447
|
}
|
|
143725
144448
|
} else {
|
|
143726
144449
|
const { resolve: resolve32 } = await import("path");
|
|
143727
|
-
const { existsSync:
|
|
144450
|
+
const { existsSync: existsSync38 } = await import("fs");
|
|
143728
144451
|
const resolvedPath = resolve32(fromAfFile);
|
|
143729
|
-
if (!
|
|
144452
|
+
if (!existsSync38(resolvedPath)) {
|
|
143730
144453
|
console.error(`Error: AgentFile not found: ${resolvedPath}`);
|
|
143731
144454
|
process.exit(1);
|
|
143732
144455
|
}
|
|
@@ -144050,6 +144773,13 @@ Error: ${message}`);
|
|
|
144050
144773
|
process.exit(1);
|
|
144051
144774
|
}
|
|
144052
144775
|
if (forceNew2 || agentIdArg || fromAfFile2) {
|
|
144776
|
+
if (agentIdArg && !forceNew2 && !fromAfFile2 && !forceNewConversation) {
|
|
144777
|
+
await settingsManager2.loadLocalProjectSettings(process.cwd());
|
|
144778
|
+
const localSession2 = settingsManager2.getLocalLastSession(process.cwd());
|
|
144779
|
+
if (localSession2?.agentId === agentIdArg && localSession2.conversationId && localSession2.conversationId !== "default") {
|
|
144780
|
+
setSelectedConversationId(localSession2.conversationId);
|
|
144781
|
+
}
|
|
144782
|
+
}
|
|
144053
144783
|
setLoadingState("assembling");
|
|
144054
144784
|
return;
|
|
144055
144785
|
}
|
|
@@ -144442,11 +145172,7 @@ Error: ${message}`);
|
|
|
144442
145172
|
}
|
|
144443
145173
|
}
|
|
144444
145174
|
if (!isSubagent) {
|
|
144445
|
-
settingsManager2.
|
|
144446
|
-
settingsManager2.setGlobalLastSession({
|
|
144447
|
-
agentId: agent.id,
|
|
144448
|
-
conversationId: conversationIdToUse
|
|
144449
|
-
});
|
|
145175
|
+
settingsManager2.persistSession(agent.id, conversationIdToUse);
|
|
144450
145176
|
}
|
|
144451
145177
|
setAgentId(agent.id);
|
|
144452
145178
|
setAgentState(agent);
|
|
@@ -144590,4 +145316,4 @@ Error during initialization: ${message}`);
|
|
|
144590
145316
|
}
|
|
144591
145317
|
main();
|
|
144592
145318
|
|
|
144593
|
-
//# debugId=
|
|
145319
|
+
//# debugId=773D326804039A9D64756E2164756E21
|