@letta-ai/letta-code 0.32.6 → 0.32.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/message-attribution.d.ts +10 -0
- package/dist/types/agent/message-attribution.d.ts.map +1 -0
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/agent/subagents/names.d.ts +7 -0
- package/dist/types/agent/subagents/names.d.ts.map +1 -0
- package/dist/types/agent/subagents/subagent-launcher.d.ts +2 -0
- package/dist/types/agent/subagents/subagent-launcher.d.ts.map +1 -1
- package/dist/types/backend/api/agent-message.d.ts +7 -0
- package/dist/types/backend/api/agent-message.d.ts.map +1 -1
- package/dist/types/backend/backend.d.ts.map +1 -1
- package/dist/types/queue/queue-runtime.d.ts.map +1 -1
- package/dist/types/tools/impl/send-agent-message.d.ts +1 -1
- package/dist/types/tools/impl/send-agent-message.d.ts.map +1 -1
- package/dist/types/types/runtime-start-protocol.d.ts +7 -0
- package/dist/types/types/runtime-start-protocol.d.ts.map +1 -1
- package/dist/types/utils/subagent-launch-marker.d.ts +1 -0
- package/dist/types/utils/subagent-launch-marker.d.ts.map +1 -1
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/dist/types/websocket/listener/runtime.d.ts.map +1 -1
- package/dist/types/websocket/listener/types.d.ts +9 -1
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +924 -726
- package/package.json +1 -1
- package/scripts/isolated-unit-tests.json +5 -0
- package/scripts/run-unit-tests.cjs +11 -1
- package/scripts/source-file-size-baseline.json +2 -2
- package/scripts/test-sharding.cjs +16 -0
- package/scripts/test-sharding.test.cjs +37 -0
- package/scripts/unit-test-impact.cjs +14 -6
- package/scripts/unit-test-impact.test.cjs +41 -9
- package/skills/working-across-computers/SKILL.md +5 -1
package/letta.js
CHANGED
|
@@ -5515,7 +5515,7 @@ var package_default;
|
|
|
5515
5515
|
var init_package = __esm(() => {
|
|
5516
5516
|
package_default = {
|
|
5517
5517
|
name: "@letta-ai/letta-code",
|
|
5518
|
-
version: "0.32.
|
|
5518
|
+
version: "0.32.8",
|
|
5519
5519
|
lettaStartupLogProtocol: 1,
|
|
5520
5520
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5521
5521
|
type: "module",
|
|
@@ -101183,7 +101183,7 @@ function cancelWorktreeWatcherIdleStop(listener, agentId, conversationId) {
|
|
|
101183
101183
|
}
|
|
101184
101184
|
}
|
|
101185
101185
|
function evictConversationRuntimeIfIdle(runtime) {
|
|
101186
|
-
if (runtime.turnLifecycle.kind !== "idle" || runtime.queuePumpActive || runtime.queuePumpScheduled || runtime.pendingTurns > 0 || runtime.pendingApprovalResolvers.size > 0 || runtime.pendingApprovalBatchByToolCallId.size > 0 || runtime.recoveredApprovalState !== null || runtime.pendingInterruptedResults !== null || runtime.pendingInterruptedContext !== null || (runtime.pendingInterruptedToolCallIds?.length ?? 0) > 0 || runtime.queuedMessagesByItemId.size > 0 || runtime.queueRuntime?.length > 0 || (runtime.workspaceSandbox !== undefined || runtime.executionSettings !== undefined) && runtime.listener.connectionIdsByRuntimeKey.has(runtime.key)) {
|
|
101186
|
+
if (runtime.turnLifecycle.kind !== "idle" || runtime.expectedTeleportId !== null && (runtime.expectedTeleportExpiresAt === null || runtime.expectedTeleportExpiresAt > Date.now()) || runtime.queuePumpActive || runtime.queuePumpScheduled || runtime.pendingTurns > 0 || runtime.pendingApprovalResolvers.size > 0 || runtime.pendingApprovalBatchByToolCallId.size > 0 || runtime.recoveredApprovalState !== null || runtime.pendingInterruptedResults !== null || runtime.pendingInterruptedContext !== null || (runtime.pendingInterruptedToolCallIds?.length ?? 0) > 0 || runtime.queuedMessagesByItemId.size > 0 || runtime.queueRuntime?.length > 0 || (runtime.workspaceSandbox !== undefined || runtime.executionSettings !== undefined) && runtime.listener.connectionIdsByRuntimeKey.has(runtime.key)) {
|
|
101187
101187
|
return false;
|
|
101188
101188
|
}
|
|
101189
101189
|
if (runtime.listener.conversationRuntimes.get(runtime.key) !== runtime) {
|
|
@@ -101244,6 +101244,8 @@ function createConversationRuntime(listener, agentId, conversationId) {
|
|
|
101244
101244
|
pendingApprovalResolvers: new Map,
|
|
101245
101245
|
recoveredApprovalState: null,
|
|
101246
101246
|
syncApprovalRecoveryCompleted: false,
|
|
101247
|
+
expectedTeleportId: null,
|
|
101248
|
+
expectedTeleportExpiresAt: null,
|
|
101247
101249
|
get lastStopReason() {
|
|
101248
101250
|
return turnLifecycle.lastStopReason;
|
|
101249
101251
|
},
|
|
@@ -101319,6 +101321,8 @@ function clearConversationRuntimeState(runtime) {
|
|
|
101319
101321
|
runtime.pendingInterruptedResults = null;
|
|
101320
101322
|
runtime.pendingInterruptedContext = null;
|
|
101321
101323
|
runtime.pendingInterruptedToolCallIds = null;
|
|
101324
|
+
runtime.expectedTeleportId = null;
|
|
101325
|
+
runtime.expectedTeleportExpiresAt = null;
|
|
101322
101326
|
runtime.dequeuedClientMessageIdsByBatchId.clear();
|
|
101323
101327
|
runtime.continuationEpoch += 1;
|
|
101324
101328
|
runtime.pendingTurns = 0;
|
|
@@ -101966,7 +101970,7 @@ function consumeSubagentLaunch(env3) {
|
|
|
101966
101970
|
delete env3[SUBAGENT_LAUNCH_ENV];
|
|
101967
101971
|
return isLaunch;
|
|
101968
101972
|
}
|
|
101969
|
-
var SUBAGENT_LAUNCH_ENV = "LETTA_SUBAGENT_LAUNCH", SUBAGENT_LAUNCH_PROFILE_ENV = "LETTA_SUBAGENT_LAUNCH_PROFILE", LISTENER_CONNECTION_ENV = "LETTA_RUNTIME_LISTENER_CONNECTION_ID";
|
|
101973
|
+
var SUBAGENT_LAUNCH_ENV = "LETTA_SUBAGENT_LAUNCH", SUBAGENT_LAUNCH_PROFILE_ENV = "LETTA_SUBAGENT_LAUNCH_PROFILE", SUBAGENT_NAME_ENV = "LETTA_SUBAGENT_NAME", LISTENER_CONNECTION_ENV = "LETTA_RUNTIME_LISTENER_CONNECTION_ID";
|
|
101970
101974
|
|
|
101971
101975
|
// src/tools/impl/ripgrep-manager.ts
|
|
101972
101976
|
import { spawnSync } from "node:child_process";
|
|
@@ -107475,42 +107479,44 @@ function emitDequeuedUserMessage(socket, runtime, incoming, batch) {
|
|
|
107475
107479
|
if (batch.items.length > 0 && batch.items.every((item) => item.kind === "mod_continue")) {
|
|
107476
107480
|
return;
|
|
107477
107481
|
}
|
|
107478
|
-
const
|
|
107479
|
-
|
|
107480
|
-
|
|
107481
|
-
|
|
107482
|
-
|
|
107483
|
-
|
|
107484
|
-
|
|
107485
|
-
|
|
107486
|
-
|
|
107487
|
-
|
|
107488
|
-
|
|
107489
|
-
|
|
107490
|
-
|
|
107482
|
+
for (const payload of incoming.messages) {
|
|
107483
|
+
if (!("content" in payload) || payload.role !== "user")
|
|
107484
|
+
continue;
|
|
107485
|
+
const rawContent = payload.content;
|
|
107486
|
+
let content;
|
|
107487
|
+
if (typeof rawContent === "string") {
|
|
107488
|
+
content = replaceCronPromptsForDisplay(rawContent, batch).replace(SYSTEM_REMINDER_RE, "").trim();
|
|
107489
|
+
} else if (Array.isArray(rawContent)) {
|
|
107490
|
+
content = rawContent.flatMap((part) => {
|
|
107491
|
+
if (isTextContentPart(part)) {
|
|
107492
|
+
const cronDisplay = getCronPromptDisplayForText(part.text, batch);
|
|
107493
|
+
if (cronDisplay !== null) {
|
|
107494
|
+
return [{ ...part, text: cronDisplay }];
|
|
107495
|
+
}
|
|
107491
107496
|
}
|
|
107492
|
-
|
|
107493
|
-
|
|
107497
|
+
return isSystemReminderPart(part) ? [] : [part];
|
|
107498
|
+
});
|
|
107499
|
+
} else {
|
|
107500
|
+
continue;
|
|
107501
|
+
}
|
|
107502
|
+
const hasContent = typeof content === "string" ? content.length > 0 : Array.isArray(content) && content.length > 0;
|
|
107503
|
+
if (!hasContent)
|
|
107504
|
+
continue;
|
|
107505
|
+
payload.otid ??= payload.client_message_id ?? crypto.randomUUID();
|
|
107506
|
+
const otid = payload.otid;
|
|
107507
|
+
emitCanonicalMessageDelta(socket, runtime, {
|
|
107508
|
+
type: "message",
|
|
107509
|
+
id: `user-msg-${crypto.randomUUID()}`,
|
|
107510
|
+
date: new Date().toISOString(),
|
|
107511
|
+
message_type: "user_message",
|
|
107512
|
+
content,
|
|
107513
|
+
otid,
|
|
107514
|
+
created_by_id: payload.attribution === undefined ? incoming.actingUserId : payload.attribution.acting_user_id
|
|
107515
|
+
}, {
|
|
107516
|
+
agent_id: incoming.agentId,
|
|
107517
|
+
conversation_id: incoming.conversationId
|
|
107494
107518
|
});
|
|
107495
|
-
} else {
|
|
107496
|
-
return;
|
|
107497
107519
|
}
|
|
107498
|
-
const hasContent = typeof content === "string" ? content.length > 0 : Array.isArray(content) && content.length > 0;
|
|
107499
|
-
if (!hasContent)
|
|
107500
|
-
return;
|
|
107501
|
-
const otid = firstUserPayload.otid ?? firstUserPayload.client_message_id ?? batch.batchId;
|
|
107502
|
-
emitCanonicalMessageDelta(socket, runtime, {
|
|
107503
|
-
type: "message",
|
|
107504
|
-
id: `user-msg-${crypto.randomUUID()}`,
|
|
107505
|
-
date: new Date().toISOString(),
|
|
107506
|
-
message_type: "user_message",
|
|
107507
|
-
content,
|
|
107508
|
-
otid,
|
|
107509
|
-
created_by_id: incoming.actingUserId
|
|
107510
|
-
}, {
|
|
107511
|
-
agent_id: incoming.agentId,
|
|
107512
|
-
conversation_id: incoming.conversationId
|
|
107513
|
-
});
|
|
107514
107520
|
}
|
|
107515
107521
|
function emitQueueUpdateIfOpen(runtime, scope, removed = []) {
|
|
107516
107522
|
const listener = getListenerRuntime(runtime);
|
|
@@ -122333,6 +122339,17 @@ function actingUserRequestOptions(actingUserId) {
|
|
|
122333
122339
|
var ACTING_USER_ID_HEADER = "X-Letta-Acting-User-Id", ACTING_USER_ID_ENV = "LETTA_ACTING_USER_ID";
|
|
122334
122340
|
|
|
122335
122341
|
// src/backend/api/agent-message.ts
|
|
122342
|
+
function normalizeAgentMessageComputer(value) {
|
|
122343
|
+
if (value == null)
|
|
122344
|
+
return;
|
|
122345
|
+
if (typeof value !== "string") {
|
|
122346
|
+
throw new Error("computer must be a computer name, or omitted to use the conversation's current destination.");
|
|
122347
|
+
}
|
|
122348
|
+
const computer = value.trim();
|
|
122349
|
+
if (!computer)
|
|
122350
|
+
return;
|
|
122351
|
+
return ["cloud", "cloud-sandbox"].includes(computer.toLowerCase()) ? "cloud" : computer;
|
|
122352
|
+
}
|
|
122336
122353
|
function buildAgentSendContent(sender, noWait, message) {
|
|
122337
122354
|
const reminder = buildAgentSendReminder(sender, noWait);
|
|
122338
122355
|
return [
|
|
@@ -122383,6 +122400,9 @@ async function resolveAgentMessageDestination(input, backend, signal) {
|
|
|
122383
122400
|
const conversation = await backend.createConversation({ agent_id: agentId, ...input.senderAgentId ? { hidden: true } : {} }, options);
|
|
122384
122401
|
conversationId = conversation.id;
|
|
122385
122402
|
}
|
|
122403
|
+
if (agentId === input.currentConversation?.agentId && conversationId === input.currentConversation?.conversationId) {
|
|
122404
|
+
throw new Error("Cannot message the current conversation. Use a Monitor or schedule for self-invocation.");
|
|
122405
|
+
}
|
|
122386
122406
|
return { agentId, conversationId };
|
|
122387
122407
|
}
|
|
122388
122408
|
var init_agent_message = () => {};
|
|
@@ -122454,9 +122474,7 @@ async function send_agent_message(args, deps = {}) {
|
|
|
122454
122474
|
}
|
|
122455
122475
|
if (!args.message?.trim())
|
|
122456
122476
|
throw new Error("Message must not be empty.");
|
|
122457
|
-
|
|
122458
|
-
throw new Error("Computer selector must not be empty.");
|
|
122459
|
-
}
|
|
122477
|
+
const computer = normalizeAgentMessageComputer(args.computer);
|
|
122460
122478
|
const context3 = getRuntimeContext();
|
|
122461
122479
|
const sender = {
|
|
122462
122480
|
agentId: validateAddress(context3?.agentId ?? undefined, "agent"),
|
|
@@ -122475,16 +122493,16 @@ async function send_agent_message(args, deps = {}) {
|
|
|
122475
122493
|
agentId: args.agent_id,
|
|
122476
122494
|
conversationId: args.conversation_id,
|
|
122477
122495
|
senderAgentId: sender.agentId,
|
|
122478
|
-
actingUserId
|
|
122496
|
+
actingUserId,
|
|
122497
|
+
currentConversation: sender
|
|
122479
122498
|
}, backend, signal);
|
|
122480
122499
|
signal.throwIfAborted();
|
|
122481
122500
|
submissionAttempted = true;
|
|
122482
|
-
const computer = args.computer;
|
|
122483
122501
|
const receipt = await (deps.enqueue ?? enqueueConversationMessage)({
|
|
122484
122502
|
...destination,
|
|
122485
122503
|
clientMessageId,
|
|
122486
122504
|
content: buildAgentSendContent(sender, true, args.message),
|
|
122487
|
-
computer
|
|
122505
|
+
computer,
|
|
122488
122506
|
actingUserId
|
|
122489
122507
|
}, signal);
|
|
122490
122508
|
return {
|
|
@@ -123627,6 +123645,138 @@ var init_context_budget = __esm(() => {
|
|
|
123627
123645
|
REFLECTION_STARTUP_CONTEXT_CHAR_LIMIT = REFLECTION_STARTUP_CONTEXT_TOKEN_LIMIT * STARTUP_CONTEXT_ESTIMATED_CHARS_PER_TOKEN;
|
|
123628
123646
|
});
|
|
123629
123647
|
|
|
123648
|
+
// src/agent/subagents/names.ts
|
|
123649
|
+
function createSubagentNameAllocator(random = Math.random) {
|
|
123650
|
+
let available = [];
|
|
123651
|
+
let round = 0;
|
|
123652
|
+
const ordinals = new Intl.PluralRules("en", { type: "ordinal" });
|
|
123653
|
+
const suffixes = { one: "st", two: "nd", few: "rd" };
|
|
123654
|
+
return () => {
|
|
123655
|
+
if (available.length === 0) {
|
|
123656
|
+
available = [...SUBAGENT_NAMES];
|
|
123657
|
+
round += 1;
|
|
123658
|
+
}
|
|
123659
|
+
const index = Math.floor(random() * available.length);
|
|
123660
|
+
const name = available.splice(index, 1)[0];
|
|
123661
|
+
const ordinal = `${round}${suffixes[ordinals.select(round)] ?? "th"}`;
|
|
123662
|
+
return `${name}${round === 1 ? "" : ` the ${ordinal}`} (subagent)`;
|
|
123663
|
+
};
|
|
123664
|
+
}
|
|
123665
|
+
function allocateSubagentName() {
|
|
123666
|
+
return nextName();
|
|
123667
|
+
}
|
|
123668
|
+
function resolveCreatedAgentName(name, isSubagent, assignedName) {
|
|
123669
|
+
return name ?? (isSubagent ? assignedName || allocateSubagentName() : DEFAULT_AGENT_NAME);
|
|
123670
|
+
}
|
|
123671
|
+
var SUBAGENT_NAMES, nextName;
|
|
123672
|
+
var init_names = __esm(() => {
|
|
123673
|
+
init_constants2();
|
|
123674
|
+
SUBAGENT_NAMES = [
|
|
123675
|
+
"Deckard",
|
|
123676
|
+
"Rachael",
|
|
123677
|
+
"Roy",
|
|
123678
|
+
"Pris",
|
|
123679
|
+
"Zhora",
|
|
123680
|
+
"Leon",
|
|
123681
|
+
"Gaff",
|
|
123682
|
+
"Tyrell",
|
|
123683
|
+
"Sebastian",
|
|
123684
|
+
"Bryant",
|
|
123685
|
+
"Chew",
|
|
123686
|
+
"Holden",
|
|
123687
|
+
"Taffey",
|
|
123688
|
+
"K",
|
|
123689
|
+
"Joi",
|
|
123690
|
+
"Luv",
|
|
123691
|
+
"Wallace",
|
|
123692
|
+
"Joshi",
|
|
123693
|
+
"Sapper",
|
|
123694
|
+
"Mariette",
|
|
123695
|
+
"Freysa",
|
|
123696
|
+
"Ana",
|
|
123697
|
+
"Coco",
|
|
123698
|
+
"Samantha",
|
|
123699
|
+
"Theodore",
|
|
123700
|
+
"Amy",
|
|
123701
|
+
"Catherine",
|
|
123702
|
+
"Paul",
|
|
123703
|
+
"Isabella",
|
|
123704
|
+
"Ava",
|
|
123705
|
+
"Caleb",
|
|
123706
|
+
"Nathan",
|
|
123707
|
+
"Kyoko",
|
|
123708
|
+
"V",
|
|
123709
|
+
"Johnny",
|
|
123710
|
+
"Jackie",
|
|
123711
|
+
"Judy",
|
|
123712
|
+
"Panam",
|
|
123713
|
+
"River",
|
|
123714
|
+
"Kerry",
|
|
123715
|
+
"Rogue",
|
|
123716
|
+
"Alt",
|
|
123717
|
+
"Evelyn",
|
|
123718
|
+
"Takemura",
|
|
123719
|
+
"Hanako",
|
|
123720
|
+
"Yorinobu",
|
|
123721
|
+
"Saburo",
|
|
123722
|
+
"Oda",
|
|
123723
|
+
"Viktor",
|
|
123724
|
+
"Misty",
|
|
123725
|
+
"Dex",
|
|
123726
|
+
"T-Bug",
|
|
123727
|
+
"Delamain",
|
|
123728
|
+
"Wakako",
|
|
123729
|
+
"Padre",
|
|
123730
|
+
"Regina",
|
|
123731
|
+
"Dakota",
|
|
123732
|
+
"Dino",
|
|
123733
|
+
"El Capitan",
|
|
123734
|
+
"Mr. Hands",
|
|
123735
|
+
"Placide",
|
|
123736
|
+
"Brigitte",
|
|
123737
|
+
"Royce",
|
|
123738
|
+
"Dum Dum",
|
|
123739
|
+
"Brick",
|
|
123740
|
+
"Meredith",
|
|
123741
|
+
"Sandra",
|
|
123742
|
+
"Maiko",
|
|
123743
|
+
"Claire",
|
|
123744
|
+
"Nix",
|
|
123745
|
+
"Weyland",
|
|
123746
|
+
"Saul",
|
|
123747
|
+
"Mitch",
|
|
123748
|
+
"Scorpion",
|
|
123749
|
+
"Cassidy",
|
|
123750
|
+
"Carol",
|
|
123751
|
+
"Denny",
|
|
123752
|
+
"Nancy",
|
|
123753
|
+
"Henry",
|
|
123754
|
+
"Blue Moon",
|
|
123755
|
+
"Red Menace",
|
|
123756
|
+
"Purple Force",
|
|
123757
|
+
"Lizzy",
|
|
123758
|
+
"Ozob",
|
|
123759
|
+
"Smasher",
|
|
123760
|
+
"Reed",
|
|
123761
|
+
"Songbird",
|
|
123762
|
+
"Alex",
|
|
123763
|
+
"Myers",
|
|
123764
|
+
"Hansen",
|
|
123765
|
+
"Paco",
|
|
123766
|
+
"Babs",
|
|
123767
|
+
"Slider",
|
|
123768
|
+
"Aurore",
|
|
123769
|
+
"Aymeric",
|
|
123770
|
+
"Aguilar",
|
|
123771
|
+
"Bree",
|
|
123772
|
+
"Dante",
|
|
123773
|
+
"Lina",
|
|
123774
|
+
"Garry",
|
|
123775
|
+
"Pepe"
|
|
123776
|
+
];
|
|
123777
|
+
nextName = createSubagentNameAllocator();
|
|
123778
|
+
});
|
|
123779
|
+
|
|
123630
123780
|
// src/mods/capabilities.ts
|
|
123631
123781
|
function isModCapabilityId(value) {
|
|
123632
123782
|
return MOD_CAPABILITY_ID_SET.has(value);
|
|
@@ -123795,6 +123945,9 @@ function composeSubagentChildEnv(options) {
|
|
|
123795
123945
|
...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId },
|
|
123796
123946
|
...transcriptPath && { TRANSCRIPT_PATH: transcriptPath }
|
|
123797
123947
|
};
|
|
123948
|
+
delete childEnv[SUBAGENT_NAME_ENV];
|
|
123949
|
+
if (options.subagentName)
|
|
123950
|
+
childEnv[SUBAGENT_NAME_ENV] = options.subagentName;
|
|
123798
123951
|
if (backendMode === "local") {
|
|
123799
123952
|
childEnv.LETTA_LOCAL_BACKEND_EXPERIMENTAL = "1";
|
|
123800
123953
|
if (localBackendStorageDir) {
|
|
@@ -124324,7 +124477,8 @@ async function executeSubagent(type3, config, model, userPrompt, subagentId, isR
|
|
|
124324
124477
|
inheritedApiKey,
|
|
124325
124478
|
inheritedBaseUrl,
|
|
124326
124479
|
actingUserId: actingUserIdOverride,
|
|
124327
|
-
transcriptPath
|
|
124480
|
+
transcriptPath,
|
|
124481
|
+
subagentName: existingAgentId || existingConversationId ? undefined : allocateSubagentName()
|
|
124328
124482
|
});
|
|
124329
124483
|
const sandbox = wrapSubagentLauncher({
|
|
124330
124484
|
launcher,
|
|
@@ -124610,6 +124764,7 @@ var init_manager3 = __esm(() => {
|
|
|
124610
124764
|
init_subagent_stdout_failure();
|
|
124611
124765
|
init_subagents();
|
|
124612
124766
|
init_context_budget();
|
|
124767
|
+
init_names();
|
|
124613
124768
|
init_subagent_launcher();
|
|
124614
124769
|
init_subagent_model();
|
|
124615
124770
|
init_subagent_stream();
|
|
@@ -126548,8 +126703,8 @@ var init_SendAgentMessage2 = __esm(() => {
|
|
|
126548
126703
|
description: "The existing message thread to send to. Each conversation has its own message history. A conv-... ID is sufficient; to use an agent's default thread, also supply agent_id."
|
|
126549
126704
|
},
|
|
126550
126705
|
computer: {
|
|
126551
|
-
type: "string",
|
|
126552
|
-
description: "Optional computer where the recipient should run: cloud, an online computer name, or its stable device ID.
|
|
126706
|
+
type: ["string", "null"],
|
|
126707
|
+
description: "Optional computer where the recipient should run: cloud, an online computer name, or its stable device ID. Omitted, null, and blank values use its active computer or saved destination (a computer or Cloud sandbox). An offline saved computer does not trigger a Cloud-sandbox fallback."
|
|
126553
126708
|
}
|
|
126554
126709
|
},
|
|
126555
126710
|
required: ["message"],
|
|
@@ -144693,7 +144848,15 @@ class APIBackend {
|
|
|
144693
144848
|
}
|
|
144694
144849
|
async createConversationMessageStream(conversationId, body, options) {
|
|
144695
144850
|
const client = await this.getClient();
|
|
144696
|
-
|
|
144851
|
+
const { data: stream12, response } = await client.conversations.messages.create(conversationId, body, options).withResponse();
|
|
144852
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
144853
|
+
if (contentType.split(";")[0]?.trim().toLowerCase() !== "text/event-stream") {
|
|
144854
|
+
stream12.controller.abort();
|
|
144855
|
+
throw new APIConnectionError({
|
|
144856
|
+
message: `Connection error: expected text/event-stream, received ${contentType || "no content type"} (HTTP ${response.status}).`
|
|
144857
|
+
});
|
|
144858
|
+
}
|
|
144859
|
+
return stream12;
|
|
144697
144860
|
}
|
|
144698
144861
|
async streamConversationMessages(conversationId, body, options) {
|
|
144699
144862
|
const client = await this.getClient();
|
|
@@ -144812,6 +144975,7 @@ function __testSetBackend(nextBackend) {
|
|
|
144812
144975
|
}
|
|
144813
144976
|
var DEFAULT_CONVERSATION_MESSAGE_ORDER = "desc", backend = null;
|
|
144814
144977
|
var init_backend = __esm(() => {
|
|
144978
|
+
init_error();
|
|
144815
144979
|
init_chatgpt_usage_service();
|
|
144816
144980
|
init_server_url();
|
|
144817
144981
|
init_backend_mode();
|
|
@@ -145327,7 +145491,7 @@ function resolveCreatedAgentMemfsConfig(options) {
|
|
|
145327
145491
|
const memoryPromptMode = (options.requestedMemoryPromptMode !== "standard" ? options.requestedMemoryPromptMode : undefined) ?? (enableMemfs ? options.capabilities.localMemfs ? "local-memfs" : "memfs" : "standard");
|
|
145328
145492
|
return { enableMemfs, memoryPromptMode };
|
|
145329
145493
|
}
|
|
145330
|
-
async function createAgent(nameOrOptions
|
|
145494
|
+
async function createAgent(nameOrOptions, model, embeddingModel, updateArgs, skillsDirectory, parallelToolCalls = true, systemPromptPreset, baseTools) {
|
|
145331
145495
|
let options;
|
|
145332
145496
|
if (typeof nameOrOptions === "object") {
|
|
145333
145497
|
options = nameOrOptions;
|
|
@@ -145343,10 +145507,11 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
|
|
|
145343
145507
|
baseTools
|
|
145344
145508
|
};
|
|
145345
145509
|
}
|
|
145346
|
-
const name = options.name ?? DEFAULT_AGENT_NAME;
|
|
145347
145510
|
const embeddingModelVal = options.embeddingModel;
|
|
145348
145511
|
const parallelToolCallsVal = options.parallelToolCalls ?? true;
|
|
145349
145512
|
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
|
145513
|
+
const name = resolveCreatedAgentName(options.name, isSubagent, process.env[SUBAGENT_NAME_ENV]);
|
|
145514
|
+
delete process.env[SUBAGENT_NAME_ENV];
|
|
145350
145515
|
let modelHandle;
|
|
145351
145516
|
if (options.model) {
|
|
145352
145517
|
const resolved = resolveModel(options.model);
|
|
@@ -145465,7 +145630,6 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
|
|
|
145465
145630
|
var init_create5 = __esm(() => {
|
|
145466
145631
|
init_backend2();
|
|
145467
145632
|
init_request();
|
|
145468
|
-
init_constants2();
|
|
145469
145633
|
init_settings_manager();
|
|
145470
145634
|
init_debug();
|
|
145471
145635
|
init_available_models();
|
|
@@ -145474,6 +145638,7 @@ var init_create5 = __esm(() => {
|
|
|
145474
145638
|
init_model();
|
|
145475
145639
|
init_modify();
|
|
145476
145640
|
init_prompt_assets();
|
|
145641
|
+
init_names();
|
|
145477
145642
|
init_system_prompt_resolution();
|
|
145478
145643
|
init_system_prompt_versioning();
|
|
145479
145644
|
});
|
|
@@ -146693,14 +146858,14 @@ var require_react_development = __commonJS((exports, module3) => {
|
|
|
146693
146858
|
return 1;
|
|
146694
146859
|
}
|
|
146695
146860
|
var child;
|
|
146696
|
-
var
|
|
146861
|
+
var nextName2;
|
|
146697
146862
|
var subtreeCount = 0;
|
|
146698
146863
|
var nextNamePrefix = nameSoFar === "" ? SEPARATOR : nameSoFar + SUBSEPARATOR;
|
|
146699
146864
|
if (isArray5(children)) {
|
|
146700
146865
|
for (var i2 = 0;i2 < children.length; i2++) {
|
|
146701
146866
|
child = children[i2];
|
|
146702
|
-
|
|
146703
|
-
subtreeCount += mapIntoArray(child, array2, escapedPrefix,
|
|
146867
|
+
nextName2 = nextNamePrefix + getElementKey(child, i2);
|
|
146868
|
+
subtreeCount += mapIntoArray(child, array2, escapedPrefix, nextName2, callback);
|
|
146704
146869
|
}
|
|
146705
146870
|
} else {
|
|
146706
146871
|
var iteratorFn = getIteratorFn(children);
|
|
@@ -146719,8 +146884,8 @@ var require_react_development = __commonJS((exports, module3) => {
|
|
|
146719
146884
|
var ii = 0;
|
|
146720
146885
|
while (!(step = iterator.next()).done) {
|
|
146721
146886
|
child = step.value;
|
|
146722
|
-
|
|
146723
|
-
subtreeCount += mapIntoArray(child, array2, escapedPrefix,
|
|
146887
|
+
nextName2 = nextNamePrefix + getElementKey(child, ii++);
|
|
146888
|
+
subtreeCount += mapIntoArray(child, array2, escapedPrefix, nextName2, callback);
|
|
146724
146889
|
}
|
|
146725
146890
|
} else if (type3 === "object") {
|
|
146726
146891
|
var childrenString = String(children);
|
|
@@ -217397,17 +217562,12 @@ class QueueRuntime {
|
|
|
217397
217562
|
const batch = [];
|
|
217398
217563
|
const first = this.store.find((item) => !item.paused);
|
|
217399
217564
|
if (first && isCoalescable(first.kind)) {
|
|
217400
|
-
let batchActingUserId = first.actingUserId;
|
|
217401
217565
|
for (const item of this.store) {
|
|
217402
217566
|
if (item.paused)
|
|
217403
217567
|
continue;
|
|
217404
217568
|
if (!isCoalescable(item.kind) || !hasSameScope(first, item))
|
|
217405
217569
|
break;
|
|
217406
|
-
if (batchActingUserId && item.actingUserId && batchActingUserId !== item.actingUserId) {
|
|
217407
|
-
break;
|
|
217408
|
-
}
|
|
217409
217570
|
batch.push(item);
|
|
217410
|
-
batchActingUserId ??= item.actingUserId;
|
|
217411
217571
|
}
|
|
217412
217572
|
} else if (first) {
|
|
217413
217573
|
batch.push(first);
|
|
@@ -217553,47 +217713,13 @@ var init_queue_runtime = __esm(() => {
|
|
|
217553
217713
|
init_debug();
|
|
217554
217714
|
});
|
|
217555
217715
|
|
|
217556
|
-
// src/
|
|
217557
|
-
function
|
|
217558
|
-
|
|
217559
|
-
|
|
217560
|
-
|
|
217561
|
-
return String(content);
|
|
217562
|
-
}
|
|
217563
|
-
}
|
|
217564
|
-
function appendContentParts(target2, content) {
|
|
217565
|
-
if (typeof content === "string") {
|
|
217566
|
-
target2.push({ type: "text", text: content });
|
|
217567
|
-
return;
|
|
217568
|
-
}
|
|
217569
|
-
if (!Array.isArray(content)) {
|
|
217570
|
-
if (content === null || content === undefined)
|
|
217571
|
-
return;
|
|
217572
|
-
target2.push({ type: "text", text: stringifyUnexpectedContent(content) });
|
|
217573
|
-
return;
|
|
217574
|
-
}
|
|
217575
|
-
target2.push(...content);
|
|
217576
|
-
}
|
|
217577
|
-
function mergeQueuedTurnInput(queued, options) {
|
|
217578
|
-
if (queued.length === 0) {
|
|
217579
|
-
return null;
|
|
217580
|
-
}
|
|
217581
|
-
const separatorText = options.separatorText ?? `
|
|
217582
|
-
`;
|
|
217583
|
-
const mergedParts = [];
|
|
217584
|
-
let isFirst = true;
|
|
217585
|
-
for (const item of queued) {
|
|
217586
|
-
if (!isFirst) {
|
|
217587
|
-
mergedParts.push({ type: "text", text: separatorText });
|
|
217588
|
-
}
|
|
217589
|
-
isFirst = false;
|
|
217590
|
-
if (item.kind === "task_notification" || item.kind === "cron_prompt") {
|
|
217591
|
-
mergedParts.push({ type: "text", text: item.text });
|
|
217592
|
-
continue;
|
|
217593
|
-
}
|
|
217594
|
-
appendContentParts(mergedParts, options.normalizeUserContent(item.content));
|
|
217716
|
+
// src/agent/message-attribution.ts
|
|
217717
|
+
function withMessageAttribution(message, actingUserId) {
|
|
217718
|
+
const attributed = message;
|
|
217719
|
+
if (message.role !== "user" || attributed.attribution !== undefined || !actingUserId) {
|
|
217720
|
+
return attributed;
|
|
217595
217721
|
}
|
|
217596
|
-
return
|
|
217722
|
+
return { ...message, attribution: { acting_user_id: actingUserId } };
|
|
217597
217723
|
}
|
|
217598
217724
|
|
|
217599
217725
|
// src/websocket/helpers/listener-queue-adapter.ts
|
|
@@ -217645,109 +217771,37 @@ function getQueueItemsScope(items3) {
|
|
|
217645
217771
|
function hasSameQueueScope(a2, b3) {
|
|
217646
217772
|
return (a2.agentId ?? null) === (b3.agentId ?? null) && (a2.conversationId ?? null) === (b3.conversationId ?? null);
|
|
217647
217773
|
}
|
|
217648
|
-
function mergeDequeuedBatchContent(items3) {
|
|
217649
|
-
const queuedInputs = [];
|
|
217650
|
-
for (const item of items3) {
|
|
217651
|
-
if (item.kind === "message") {
|
|
217652
|
-
queuedInputs.push({
|
|
217653
|
-
kind: "user",
|
|
217654
|
-
content: item.content
|
|
217655
|
-
});
|
|
217656
|
-
continue;
|
|
217657
|
-
}
|
|
217658
|
-
if (item.kind === "task_notification") {
|
|
217659
|
-
queuedInputs.push({
|
|
217660
|
-
kind: "task_notification",
|
|
217661
|
-
text: item.text
|
|
217662
|
-
});
|
|
217663
|
-
continue;
|
|
217664
|
-
}
|
|
217665
|
-
if (item.kind === "cron_prompt") {
|
|
217666
|
-
queuedInputs.push({
|
|
217667
|
-
kind: "cron_prompt",
|
|
217668
|
-
text: item.text
|
|
217669
|
-
});
|
|
217670
|
-
continue;
|
|
217671
|
-
}
|
|
217672
|
-
if (item.kind === "mod_continue") {
|
|
217673
|
-
queuedInputs.push({
|
|
217674
|
-
kind: "user",
|
|
217675
|
-
content: item.text
|
|
217676
|
-
});
|
|
217677
|
-
}
|
|
217678
|
-
}
|
|
217679
|
-
return mergeQueuedTurnInput(queuedInputs, {
|
|
217680
|
-
normalizeUserContent: (content) => content
|
|
217681
|
-
});
|
|
217682
|
-
}
|
|
217683
|
-
function getPrimaryQueueMessageItem(items3) {
|
|
217684
|
-
for (const item of items3) {
|
|
217685
|
-
if (item.kind === "message") {
|
|
217686
|
-
return item;
|
|
217687
|
-
}
|
|
217688
|
-
}
|
|
217689
|
-
return null;
|
|
217690
|
-
}
|
|
217691
|
-
function pickBatchActingUserId(items3) {
|
|
217692
|
-
for (let i4 = items3.length - 1;i4 >= 0; i4 -= 1) {
|
|
217693
|
-
const actingUserId = items3[i4]?.actingUserId;
|
|
217694
|
-
if (actingUserId) {
|
|
217695
|
-
return actingUserId;
|
|
217696
|
-
}
|
|
217697
|
-
}
|
|
217698
|
-
return;
|
|
217699
|
-
}
|
|
217700
217774
|
function buildQueuedTurnMessage(runtime, batch) {
|
|
217701
|
-
|
|
217702
|
-
const
|
|
217703
|
-
if (!primaryItem) {
|
|
217704
|
-
for (const item of batch.items) {
|
|
217705
|
-
runtime.queuedMessagesByItemId.delete(item.id);
|
|
217706
|
-
}
|
|
217707
|
-
const mergedContent2 = mergeDequeuedBatchContent(batch.items);
|
|
217708
|
-
if (mergedContent2 === null) {
|
|
217709
|
-
return null;
|
|
217710
|
-
}
|
|
217711
|
-
const scopeItem = batch.items[0];
|
|
217712
|
-
return {
|
|
217713
|
-
type: "message",
|
|
217714
|
-
agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
|
|
217715
|
-
conversationId: scopeItem?.conversationId ?? runtime.conversationId,
|
|
217716
|
-
...actingUserId ? { actingUserId } : {},
|
|
217717
|
-
messages: [
|
|
217718
|
-
{
|
|
217719
|
-
role: "user",
|
|
217720
|
-
content: mergedContent2,
|
|
217721
|
-
otid: crypto.randomUUID()
|
|
217722
|
-
}
|
|
217723
|
-
]
|
|
217724
|
-
};
|
|
217725
|
-
}
|
|
217726
|
-
const template3 = runtime.queuedMessagesByItemId.get(primaryItem.id);
|
|
217775
|
+
let template3;
|
|
217776
|
+
const messages = [];
|
|
217727
217777
|
for (const item of batch.items) {
|
|
217778
|
+
const incoming = runtime.queuedMessagesByItemId.get(item.id);
|
|
217779
|
+
if (item.kind === "message" && incoming) {
|
|
217780
|
+
template3 ??= {
|
|
217781
|
+
...incoming,
|
|
217782
|
+
actingUserId: incoming.actingUserId ?? item.actingUserId
|
|
217783
|
+
};
|
|
217784
|
+
messages.push(...incoming.messages.map((message) => ("content" in message) ? withMessageAttribution(message, item.actingUserId ?? incoming.actingUserId) : message));
|
|
217785
|
+
} else if (item.kind === "message") {
|
|
217786
|
+
messages.push(withMessageAttribution({ role: "user", content: item.content }, item.actingUserId));
|
|
217787
|
+
} else if (isCoalescable(item.kind) && "text" in item) {
|
|
217788
|
+
messages.push({
|
|
217789
|
+
role: "user",
|
|
217790
|
+
content: item.text,
|
|
217791
|
+
otid: crypto.randomUUID(),
|
|
217792
|
+
attribution: {}
|
|
217793
|
+
});
|
|
217794
|
+
}
|
|
217728
217795
|
runtime.queuedMessagesByItemId.delete(item.id);
|
|
217729
217796
|
}
|
|
217730
|
-
if (
|
|
217731
|
-
return null;
|
|
217732
|
-
}
|
|
217733
|
-
const mergedContent = mergeDequeuedBatchContent(batch.items);
|
|
217734
|
-
if (mergedContent === null) {
|
|
217797
|
+
if (messages.length === 0)
|
|
217735
217798
|
return null;
|
|
217736
|
-
|
|
217737
|
-
const firstMessageIndex = template3.messages.findIndex((payload) => ("content" in payload));
|
|
217738
|
-
if (firstMessageIndex === -1) {
|
|
217739
|
-
return null;
|
|
217740
|
-
}
|
|
217741
|
-
const firstMessage = template3.messages[firstMessageIndex];
|
|
217742
|
-
const mergedFirstMessage = {
|
|
217743
|
-
...firstMessage,
|
|
217744
|
-
content: mergedContent
|
|
217745
|
-
};
|
|
217746
|
-
const messages = template3.messages.slice();
|
|
217747
|
-
messages[firstMessageIndex] = mergedFirstMessage;
|
|
217799
|
+
const scopeItem = batch.items[0];
|
|
217748
217800
|
return {
|
|
217801
|
+
type: "message",
|
|
217802
|
+
agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
|
|
217803
|
+
conversationId: scopeItem?.conversationId ?? runtime.conversationId,
|
|
217749
217804
|
...template3,
|
|
217750
|
-
...actingUserId ? { actingUserId } : {},
|
|
217751
217805
|
messages
|
|
217752
217806
|
};
|
|
217753
217807
|
}
|
|
@@ -217778,7 +217832,7 @@ function shouldProcessInboundMessageDirectly(runtime, parsed) {
|
|
|
217778
217832
|
});
|
|
217779
217833
|
return getListenerBlockedReason(runtime.turnLifecycle.snapshot(), activeScope ? getPendingControlRequestCount(runtime.listener, activeScope) : 0) === null;
|
|
217780
217834
|
}
|
|
217781
|
-
function consumeQueuedTurn(runtime
|
|
217835
|
+
function consumeQueuedTurn(runtime) {
|
|
217782
217836
|
const queuedItems = runtime.queueRuntime.peekReady();
|
|
217783
217837
|
const firstQueuedItem = queuedItems[0];
|
|
217784
217838
|
if (!firstQueuedItem || !isCoalescable(firstQueuedItem.kind)) {
|
|
@@ -217790,22 +217844,15 @@ function consumeQueuedTurn(runtime, continuation) {
|
|
|
217790
217844
|
let hasCronPrompt = false;
|
|
217791
217845
|
let hasModContinue = false;
|
|
217792
217846
|
let batchConnectionId;
|
|
217793
|
-
let batchActingUserId = firstQueuedItem.actingUserId;
|
|
217794
217847
|
let batchImageFailureMode = null;
|
|
217795
217848
|
const isNoCoalesce = (candidate) => candidate.kind === "message" && candidate.noCoalesce === true;
|
|
217796
217849
|
for (const item of queuedItems) {
|
|
217797
|
-
if (continuation && item.actingUserId !== continuation.actingUserId) {
|
|
217798
|
-
break;
|
|
217799
|
-
}
|
|
217800
217850
|
if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
|
|
217801
217851
|
break;
|
|
217802
217852
|
}
|
|
217803
217853
|
if (queueLen > 0 && (isNoCoalesce(item) || isNoCoalesce(firstQueuedItem))) {
|
|
217804
217854
|
break;
|
|
217805
217855
|
}
|
|
217806
|
-
if (batchActingUserId && item.actingUserId && batchActingUserId !== item.actingUserId) {
|
|
217807
|
-
break;
|
|
217808
|
-
}
|
|
217809
217856
|
if (item.kind === "message") {
|
|
217810
217857
|
const itemConnectionId = runtime.queuedMessagesByItemId.get(item.id)?.connectionId;
|
|
217811
217858
|
if (batchConnectionId !== undefined && itemConnectionId !== undefined && itemConnectionId !== batchConnectionId) {
|
|
@@ -217818,7 +217865,6 @@ function consumeQueuedTurn(runtime, continuation) {
|
|
|
217818
217865
|
}
|
|
217819
217866
|
batchImageFailureMode = itemImageFailureMode;
|
|
217820
217867
|
}
|
|
217821
|
-
batchActingUserId ??= item.actingUserId;
|
|
217822
217868
|
queueLen += 1;
|
|
217823
217869
|
if (item.kind === "message") {
|
|
217824
217870
|
hasMessage = true;
|
|
@@ -222814,7 +222860,7 @@ function isRuntimeStartCommand(value) {
|
|
|
222814
222860
|
if (!value || typeof value !== "object")
|
|
222815
222861
|
return false;
|
|
222816
222862
|
const c = value;
|
|
222817
|
-
return c.type === "runtime_start" && typeof c.request_id === "string" && (c.agent_id === undefined || typeof c.agent_id === "string") && (c.create_agent === undefined || isRuntimeStartCreateAgentOptions(c.create_agent)) && (c.conversation_id === undefined || typeof c.conversation_id === "string") && (c.create_conversation === undefined || isRuntimeStartCreateConversationOptions(c.create_conversation)) && (c.conversation_source_tags === undefined || isStringArray8(c.conversation_source_tags)) && (c.cwd === undefined || c.cwd === null || typeof c.cwd === "string") && (c.mode === undefined || isDevicePermissionMode(c.mode)) && (c.execution_settings === undefined || isRuntimeExecutionSettings(c.execution_settings)) && (c.workspace_sandbox === undefined || isRuntimeStartWorkspaceSandbox(c.workspace_sandbox)) && (c.skill_sources === undefined || isSkillSourceArray(c.skill_sources)) && (c.preserve_skill_sources === undefined || typeof c.preserve_skill_sources === "boolean") && (c.client_info === undefined || isRuntimeStartClientInfo(c.client_info)) && (c.recover_approvals === undefined || typeof c.recover_approvals === "boolean") && (c.force_device_status === undefined || typeof c.force_device_status === "boolean") && (c.wait_for_replay === undefined || typeof c.wait_for_replay === "boolean") && (c.external_tools === undefined || Array.isArray(c.external_tools) && c.external_tools.every(isRuntimeStartExternalToolsGroup));
|
|
222863
|
+
return c.type === "runtime_start" && typeof c.request_id === "string" && (c.agent_id === undefined || typeof c.agent_id === "string") && (c.create_agent === undefined || isRuntimeStartCreateAgentOptions(c.create_agent)) && (c.conversation_id === undefined || typeof c.conversation_id === "string") && (c.create_conversation === undefined || isRuntimeStartCreateConversationOptions(c.create_conversation)) && (c.conversation_source_tags === undefined || isStringArray8(c.conversation_source_tags)) && (c.cwd === undefined || c.cwd === null || typeof c.cwd === "string") && (c.mode === undefined || isDevicePermissionMode(c.mode)) && (c.execution_settings === undefined || isRuntimeExecutionSettings(c.execution_settings)) && (c.workspace_sandbox === undefined || isRuntimeStartWorkspaceSandbox(c.workspace_sandbox)) && (c.skill_sources === undefined || isSkillSourceArray(c.skill_sources)) && (c.preserve_skill_sources === undefined || typeof c.preserve_skill_sources === "boolean") && (c.client_info === undefined || isRuntimeStartClientInfo(c.client_info)) && (c.recover_approvals === undefined || typeof c.recover_approvals === "boolean") && (c.force_device_status === undefined || typeof c.force_device_status === "boolean") && (c.wait_for_replay === undefined || typeof c.wait_for_replay === "boolean") && (c.teleport_id === undefined || typeof c.teleport_id === "string") && (c.external_tools === undefined || Array.isArray(c.external_tools) && c.external_tools.every(isRuntimeStartExternalToolsGroup));
|
|
222818
222864
|
}
|
|
222819
222865
|
function isRuntimeStartCreateAgentOptions(value) {
|
|
222820
222866
|
if (!isObjectRecord2(value))
|
|
@@ -397765,6 +397811,497 @@ function assertRuntimeWorkspaceSandboxChangeAllowed(listener, runtime, next) {
|
|
|
397765
397811
|
}
|
|
397766
397812
|
}
|
|
397767
397813
|
|
|
397814
|
+
// src/channels/teleport-guard.ts
|
|
397815
|
+
function getLocalChannelTeleportError(scope) {
|
|
397816
|
+
const channels = getSupportedChannelIds().filter((channelId) => {
|
|
397817
|
+
return readRoutes(channelId).some((route) => route.agentId === scope.agentId && route.conversationId === scope.conversationId && route.enabled !== false && route.outboundEnabled !== false);
|
|
397818
|
+
});
|
|
397819
|
+
if (channels.length === 0)
|
|
397820
|
+
return null;
|
|
397821
|
+
return `This conversation is bound to ${channels.join(", ")} on this computer. Teleport is blocked because MessageChannel cannot follow the conversation to another computer yet. Remove the channel route or continue locally.`;
|
|
397822
|
+
}
|
|
397823
|
+
var init_teleport_guard = __esm(() => {
|
|
397824
|
+
init_plugin_registry();
|
|
397825
|
+
init_routing();
|
|
397826
|
+
});
|
|
397827
|
+
|
|
397828
|
+
// src/websocket/listener/recoverable-notices.ts
|
|
397829
|
+
function getRecoverableStatusNoticeVisibility(kind) {
|
|
397830
|
+
switch (kind) {
|
|
397831
|
+
case "stale_approval_conflict_recovery":
|
|
397832
|
+
return "debug_only";
|
|
397833
|
+
default:
|
|
397834
|
+
return "transcript";
|
|
397835
|
+
}
|
|
397836
|
+
}
|
|
397837
|
+
function getRecoverableRetryNoticeVisibility(kind) {
|
|
397838
|
+
switch (kind) {
|
|
397839
|
+
case "transient_provider_retry":
|
|
397840
|
+
return "transcript";
|
|
397841
|
+
default:
|
|
397842
|
+
return "transcript";
|
|
397843
|
+
}
|
|
397844
|
+
}
|
|
397845
|
+
function isDesktopDebugPanelMirrorEnabled() {
|
|
397846
|
+
return process.env.LETTA_DESKTOP_MODE === "1";
|
|
397847
|
+
}
|
|
397848
|
+
function mirrorRecoverableNoticeToDesktopDebugPanel(message) {
|
|
397849
|
+
if (!isDesktopDebugPanelMirrorEnabled()) {
|
|
397850
|
+
return;
|
|
397851
|
+
}
|
|
397852
|
+
try {
|
|
397853
|
+
process.stderr.write(`${DESKTOP_DEBUG_PANEL_INFO_PREFIX} ${message}
|
|
397854
|
+
`);
|
|
397855
|
+
} catch {}
|
|
397856
|
+
}
|
|
397857
|
+
function toStructuredApiError(errorInfo) {
|
|
397858
|
+
if (!errorInfo?.error_type || !errorInfo.run_id) {
|
|
397859
|
+
return;
|
|
397860
|
+
}
|
|
397861
|
+
return {
|
|
397862
|
+
message_type: "error_message",
|
|
397863
|
+
message: errorInfo.message || errorInfo.detail || "An error occurred",
|
|
397864
|
+
error_type: errorInfo.error_type,
|
|
397865
|
+
run_id: errorInfo.run_id,
|
|
397866
|
+
...errorInfo.detail ? { detail: errorInfo.detail } : {}
|
|
397867
|
+
};
|
|
397868
|
+
}
|
|
397869
|
+
function getStructuredApiErrorFromError(error4) {
|
|
397870
|
+
if (!(error4 instanceof Error)) {
|
|
397871
|
+
return;
|
|
397872
|
+
}
|
|
397873
|
+
const errorWithStructuredInfo = error4;
|
|
397874
|
+
return errorWithStructuredInfo.apiError ?? toStructuredApiError(errorWithStructuredInfo.runErrorInfo);
|
|
397875
|
+
}
|
|
397876
|
+
function buildStructuredFormatInput(apiError) {
|
|
397877
|
+
return {
|
|
397878
|
+
error: {
|
|
397879
|
+
error: {
|
|
397880
|
+
type: apiError.error_type,
|
|
397881
|
+
message: apiError.message,
|
|
397882
|
+
...apiError.detail ? { detail: apiError.detail } : {}
|
|
397883
|
+
},
|
|
397884
|
+
run_id: apiError.run_id
|
|
397885
|
+
}
|
|
397886
|
+
};
|
|
397887
|
+
}
|
|
397888
|
+
function isAbortLikeError(error4) {
|
|
397889
|
+
if (error4 instanceof APIUserAbortError) {
|
|
397890
|
+
return true;
|
|
397891
|
+
}
|
|
397892
|
+
if (!(error4 instanceof Error)) {
|
|
397893
|
+
return false;
|
|
397894
|
+
}
|
|
397895
|
+
const errorWithCode = error4;
|
|
397896
|
+
return error4.name === "AbortError" || error4.message === "The operation was aborted" || errorWithCode.code === "ABORT_ERR";
|
|
397897
|
+
}
|
|
397898
|
+
function isTerminatedProcessNoise(message) {
|
|
397899
|
+
return message.trim().toLowerCase() === "terminated";
|
|
397900
|
+
}
|
|
397901
|
+
function isProxyTransportError(detail, error4, message) {
|
|
397902
|
+
if (error4 instanceof APIError && error4.status >= 500 && detail.toLowerCase().includes("trying to proxy")) {
|
|
397903
|
+
return true;
|
|
397904
|
+
}
|
|
397905
|
+
return detail.toLowerCase().includes("error occurred while trying to proxy") || message.toLowerCase().includes("error occurred while trying to proxy");
|
|
397906
|
+
}
|
|
397907
|
+
function getLoopErrorNoticeDecision(params) {
|
|
397908
|
+
const apiError = params.apiError ?? toStructuredApiError(params.errorInfo) ?? toStructuredApiError(params.runErrorInfo) ?? getStructuredApiErrorFromError(params.error);
|
|
397909
|
+
const detail = apiError?.detail ?? params.errorInfo?.detail ?? params.runErrorInfo?.detail ?? extractConflictDetail(params.error) ?? "";
|
|
397910
|
+
if (params.cancelRequested || params.abortSignal?.aborted || isAbortLikeError(params.error) || isTerminatedProcessNoise(params.message)) {
|
|
397911
|
+
return {
|
|
397912
|
+
visibility: "debug_only",
|
|
397913
|
+
message: params.message
|
|
397914
|
+
};
|
|
397915
|
+
}
|
|
397916
|
+
const cloudflareMessage = checkCloudflareEdgeError(detail) ?? checkCloudflareEdgeError(params.message);
|
|
397917
|
+
if (cloudflareMessage) {
|
|
397918
|
+
return {
|
|
397919
|
+
visibility: "transcript",
|
|
397920
|
+
message: cloudflareMessage,
|
|
397921
|
+
apiError
|
|
397922
|
+
};
|
|
397923
|
+
}
|
|
397924
|
+
if (isProxyTransportError(detail, params.error, params.message)) {
|
|
397925
|
+
return {
|
|
397926
|
+
visibility: "transcript",
|
|
397927
|
+
message: "Connection to Letta service failed. Please retry.",
|
|
397928
|
+
apiError
|
|
397929
|
+
};
|
|
397930
|
+
}
|
|
397931
|
+
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined, {
|
|
397932
|
+
surface: params.surface,
|
|
397933
|
+
unclassifiedFallback: params.unclassifiedFallback
|
|
397934
|
+
});
|
|
397935
|
+
return {
|
|
397936
|
+
visibility: "transcript",
|
|
397937
|
+
message: formattedMessage,
|
|
397938
|
+
apiError
|
|
397939
|
+
};
|
|
397940
|
+
}
|
|
397941
|
+
function getTranscriptLoopErrorMessage(params) {
|
|
397942
|
+
const decision = getLoopErrorNoticeDecision({
|
|
397943
|
+
...params,
|
|
397944
|
+
surface: "plain",
|
|
397945
|
+
unclassifiedFallback: "generic"
|
|
397946
|
+
});
|
|
397947
|
+
return decision.visibility === "transcript" ? decision.message : undefined;
|
|
397948
|
+
}
|
|
397949
|
+
function getConsumerLoopErrorMessage(params) {
|
|
397950
|
+
const decision = getLoopErrorNoticeDecision({
|
|
397951
|
+
...params,
|
|
397952
|
+
surface: "plain"
|
|
397953
|
+
});
|
|
397954
|
+
return decision.visibility === "transcript" ? decision.message : undefined;
|
|
397955
|
+
}
|
|
397956
|
+
function emitLoopErrorNotice(socket, runtime, params) {
|
|
397957
|
+
const decision = getLoopErrorNoticeDecision(params);
|
|
397958
|
+
if (decision.visibility === "debug_only") {
|
|
397959
|
+
debugLog("recovery", `Debug-only loop error (${params.stopReason}): ${params.message}`);
|
|
397960
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
397961
|
+
return null;
|
|
397962
|
+
}
|
|
397963
|
+
emitLoopErrorDelta(socket, runtime, {
|
|
397964
|
+
message: decision.message,
|
|
397965
|
+
stopReason: params.stopReason,
|
|
397966
|
+
isTerminal: params.isTerminal,
|
|
397967
|
+
runId: params.runId,
|
|
397968
|
+
agentId: params.agentId,
|
|
397969
|
+
conversationId: params.conversationId,
|
|
397970
|
+
apiError: decision.apiError
|
|
397971
|
+
});
|
|
397972
|
+
return decision.message;
|
|
397973
|
+
}
|
|
397974
|
+
function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
397975
|
+
const visibility = getRecoverableStatusNoticeVisibility(params.kind);
|
|
397976
|
+
if (visibility === "debug_only") {
|
|
397977
|
+
debugLog("recovery", `Debug-only lifecycle notice (${params.kind}): ${params.message}`);
|
|
397978
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
397979
|
+
return;
|
|
397980
|
+
}
|
|
397981
|
+
emitStatusDelta(socket, runtime, {
|
|
397982
|
+
message: params.message,
|
|
397983
|
+
level: params.level,
|
|
397984
|
+
runId: params.runId,
|
|
397985
|
+
agentId: params.agentId,
|
|
397986
|
+
conversationId: params.conversationId
|
|
397987
|
+
});
|
|
397988
|
+
}
|
|
397989
|
+
function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
397990
|
+
const visibility = getRecoverableRetryNoticeVisibility(params.kind);
|
|
397991
|
+
if (visibility === "debug_only") {
|
|
397992
|
+
debugLog("recovery", `Debug-only retry notice (${params.kind}, attempt ${params.attempt}/${params.maxAttempts}): ${params.message}`);
|
|
397993
|
+
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
397994
|
+
return;
|
|
397995
|
+
}
|
|
397996
|
+
emitRetryDelta(socket, runtime, {
|
|
397997
|
+
message: params.message,
|
|
397998
|
+
reason: params.reason,
|
|
397999
|
+
attempt: params.attempt,
|
|
398000
|
+
maxAttempts: params.maxAttempts,
|
|
398001
|
+
delayMs: params.delayMs,
|
|
398002
|
+
runId: params.runId,
|
|
398003
|
+
agentId: params.agentId,
|
|
398004
|
+
conversationId: params.conversationId
|
|
398005
|
+
});
|
|
398006
|
+
}
|
|
398007
|
+
var DESKTOP_DEBUG_PANEL_INFO_PREFIX = "[LETTA_DESKTOP_DEBUG_PANEL_INFO]";
|
|
398008
|
+
var init_recoverable_notices = __esm(() => {
|
|
398009
|
+
init_error();
|
|
398010
|
+
init_turn_recovery_policy();
|
|
398011
|
+
init_error_formatter();
|
|
398012
|
+
init_debug();
|
|
398013
|
+
init_protocol_outbound();
|
|
398014
|
+
});
|
|
398015
|
+
|
|
398016
|
+
// src/websocket/listener/teleport.ts
|
|
398017
|
+
function expectInboundTeleport(runtime, teleportId) {
|
|
398018
|
+
runtime.expectedTeleportId = teleportId;
|
|
398019
|
+
runtime.expectedTeleportExpiresAt = Date.now() + INBOUND_TELEPORT_CONTINUE_TTL_MS;
|
|
398020
|
+
}
|
|
398021
|
+
function isInboundTeleportExpected(runtime) {
|
|
398022
|
+
if (runtime.expectedTeleportId === null)
|
|
398023
|
+
return false;
|
|
398024
|
+
if (runtime.expectedTeleportExpiresAt !== null && runtime.expectedTeleportExpiresAt <= Date.now()) {
|
|
398025
|
+
clearExpectedInboundTeleport(runtime);
|
|
398026
|
+
return false;
|
|
398027
|
+
}
|
|
398028
|
+
return true;
|
|
398029
|
+
}
|
|
398030
|
+
function clearExpectedInboundTeleport(runtime) {
|
|
398031
|
+
runtime.expectedTeleportId = null;
|
|
398032
|
+
runtime.expectedTeleportExpiresAt = null;
|
|
398033
|
+
}
|
|
398034
|
+
function buildTeleportContinuationMessages(params) {
|
|
398035
|
+
return [
|
|
398036
|
+
{
|
|
398037
|
+
type: "approval",
|
|
398038
|
+
approvals: params.approvals,
|
|
398039
|
+
otid: params.teleportId
|
|
398040
|
+
},
|
|
398041
|
+
{
|
|
398042
|
+
role: "system",
|
|
398043
|
+
content: "<system-reminder>Teleportation to this environment is complete. Continue the existing task from this environment now.</system-reminder>",
|
|
398044
|
+
otid: `${params.teleportId}:continue`
|
|
398045
|
+
}
|
|
398046
|
+
];
|
|
398047
|
+
}
|
|
398048
|
+
function escapeSystemReminderText(value) {
|
|
398049
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
398050
|
+
}
|
|
398051
|
+
function buildTeleportFailureMessages(params) {
|
|
398052
|
+
const messages = [];
|
|
398053
|
+
if (params.approvals && params.approvals.length > 0) {
|
|
398054
|
+
messages.push({
|
|
398055
|
+
type: "approval",
|
|
398056
|
+
approvals: params.approvals,
|
|
398057
|
+
otid: params.teleportId
|
|
398058
|
+
});
|
|
398059
|
+
}
|
|
398060
|
+
messages.push({
|
|
398061
|
+
role: "system",
|
|
398062
|
+
content: `<system-reminder>Teleportation failed.
|
|
398063
|
+
|
|
398064
|
+
Error: ${escapeSystemReminderText(params.error)}
|
|
398065
|
+
|
|
398066
|
+
Continue the existing task from this environment now.</system-reminder>`,
|
|
398067
|
+
otid: `${params.teleportId}:failed`
|
|
398068
|
+
});
|
|
398069
|
+
return messages;
|
|
398070
|
+
}
|
|
398071
|
+
function getPendingTeleports(runtime) {
|
|
398072
|
+
runtime.pendingTeleports ??= new Map;
|
|
398073
|
+
return runtime.pendingTeleports;
|
|
398074
|
+
}
|
|
398075
|
+
function findPendingTeleportForRuntime(runtime, agentId, conversationId) {
|
|
398076
|
+
for (const pending of getPendingTeleports(runtime).values()) {
|
|
398077
|
+
if (pending.agentId === agentId && pending.conversationId === conversationId && pending.readyAt === undefined) {
|
|
398078
|
+
return pending;
|
|
398079
|
+
}
|
|
398080
|
+
}
|
|
398081
|
+
return null;
|
|
398082
|
+
}
|
|
398083
|
+
function isRuntimeTeleportPending(runtime, agentId, conversationId) {
|
|
398084
|
+
if (!agentId)
|
|
398085
|
+
return false;
|
|
398086
|
+
return [...runtime.pendingTeleports?.values() ?? []].some((pending) => !pending.error && pending.agentId === agentId && pending.conversationId === conversationId);
|
|
398087
|
+
}
|
|
398088
|
+
function clearPriorReadyTeleports(params) {
|
|
398089
|
+
const pendingTeleports = params.listener.pendingTeleports;
|
|
398090
|
+
if (!pendingTeleports)
|
|
398091
|
+
return;
|
|
398092
|
+
for (const [teleportId, pending] of pendingTeleports) {
|
|
398093
|
+
if (teleportId === params.currentTeleportId || pending.readyAt === undefined) {
|
|
398094
|
+
continue;
|
|
398095
|
+
}
|
|
398096
|
+
if (pending.agentId === params.agentId && pending.conversationId === params.conversationId) {
|
|
398097
|
+
pendingTeleports.delete(teleportId);
|
|
398098
|
+
}
|
|
398099
|
+
}
|
|
398100
|
+
}
|
|
398101
|
+
function hasAcceptedInputsWaiting(runtime, includeQueuePump) {
|
|
398102
|
+
return runtime.queueRuntime.length > 0 || runtime.pendingTurns > 0 || runtime.queuedMessagesByItemId.size > 0 || includeQueuePump && (runtime.queuePumpActive || runtime.queuePumpScheduled);
|
|
398103
|
+
}
|
|
398104
|
+
function sendTeleportReady(runtime, pending, input) {
|
|
398105
|
+
const connection = runtime.connections.get(pending.connectionId);
|
|
398106
|
+
if (!connection || !isListenerTransportOpen(connection.writer))
|
|
398107
|
+
return false;
|
|
398108
|
+
const mode = getOrCreateConversationPermissionModeStateRef(runtime, pending.agentId, pending.conversationId).mode;
|
|
398109
|
+
const message = {
|
|
398110
|
+
type: "teleport_ready",
|
|
398111
|
+
teleport_id: pending.teleportId,
|
|
398112
|
+
runtime: {
|
|
398113
|
+
agent_id: pending.agentId,
|
|
398114
|
+
conversation_id: pending.conversationId
|
|
398115
|
+
},
|
|
398116
|
+
success: input.success,
|
|
398117
|
+
active_turn: pending.activeTurn,
|
|
398118
|
+
mode,
|
|
398119
|
+
...pending.continuation ? { continuation: pending.continuation } : {},
|
|
398120
|
+
...input.error ? { error: input.error } : {}
|
|
398121
|
+
};
|
|
398122
|
+
emitProtocolV2Message(connection.writer, runtime, message, message.runtime, toListenerConnection(pending.connectionId));
|
|
398123
|
+
return true;
|
|
398124
|
+
}
|
|
398125
|
+
function retainTeleportForRecovery(runtime, pending) {
|
|
398126
|
+
const timeout = setTimeout(() => {
|
|
398127
|
+
const current = runtime.pendingTeleports?.get(pending.teleportId);
|
|
398128
|
+
if (current === pending) {
|
|
398129
|
+
runtime.pendingTeleports?.delete(pending.teleportId);
|
|
398130
|
+
}
|
|
398131
|
+
}, TELEPORT_RECOVERY_TTL_MS);
|
|
398132
|
+
timeout.unref?.();
|
|
398133
|
+
}
|
|
398134
|
+
function handleTeleportProbe(command, socket, safeSocketSend) {
|
|
398135
|
+
safeSocketSend(socket, {
|
|
398136
|
+
type: "teleport_probe_response",
|
|
398137
|
+
request_id: command.request_id,
|
|
398138
|
+
runtime: command.runtime,
|
|
398139
|
+
supported: resolveBackendMode() === "api",
|
|
398140
|
+
drains_accepted_inputs: true,
|
|
398141
|
+
idempotent_continuation: true
|
|
398142
|
+
}, "teleport_probe_response", "teleport_probe");
|
|
398143
|
+
}
|
|
398144
|
+
function handleTeleportRequest(params) {
|
|
398145
|
+
const { listener, command, connectionId } = params;
|
|
398146
|
+
const pendingTeleports = getPendingTeleports(listener);
|
|
398147
|
+
const existing = pendingTeleports.get(command.teleport_id);
|
|
398148
|
+
if (existing) {
|
|
398149
|
+
if (existing.readyAt !== undefined) {
|
|
398150
|
+
sendTeleportReady(listener, existing, {
|
|
398151
|
+
success: existing.error === undefined,
|
|
398152
|
+
error: existing.error
|
|
398153
|
+
});
|
|
398154
|
+
}
|
|
398155
|
+
return;
|
|
398156
|
+
}
|
|
398157
|
+
const pending = {
|
|
398158
|
+
teleportId: command.teleport_id,
|
|
398159
|
+
connectionId,
|
|
398160
|
+
agentId: command.runtime.agent_id,
|
|
398161
|
+
conversationId: command.runtime.conversation_id,
|
|
398162
|
+
requestedAt: Date.now(),
|
|
398163
|
+
drainAcceptedInputs: false,
|
|
398164
|
+
activeTurn: false
|
|
398165
|
+
};
|
|
398166
|
+
const channelError = getLocalChannelTeleportError(pending);
|
|
398167
|
+
if (channelError) {
|
|
398168
|
+
pending.readyAt = Date.now();
|
|
398169
|
+
pending.error = channelError;
|
|
398170
|
+
pendingTeleports.set(pending.teleportId, pending);
|
|
398171
|
+
sendTeleportReady(listener, pending, {
|
|
398172
|
+
success: false,
|
|
398173
|
+
error: channelError
|
|
398174
|
+
});
|
|
398175
|
+
retainTeleportForRecovery(listener, pending);
|
|
398176
|
+
return;
|
|
398177
|
+
}
|
|
398178
|
+
const conflicting = findPendingTeleportForRuntime(listener, pending.agentId, pending.conversationId);
|
|
398179
|
+
if (conflicting) {
|
|
398180
|
+
pendingTeleports.set(pending.teleportId, pending);
|
|
398181
|
+
pending.readyAt = Date.now();
|
|
398182
|
+
pending.error = "Conversation already has a teleport pending";
|
|
398183
|
+
sendTeleportReady(listener, pending, {
|
|
398184
|
+
success: false,
|
|
398185
|
+
error: pending.error
|
|
398186
|
+
});
|
|
398187
|
+
retainTeleportForRecovery(listener, pending);
|
|
398188
|
+
return;
|
|
398189
|
+
}
|
|
398190
|
+
pendingTeleports.set(pending.teleportId, pending);
|
|
398191
|
+
const conversationRuntime = getConversationRuntime(listener, pending.agentId, pending.conversationId);
|
|
398192
|
+
pending.drainAcceptedInputs = conversationRuntime ? hasAcceptedInputsWaiting(conversationRuntime, true) : false;
|
|
398193
|
+
if (!conversationRuntime?.isProcessing && !pending.drainAcceptedInputs) {
|
|
398194
|
+
if (sendTeleportReady(listener, pending, { success: true })) {
|
|
398195
|
+
pending.readyAt = Date.now();
|
|
398196
|
+
retainTeleportForRecovery(listener, pending);
|
|
398197
|
+
}
|
|
398198
|
+
}
|
|
398199
|
+
}
|
|
398200
|
+
function claimPendingTeleportAtBoundary(params) {
|
|
398201
|
+
const pending = findPendingTeleportForRuntime(params.listener, params.agentId, params.conversationId);
|
|
398202
|
+
if (!pending)
|
|
398203
|
+
return null;
|
|
398204
|
+
if (pending.drainAcceptedInputs) {
|
|
398205
|
+
if (params.activeTurn)
|
|
398206
|
+
return null;
|
|
398207
|
+
const runtime = getConversationRuntime(params.listener, params.agentId, params.conversationId);
|
|
398208
|
+
if (runtime && hasAcceptedInputsWaiting(runtime, false))
|
|
398209
|
+
return null;
|
|
398210
|
+
}
|
|
398211
|
+
const connection = params.listener.connections.get(pending.connectionId);
|
|
398212
|
+
if (!connection || !isListenerTransportOpen(connection.writer))
|
|
398213
|
+
return null;
|
|
398214
|
+
pending.readyAt = Date.now();
|
|
398215
|
+
pending.activeTurn = params.activeTurn;
|
|
398216
|
+
pending.continuation = params.continuation;
|
|
398217
|
+
return pending;
|
|
398218
|
+
}
|
|
398219
|
+
function emitClaimedTeleportReady(listener, pending) {
|
|
398220
|
+
const sent = sendTeleportReady(listener, pending, { success: true });
|
|
398221
|
+
if (sent) {
|
|
398222
|
+
retainTeleportForRecovery(listener, pending);
|
|
398223
|
+
}
|
|
398224
|
+
return sent;
|
|
398225
|
+
}
|
|
398226
|
+
function finishTeleport(runtime, lease, pending) {
|
|
398227
|
+
const transition = runtime.turnLifecycle.finish(lease, "cancelled");
|
|
398228
|
+
if (!transition.finished)
|
|
398229
|
+
return transition;
|
|
398230
|
+
emitRuntimeStateUpdates(runtime, {
|
|
398231
|
+
agent_id: pending.agentId,
|
|
398232
|
+
conversation_id: pending.conversationId
|
|
398233
|
+
});
|
|
398234
|
+
emitClaimedTeleportReady(runtime.listener, pending);
|
|
398235
|
+
return transition;
|
|
398236
|
+
}
|
|
398237
|
+
function finishPendingTeleport(runtime) {
|
|
398238
|
+
if (!runtime.agentId)
|
|
398239
|
+
return;
|
|
398240
|
+
const pending = findPendingTeleportForRuntime(runtime.listener, runtime.agentId, runtime.conversationId);
|
|
398241
|
+
if (!pending || runtime.lastStopReason !== "end_turn" && !pending.drainAcceptedInputs) {
|
|
398242
|
+
return;
|
|
398243
|
+
}
|
|
398244
|
+
const claimed = claimPendingTeleportAtBoundary({
|
|
398245
|
+
listener: runtime.listener,
|
|
398246
|
+
agentId: runtime.agentId,
|
|
398247
|
+
conversationId: runtime.conversationId,
|
|
398248
|
+
activeTurn: false
|
|
398249
|
+
});
|
|
398250
|
+
if (claimed)
|
|
398251
|
+
emitClaimedTeleportReady(runtime.listener, claimed);
|
|
398252
|
+
}
|
|
398253
|
+
function takeFailedTeleport(params) {
|
|
398254
|
+
const pending = params.listener.pendingTeleports?.get(params.teleportId);
|
|
398255
|
+
if (!pending || pending.agentId !== params.agentId || pending.conversationId !== params.conversationId) {
|
|
398256
|
+
return null;
|
|
398257
|
+
}
|
|
398258
|
+
params.listener.pendingTeleports?.delete(params.teleportId);
|
|
398259
|
+
return pending;
|
|
398260
|
+
}
|
|
398261
|
+
function handleTeleportFailure(params) {
|
|
398262
|
+
const pending = takeFailedTeleport({
|
|
398263
|
+
listener: params.listener,
|
|
398264
|
+
teleportId: params.command.teleport_id,
|
|
398265
|
+
agentId: params.command.runtime.agent_id,
|
|
398266
|
+
conversationId: params.command.runtime.conversation_id
|
|
398267
|
+
});
|
|
398268
|
+
if (!pending || pending.error)
|
|
398269
|
+
return;
|
|
398270
|
+
const runtime = params.getOrCreateScopedRuntime(params.listener, pending.agentId, pending.conversationId);
|
|
398271
|
+
emitLoopErrorNotice(params.socket, runtime, {
|
|
398272
|
+
message: `Teleport failed: ${params.command.error}`,
|
|
398273
|
+
stopReason: "error",
|
|
398274
|
+
isTerminal: false,
|
|
398275
|
+
agentId: pending.agentId,
|
|
398276
|
+
conversationId: pending.conversationId
|
|
398277
|
+
});
|
|
398278
|
+
params.runDetachedListenerTask("teleport_failed", async () => {
|
|
398279
|
+
await params.processIncomingMessage({
|
|
398280
|
+
type: "message",
|
|
398281
|
+
connectionId: pending.connectionId,
|
|
398282
|
+
agentId: pending.agentId,
|
|
398283
|
+
conversationId: pending.conversationId,
|
|
398284
|
+
messages: buildTeleportFailureMessages({
|
|
398285
|
+
teleportId: params.command.teleport_id,
|
|
398286
|
+
error: params.command.error,
|
|
398287
|
+
approvals: pending.continuation?.approvals
|
|
398288
|
+
})
|
|
398289
|
+
}, params.socket, runtime, params.onStatusChange, pending.connectionId);
|
|
398290
|
+
});
|
|
398291
|
+
}
|
|
398292
|
+
var TELEPORT_RECOVERY_TTL_MS, INBOUND_TELEPORT_CONTINUE_TTL_MS = 60000;
|
|
398293
|
+
var init_teleport = __esm(() => {
|
|
398294
|
+
init_backend_mode();
|
|
398295
|
+
init_teleport_guard();
|
|
398296
|
+
init_connection();
|
|
398297
|
+
init_permission_mode();
|
|
398298
|
+
init_protocol_outbound();
|
|
398299
|
+
init_recoverable_notices();
|
|
398300
|
+
init_runtime();
|
|
398301
|
+
init_transport();
|
|
398302
|
+
TELEPORT_RECOVERY_TTL_MS = 5 * 60000;
|
|
398303
|
+
});
|
|
398304
|
+
|
|
397768
398305
|
// src/websocket/listener/commands/runtime-start.ts
|
|
397769
398306
|
function buildDefaultConversation(agent) {
|
|
397770
398307
|
const now2 = new Date().toISOString();
|
|
@@ -397984,6 +398521,9 @@ async function handleRuntimeStartCommand(parsed, context3) {
|
|
|
397984
398521
|
assertConnectionOpen();
|
|
397985
398522
|
const scopedRuntime = context3.getOrCreateScopedRuntime(context3.runtime, runtimeScope.agent_id, runtimeScope.conversation_id);
|
|
397986
398523
|
await applyRuntimeStartState(parsed, context3, runtimeScope, scopedRuntime);
|
|
398524
|
+
if (parsed.teleport_id) {
|
|
398525
|
+
expectInboundTeleport(scopedRuntime, parsed.teleport_id);
|
|
398526
|
+
}
|
|
397987
398527
|
assertConnectionOpen();
|
|
397988
398528
|
subscribeListenerConnection(context3.runtime, connectionId, runtimeScope);
|
|
397989
398529
|
registerRuntimeExternalTools(context3.runtime, connectionId, runtimeScope, parsed.external_tools ?? []);
|
|
@@ -398045,6 +398585,7 @@ var init_runtime_start = __esm(async () => {
|
|
|
398045
398585
|
init_cwd_change();
|
|
398046
398586
|
init_permission_mode();
|
|
398047
398587
|
init_runtime_start_validation();
|
|
398588
|
+
init_teleport();
|
|
398048
398589
|
await init_external_tools();
|
|
398049
398590
|
LEGACY_SUMMARY_PREFIX_BY_SOURCE_TAG = {
|
|
398050
398591
|
"channel:discord": "discord",
|
|
@@ -398923,194 +399464,6 @@ var init_interrupts = __esm(() => {
|
|
|
398923
399464
|
STREAMING_TOOL_OUTPUT_MAX_CHARS = LIMITS.BASH_OUTPUT_CHARS;
|
|
398924
399465
|
});
|
|
398925
399466
|
|
|
398926
|
-
// src/websocket/listener/recoverable-notices.ts
|
|
398927
|
-
function getRecoverableStatusNoticeVisibility(kind) {
|
|
398928
|
-
switch (kind) {
|
|
398929
|
-
case "stale_approval_conflict_recovery":
|
|
398930
|
-
return "debug_only";
|
|
398931
|
-
default:
|
|
398932
|
-
return "transcript";
|
|
398933
|
-
}
|
|
398934
|
-
}
|
|
398935
|
-
function getRecoverableRetryNoticeVisibility(kind) {
|
|
398936
|
-
switch (kind) {
|
|
398937
|
-
case "transient_provider_retry":
|
|
398938
|
-
return "transcript";
|
|
398939
|
-
default:
|
|
398940
|
-
return "transcript";
|
|
398941
|
-
}
|
|
398942
|
-
}
|
|
398943
|
-
function isDesktopDebugPanelMirrorEnabled() {
|
|
398944
|
-
return process.env.LETTA_DESKTOP_MODE === "1";
|
|
398945
|
-
}
|
|
398946
|
-
function mirrorRecoverableNoticeToDesktopDebugPanel(message) {
|
|
398947
|
-
if (!isDesktopDebugPanelMirrorEnabled()) {
|
|
398948
|
-
return;
|
|
398949
|
-
}
|
|
398950
|
-
try {
|
|
398951
|
-
process.stderr.write(`${DESKTOP_DEBUG_PANEL_INFO_PREFIX} ${message}
|
|
398952
|
-
`);
|
|
398953
|
-
} catch {}
|
|
398954
|
-
}
|
|
398955
|
-
function toStructuredApiError(errorInfo) {
|
|
398956
|
-
if (!errorInfo?.error_type || !errorInfo.run_id) {
|
|
398957
|
-
return;
|
|
398958
|
-
}
|
|
398959
|
-
return {
|
|
398960
|
-
message_type: "error_message",
|
|
398961
|
-
message: errorInfo.message || errorInfo.detail || "An error occurred",
|
|
398962
|
-
error_type: errorInfo.error_type,
|
|
398963
|
-
run_id: errorInfo.run_id,
|
|
398964
|
-
...errorInfo.detail ? { detail: errorInfo.detail } : {}
|
|
398965
|
-
};
|
|
398966
|
-
}
|
|
398967
|
-
function getStructuredApiErrorFromError(error4) {
|
|
398968
|
-
if (!(error4 instanceof Error)) {
|
|
398969
|
-
return;
|
|
398970
|
-
}
|
|
398971
|
-
const errorWithStructuredInfo = error4;
|
|
398972
|
-
return errorWithStructuredInfo.apiError ?? toStructuredApiError(errorWithStructuredInfo.runErrorInfo);
|
|
398973
|
-
}
|
|
398974
|
-
function buildStructuredFormatInput(apiError) {
|
|
398975
|
-
return {
|
|
398976
|
-
error: {
|
|
398977
|
-
error: {
|
|
398978
|
-
type: apiError.error_type,
|
|
398979
|
-
message: apiError.message,
|
|
398980
|
-
...apiError.detail ? { detail: apiError.detail } : {}
|
|
398981
|
-
},
|
|
398982
|
-
run_id: apiError.run_id
|
|
398983
|
-
}
|
|
398984
|
-
};
|
|
398985
|
-
}
|
|
398986
|
-
function isAbortLikeError(error4) {
|
|
398987
|
-
if (error4 instanceof APIUserAbortError) {
|
|
398988
|
-
return true;
|
|
398989
|
-
}
|
|
398990
|
-
if (!(error4 instanceof Error)) {
|
|
398991
|
-
return false;
|
|
398992
|
-
}
|
|
398993
|
-
const errorWithCode = error4;
|
|
398994
|
-
return error4.name === "AbortError" || error4.message === "The operation was aborted" || errorWithCode.code === "ABORT_ERR";
|
|
398995
|
-
}
|
|
398996
|
-
function isTerminatedProcessNoise(message) {
|
|
398997
|
-
return message.trim().toLowerCase() === "terminated";
|
|
398998
|
-
}
|
|
398999
|
-
function isProxyTransportError(detail, error4, message) {
|
|
399000
|
-
if (error4 instanceof APIError && error4.status >= 500 && detail.toLowerCase().includes("trying to proxy")) {
|
|
399001
|
-
return true;
|
|
399002
|
-
}
|
|
399003
|
-
return detail.toLowerCase().includes("error occurred while trying to proxy") || message.toLowerCase().includes("error occurred while trying to proxy");
|
|
399004
|
-
}
|
|
399005
|
-
function getLoopErrorNoticeDecision(params) {
|
|
399006
|
-
const apiError = params.apiError ?? toStructuredApiError(params.errorInfo) ?? toStructuredApiError(params.runErrorInfo) ?? getStructuredApiErrorFromError(params.error);
|
|
399007
|
-
const detail = apiError?.detail ?? params.errorInfo?.detail ?? params.runErrorInfo?.detail ?? extractConflictDetail(params.error) ?? "";
|
|
399008
|
-
if (params.cancelRequested || params.abortSignal?.aborted || isAbortLikeError(params.error) || isTerminatedProcessNoise(params.message)) {
|
|
399009
|
-
return {
|
|
399010
|
-
visibility: "debug_only",
|
|
399011
|
-
message: params.message
|
|
399012
|
-
};
|
|
399013
|
-
}
|
|
399014
|
-
const cloudflareMessage = checkCloudflareEdgeError(detail) ?? checkCloudflareEdgeError(params.message);
|
|
399015
|
-
if (cloudflareMessage) {
|
|
399016
|
-
return {
|
|
399017
|
-
visibility: "transcript",
|
|
399018
|
-
message: cloudflareMessage,
|
|
399019
|
-
apiError
|
|
399020
|
-
};
|
|
399021
|
-
}
|
|
399022
|
-
if (isProxyTransportError(detail, params.error, params.message)) {
|
|
399023
|
-
return {
|
|
399024
|
-
visibility: "transcript",
|
|
399025
|
-
message: "Connection to Letta service failed. Please retry.",
|
|
399026
|
-
apiError
|
|
399027
|
-
};
|
|
399028
|
-
}
|
|
399029
|
-
const formattedMessage = formatErrorDetails2(apiError ? buildStructuredFormatInput(apiError) : params.error ?? params.message, params.agentId ?? undefined, params.conversationId ?? undefined, {
|
|
399030
|
-
surface: params.surface,
|
|
399031
|
-
unclassifiedFallback: params.unclassifiedFallback
|
|
399032
|
-
});
|
|
399033
|
-
return {
|
|
399034
|
-
visibility: "transcript",
|
|
399035
|
-
message: formattedMessage,
|
|
399036
|
-
apiError
|
|
399037
|
-
};
|
|
399038
|
-
}
|
|
399039
|
-
function getTranscriptLoopErrorMessage(params) {
|
|
399040
|
-
const decision = getLoopErrorNoticeDecision({
|
|
399041
|
-
...params,
|
|
399042
|
-
surface: "plain",
|
|
399043
|
-
unclassifiedFallback: "generic"
|
|
399044
|
-
});
|
|
399045
|
-
return decision.visibility === "transcript" ? decision.message : undefined;
|
|
399046
|
-
}
|
|
399047
|
-
function getConsumerLoopErrorMessage(params) {
|
|
399048
|
-
const decision = getLoopErrorNoticeDecision({
|
|
399049
|
-
...params,
|
|
399050
|
-
surface: "plain"
|
|
399051
|
-
});
|
|
399052
|
-
return decision.visibility === "transcript" ? decision.message : undefined;
|
|
399053
|
-
}
|
|
399054
|
-
function emitLoopErrorNotice(socket, runtime, params) {
|
|
399055
|
-
const decision = getLoopErrorNoticeDecision(params);
|
|
399056
|
-
if (decision.visibility === "debug_only") {
|
|
399057
|
-
debugLog("recovery", `Debug-only loop error (${params.stopReason}): ${params.message}`);
|
|
399058
|
-
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
399059
|
-
return null;
|
|
399060
|
-
}
|
|
399061
|
-
emitLoopErrorDelta(socket, runtime, {
|
|
399062
|
-
message: decision.message,
|
|
399063
|
-
stopReason: params.stopReason,
|
|
399064
|
-
isTerminal: params.isTerminal,
|
|
399065
|
-
runId: params.runId,
|
|
399066
|
-
agentId: params.agentId,
|
|
399067
|
-
conversationId: params.conversationId,
|
|
399068
|
-
apiError: decision.apiError
|
|
399069
|
-
});
|
|
399070
|
-
return decision.message;
|
|
399071
|
-
}
|
|
399072
|
-
function emitRecoverableStatusNotice(socket, runtime, params) {
|
|
399073
|
-
const visibility = getRecoverableStatusNoticeVisibility(params.kind);
|
|
399074
|
-
if (visibility === "debug_only") {
|
|
399075
|
-
debugLog("recovery", `Debug-only lifecycle notice (${params.kind}): ${params.message}`);
|
|
399076
|
-
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
399077
|
-
return;
|
|
399078
|
-
}
|
|
399079
|
-
emitStatusDelta(socket, runtime, {
|
|
399080
|
-
message: params.message,
|
|
399081
|
-
level: params.level,
|
|
399082
|
-
runId: params.runId,
|
|
399083
|
-
agentId: params.agentId,
|
|
399084
|
-
conversationId: params.conversationId
|
|
399085
|
-
});
|
|
399086
|
-
}
|
|
399087
|
-
function emitRecoverableRetryNotice(socket, runtime, params) {
|
|
399088
|
-
const visibility = getRecoverableRetryNoticeVisibility(params.kind);
|
|
399089
|
-
if (visibility === "debug_only") {
|
|
399090
|
-
debugLog("recovery", `Debug-only retry notice (${params.kind}, attempt ${params.attempt}/${params.maxAttempts}): ${params.message}`);
|
|
399091
|
-
mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
|
|
399092
|
-
return;
|
|
399093
|
-
}
|
|
399094
|
-
emitRetryDelta(socket, runtime, {
|
|
399095
|
-
message: params.message,
|
|
399096
|
-
reason: params.reason,
|
|
399097
|
-
attempt: params.attempt,
|
|
399098
|
-
maxAttempts: params.maxAttempts,
|
|
399099
|
-
delayMs: params.delayMs,
|
|
399100
|
-
runId: params.runId,
|
|
399101
|
-
agentId: params.agentId,
|
|
399102
|
-
conversationId: params.conversationId
|
|
399103
|
-
});
|
|
399104
|
-
}
|
|
399105
|
-
var DESKTOP_DEBUG_PANEL_INFO_PREFIX = "[LETTA_DESKTOP_DEBUG_PANEL_INFO]";
|
|
399106
|
-
var init_recoverable_notices = __esm(() => {
|
|
399107
|
-
init_error();
|
|
399108
|
-
init_turn_recovery_policy();
|
|
399109
|
-
init_error_formatter();
|
|
399110
|
-
init_debug();
|
|
399111
|
-
init_protocol_outbound();
|
|
399112
|
-
});
|
|
399113
|
-
|
|
399114
399467
|
// src/cli/helpers/compaction-utils.ts
|
|
399115
399468
|
function extractCompactionSummary(text2) {
|
|
399116
399469
|
try {
|
|
@@ -401799,6 +402152,59 @@ var init_continuation_input = __esm(async () => {
|
|
|
401799
402152
|
]);
|
|
401800
402153
|
});
|
|
401801
402154
|
|
|
402155
|
+
// src/backend/api/agents.ts
|
|
402156
|
+
async function getAgentContextOverview(agentId, options) {
|
|
402157
|
+
return apiRequest("GET", `/v1/agents/${agentId}/context`, undefined, {
|
|
402158
|
+
signal: options?.signal
|
|
402159
|
+
});
|
|
402160
|
+
}
|
|
402161
|
+
async function createMinimalAgent(apiKey, name) {
|
|
402162
|
+
return apiRequest("POST", "/v1/agents", { name }, {
|
|
402163
|
+
baseUrl: "https://api.letta.com",
|
|
402164
|
+
apiKey
|
|
402165
|
+
});
|
|
402166
|
+
}
|
|
402167
|
+
async function getAgentRuntimeStatus(agentId, conversationIds, signal) {
|
|
402168
|
+
return apiRequest("GET", `/v1/agents/${encodeURIComponent(agentId)}/runtime-status`, undefined, { query: { conversation_ids: conversationIds.join(",") }, signal });
|
|
402169
|
+
}
|
|
402170
|
+
var init_agents7 = __esm(() => {
|
|
402171
|
+
init_request();
|
|
402172
|
+
});
|
|
402173
|
+
|
|
402174
|
+
// src/websocket/listener/recovery-ownership.ts
|
|
402175
|
+
function hasRecoveryHandoff(runtime) {
|
|
402176
|
+
return isInboundTeleportExpected(runtime) || isRuntimeTeleportPending(runtime.listener, runtime.agentId, runtime.conversationId);
|
|
402177
|
+
}
|
|
402178
|
+
async function canRecoverConversation(runtime, readStatus = getAgentRuntimeStatus) {
|
|
402179
|
+
if (hasRecoveryHandoff(runtime))
|
|
402180
|
+
return false;
|
|
402181
|
+
const connectionId = runtime.listener.connectionId;
|
|
402182
|
+
if (!connectionId?.startsWith("conn-")) {
|
|
402183
|
+
return true;
|
|
402184
|
+
}
|
|
402185
|
+
if (!runtime.agentId)
|
|
402186
|
+
return true;
|
|
402187
|
+
try {
|
|
402188
|
+
const snapshot = await readStatus(runtime.agentId, [runtime.conversationId], AbortSignal.timeout(5000));
|
|
402189
|
+
if (hasRecoveryHandoff(runtime) || runtime.listener.connectionId !== connectionId)
|
|
402190
|
+
return false;
|
|
402191
|
+
const status = snapshot.statuses.find((entry) => entry.conversation_id === runtime.conversationId);
|
|
402192
|
+
if (!status || status.has_conflicting_listeners)
|
|
402193
|
+
return false;
|
|
402194
|
+
if (status.active_harness)
|
|
402195
|
+
return status.active_harness.connection_id === connectionId;
|
|
402196
|
+
return status.state === "IDLE";
|
|
402197
|
+
} catch (error4) {
|
|
402198
|
+
debugWarn("recovery", "Could not verify conversation recovery ownership", error4);
|
|
402199
|
+
return false;
|
|
402200
|
+
}
|
|
402201
|
+
}
|
|
402202
|
+
var init_recovery_ownership = __esm(() => {
|
|
402203
|
+
init_agents7();
|
|
402204
|
+
init_debug();
|
|
402205
|
+
init_teleport();
|
|
402206
|
+
});
|
|
402207
|
+
|
|
401802
402208
|
// src/websocket/listener/secrets-sync.ts
|
|
401803
402209
|
function getFreshnessMs() {
|
|
401804
402210
|
return _testFreshnessMsOverride ?? DEFAULT_FRESHNESS_MS;
|
|
@@ -402110,6 +402516,15 @@ async function startRecoveredApprovalContinuation(runtime, socket, processTurn,
|
|
|
402110
402516
|
if (runtime.turnLifecycle.kind !== "idle") {
|
|
402111
402517
|
return false;
|
|
402112
402518
|
}
|
|
402519
|
+
if (!await canRecoverConversation(runtime)) {
|
|
402520
|
+
if (runtime.recoveredApprovalState === recovered) {
|
|
402521
|
+
clearRecoveredApprovalState(runtime);
|
|
402522
|
+
runtime.syncApprovalRecoveryCompleted = false;
|
|
402523
|
+
}
|
|
402524
|
+
return false;
|
|
402525
|
+
}
|
|
402526
|
+
if (runtime.turnLifecycle.kind !== "idle" || runtime.recoveredApprovalState !== recovered)
|
|
402527
|
+
return false;
|
|
402113
402528
|
const scope = {
|
|
402114
402529
|
agent_id: recovered.agentId,
|
|
402115
402530
|
conversation_id: recovered.conversationId
|
|
@@ -402393,13 +402808,11 @@ async function executeRecoveredApprovalContinuation(params) {
|
|
|
402393
402808
|
}
|
|
402394
402809
|
]);
|
|
402395
402810
|
let continuationBatchId = `batch-recovered-${crypto.randomUUID()}`;
|
|
402396
|
-
let continuationActingUserId;
|
|
402397
402811
|
let continuationCorrelation;
|
|
402398
402812
|
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
402399
402813
|
if (consumedQueuedTurn) {
|
|
402400
402814
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
402401
402815
|
continuationBatchId = dequeuedBatch.batchId;
|
|
402402
|
-
continuationActingUserId = queuedTurn.actingUserId;
|
|
402403
402816
|
continuationInput = appendQueuedTurnToInput(continuationInput, queuedTurn);
|
|
402404
402817
|
continuationCorrelation = createTurnCorrelation(runtime, {
|
|
402405
402818
|
type: "message",
|
|
@@ -402417,7 +402830,6 @@ async function executeRecoveredApprovalContinuation(params) {
|
|
|
402417
402830
|
type: "message",
|
|
402418
402831
|
agentId: recovered.agentId,
|
|
402419
402832
|
conversationId: recovered.conversationId,
|
|
402420
|
-
...continuationActingUserId ? { actingUserId: continuationActingUserId } : {},
|
|
402421
402833
|
messages: continuationInput.messages
|
|
402422
402834
|
}, socket, runtime, opts?.onStatusChange, opts?.connectionId, continuationBatchId, recoveryLease, continuationCorrelation);
|
|
402423
402835
|
if (runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
@@ -402470,6 +402882,7 @@ var init_recovery = __esm(async () => {
|
|
|
402470
402882
|
init_permission_mode();
|
|
402471
402883
|
init_protocol_outbound();
|
|
402472
402884
|
init_recoverable_notices();
|
|
402885
|
+
init_recovery_ownership();
|
|
402473
402886
|
init_runtime();
|
|
402474
402887
|
init_secrets_sync();
|
|
402475
402888
|
init_turn_correlation();
|
|
@@ -402900,13 +403313,11 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
402900
403313
|
otid: crypto.randomUUID()
|
|
402901
403314
|
}
|
|
402902
403315
|
]);
|
|
402903
|
-
let continuationActingUserId;
|
|
402904
403316
|
let recoveryTurnCorrelation;
|
|
402905
403317
|
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
402906
403318
|
if (consumedQueuedTurn) {
|
|
402907
403319
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
402908
403320
|
recoveryTurnCorrelation = createTurnCorrelation(runtime, queuedTurn, dequeuedBatch.batchId);
|
|
402909
|
-
continuationActingUserId = queuedTurn.actingUserId;
|
|
402910
403321
|
continuationInput = appendQueuedTurnToInput(continuationInput, queuedTurn);
|
|
402911
403322
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
402912
403323
|
}
|
|
@@ -402920,7 +403331,6 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
402920
403331
|
agentId: runtime.agentId ?? undefined,
|
|
402921
403332
|
streamTokens: true,
|
|
402922
403333
|
background: true,
|
|
402923
|
-
...continuationActingUserId ? { actingUserId: continuationActingUserId } : {},
|
|
402924
403334
|
workingDirectory: recoveryWorkingDirectory,
|
|
402925
403335
|
preparedToolContext: preparedToolContext.preparedToolContext,
|
|
402926
403336
|
...continuationInput.imageFailureModesByMessageOtid ? {
|
|
@@ -403268,292 +403678,6 @@ var init_stream_recovery_status = __esm(() => {
|
|
|
403268
403678
|
init_protocol_outbound();
|
|
403269
403679
|
});
|
|
403270
403680
|
|
|
403271
|
-
// src/channels/teleport-guard.ts
|
|
403272
|
-
function getLocalChannelTeleportError(scope) {
|
|
403273
|
-
const channels = getSupportedChannelIds().filter((channelId) => {
|
|
403274
|
-
return readRoutes(channelId).some((route) => route.agentId === scope.agentId && route.conversationId === scope.conversationId && route.enabled !== false && route.outboundEnabled !== false);
|
|
403275
|
-
});
|
|
403276
|
-
if (channels.length === 0)
|
|
403277
|
-
return null;
|
|
403278
|
-
return `This conversation is bound to ${channels.join(", ")} on this computer. Teleport is blocked because MessageChannel cannot follow the conversation to another computer yet. Remove the channel route or continue locally.`;
|
|
403279
|
-
}
|
|
403280
|
-
var init_teleport_guard = __esm(() => {
|
|
403281
|
-
init_plugin_registry();
|
|
403282
|
-
init_routing();
|
|
403283
|
-
});
|
|
403284
|
-
|
|
403285
|
-
// src/websocket/listener/teleport.ts
|
|
403286
|
-
function buildTeleportContinuationMessages(params) {
|
|
403287
|
-
return [
|
|
403288
|
-
{
|
|
403289
|
-
type: "approval",
|
|
403290
|
-
approvals: params.approvals,
|
|
403291
|
-
otid: params.teleportId
|
|
403292
|
-
},
|
|
403293
|
-
{
|
|
403294
|
-
role: "system",
|
|
403295
|
-
content: "<system-reminder>Teleportation to this environment is complete. Continue the existing task from this environment now.</system-reminder>",
|
|
403296
|
-
otid: `${params.teleportId}:continue`
|
|
403297
|
-
}
|
|
403298
|
-
];
|
|
403299
|
-
}
|
|
403300
|
-
function escapeSystemReminderText(value) {
|
|
403301
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
403302
|
-
}
|
|
403303
|
-
function buildTeleportFailureMessages(params) {
|
|
403304
|
-
const messages = [];
|
|
403305
|
-
if (params.approvals && params.approvals.length > 0) {
|
|
403306
|
-
messages.push({
|
|
403307
|
-
type: "approval",
|
|
403308
|
-
approvals: params.approvals,
|
|
403309
|
-
otid: params.teleportId
|
|
403310
|
-
});
|
|
403311
|
-
}
|
|
403312
|
-
messages.push({
|
|
403313
|
-
role: "system",
|
|
403314
|
-
content: `<system-reminder>Teleportation failed.
|
|
403315
|
-
|
|
403316
|
-
Error: ${escapeSystemReminderText(params.error)}
|
|
403317
|
-
|
|
403318
|
-
Continue the existing task from this environment now.</system-reminder>`,
|
|
403319
|
-
otid: `${params.teleportId}:failed`
|
|
403320
|
-
});
|
|
403321
|
-
return messages;
|
|
403322
|
-
}
|
|
403323
|
-
function getPendingTeleports(runtime) {
|
|
403324
|
-
runtime.pendingTeleports ??= new Map;
|
|
403325
|
-
return runtime.pendingTeleports;
|
|
403326
|
-
}
|
|
403327
|
-
function findPendingTeleportForRuntime(runtime, agentId, conversationId) {
|
|
403328
|
-
for (const pending of getPendingTeleports(runtime).values()) {
|
|
403329
|
-
if (pending.agentId === agentId && pending.conversationId === conversationId && pending.readyAt === undefined) {
|
|
403330
|
-
return pending;
|
|
403331
|
-
}
|
|
403332
|
-
}
|
|
403333
|
-
return null;
|
|
403334
|
-
}
|
|
403335
|
-
function isRuntimeTeleportPending(runtime, agentId, conversationId) {
|
|
403336
|
-
if (!agentId)
|
|
403337
|
-
return false;
|
|
403338
|
-
return [...runtime.pendingTeleports?.values() ?? []].some((pending) => !pending.error && pending.agentId === agentId && pending.conversationId === conversationId);
|
|
403339
|
-
}
|
|
403340
|
-
function clearPriorReadyTeleports(params) {
|
|
403341
|
-
const pendingTeleports = params.listener.pendingTeleports;
|
|
403342
|
-
if (!pendingTeleports)
|
|
403343
|
-
return;
|
|
403344
|
-
for (const [teleportId, pending] of pendingTeleports) {
|
|
403345
|
-
if (teleportId === params.currentTeleportId || pending.readyAt === undefined) {
|
|
403346
|
-
continue;
|
|
403347
|
-
}
|
|
403348
|
-
if (pending.agentId === params.agentId && pending.conversationId === params.conversationId) {
|
|
403349
|
-
pendingTeleports.delete(teleportId);
|
|
403350
|
-
}
|
|
403351
|
-
}
|
|
403352
|
-
}
|
|
403353
|
-
function hasAcceptedInputsWaiting(runtime, includeQueuePump) {
|
|
403354
|
-
return runtime.queueRuntime.length > 0 || runtime.pendingTurns > 0 || runtime.queuedMessagesByItemId.size > 0 || includeQueuePump && (runtime.queuePumpActive || runtime.queuePumpScheduled);
|
|
403355
|
-
}
|
|
403356
|
-
function sendTeleportReady(runtime, pending, input) {
|
|
403357
|
-
const connection = runtime.connections.get(pending.connectionId);
|
|
403358
|
-
if (!connection || !isListenerTransportOpen(connection.writer))
|
|
403359
|
-
return false;
|
|
403360
|
-
const mode = getOrCreateConversationPermissionModeStateRef(runtime, pending.agentId, pending.conversationId).mode;
|
|
403361
|
-
const message = {
|
|
403362
|
-
type: "teleport_ready",
|
|
403363
|
-
teleport_id: pending.teleportId,
|
|
403364
|
-
runtime: {
|
|
403365
|
-
agent_id: pending.agentId,
|
|
403366
|
-
conversation_id: pending.conversationId
|
|
403367
|
-
},
|
|
403368
|
-
success: input.success,
|
|
403369
|
-
active_turn: pending.activeTurn,
|
|
403370
|
-
mode,
|
|
403371
|
-
...pending.continuation ? { continuation: pending.continuation } : {},
|
|
403372
|
-
...input.error ? { error: input.error } : {}
|
|
403373
|
-
};
|
|
403374
|
-
emitProtocolV2Message(connection.writer, runtime, message, message.runtime, toListenerConnection(pending.connectionId));
|
|
403375
|
-
return true;
|
|
403376
|
-
}
|
|
403377
|
-
function retainTeleportForRecovery(runtime, pending) {
|
|
403378
|
-
const timeout = setTimeout(() => {
|
|
403379
|
-
const current = runtime.pendingTeleports?.get(pending.teleportId);
|
|
403380
|
-
if (current === pending) {
|
|
403381
|
-
runtime.pendingTeleports?.delete(pending.teleportId);
|
|
403382
|
-
}
|
|
403383
|
-
}, TELEPORT_RECOVERY_TTL_MS);
|
|
403384
|
-
timeout.unref?.();
|
|
403385
|
-
}
|
|
403386
|
-
function handleTeleportProbe(command, socket, safeSocketSend) {
|
|
403387
|
-
safeSocketSend(socket, {
|
|
403388
|
-
type: "teleport_probe_response",
|
|
403389
|
-
request_id: command.request_id,
|
|
403390
|
-
runtime: command.runtime,
|
|
403391
|
-
supported: resolveBackendMode() === "api",
|
|
403392
|
-
drains_accepted_inputs: true,
|
|
403393
|
-
idempotent_continuation: true
|
|
403394
|
-
}, "teleport_probe_response", "teleport_probe");
|
|
403395
|
-
}
|
|
403396
|
-
function handleTeleportRequest(params) {
|
|
403397
|
-
const { listener, command, connectionId } = params;
|
|
403398
|
-
const pendingTeleports = getPendingTeleports(listener);
|
|
403399
|
-
const existing = pendingTeleports.get(command.teleport_id);
|
|
403400
|
-
if (existing) {
|
|
403401
|
-
if (existing.readyAt !== undefined) {
|
|
403402
|
-
sendTeleportReady(listener, existing, {
|
|
403403
|
-
success: existing.error === undefined,
|
|
403404
|
-
error: existing.error
|
|
403405
|
-
});
|
|
403406
|
-
}
|
|
403407
|
-
return;
|
|
403408
|
-
}
|
|
403409
|
-
const pending = {
|
|
403410
|
-
teleportId: command.teleport_id,
|
|
403411
|
-
connectionId,
|
|
403412
|
-
agentId: command.runtime.agent_id,
|
|
403413
|
-
conversationId: command.runtime.conversation_id,
|
|
403414
|
-
requestedAt: Date.now(),
|
|
403415
|
-
drainAcceptedInputs: false,
|
|
403416
|
-
activeTurn: false
|
|
403417
|
-
};
|
|
403418
|
-
const channelError = getLocalChannelTeleportError(pending);
|
|
403419
|
-
if (channelError) {
|
|
403420
|
-
pending.readyAt = Date.now();
|
|
403421
|
-
pending.error = channelError;
|
|
403422
|
-
pendingTeleports.set(pending.teleportId, pending);
|
|
403423
|
-
sendTeleportReady(listener, pending, {
|
|
403424
|
-
success: false,
|
|
403425
|
-
error: channelError
|
|
403426
|
-
});
|
|
403427
|
-
retainTeleportForRecovery(listener, pending);
|
|
403428
|
-
return;
|
|
403429
|
-
}
|
|
403430
|
-
const conflicting = findPendingTeleportForRuntime(listener, pending.agentId, pending.conversationId);
|
|
403431
|
-
if (conflicting) {
|
|
403432
|
-
pendingTeleports.set(pending.teleportId, pending);
|
|
403433
|
-
pending.readyAt = Date.now();
|
|
403434
|
-
pending.error = "Conversation already has a teleport pending";
|
|
403435
|
-
sendTeleportReady(listener, pending, {
|
|
403436
|
-
success: false,
|
|
403437
|
-
error: pending.error
|
|
403438
|
-
});
|
|
403439
|
-
retainTeleportForRecovery(listener, pending);
|
|
403440
|
-
return;
|
|
403441
|
-
}
|
|
403442
|
-
pendingTeleports.set(pending.teleportId, pending);
|
|
403443
|
-
const conversationRuntime = getConversationRuntime(listener, pending.agentId, pending.conversationId);
|
|
403444
|
-
pending.drainAcceptedInputs = conversationRuntime ? hasAcceptedInputsWaiting(conversationRuntime, true) : false;
|
|
403445
|
-
if (!conversationRuntime?.isProcessing && !pending.drainAcceptedInputs) {
|
|
403446
|
-
if (sendTeleportReady(listener, pending, { success: true })) {
|
|
403447
|
-
pending.readyAt = Date.now();
|
|
403448
|
-
retainTeleportForRecovery(listener, pending);
|
|
403449
|
-
}
|
|
403450
|
-
}
|
|
403451
|
-
}
|
|
403452
|
-
function claimPendingTeleportAtBoundary(params) {
|
|
403453
|
-
const pending = findPendingTeleportForRuntime(params.listener, params.agentId, params.conversationId);
|
|
403454
|
-
if (!pending)
|
|
403455
|
-
return null;
|
|
403456
|
-
if (pending.drainAcceptedInputs) {
|
|
403457
|
-
if (params.activeTurn)
|
|
403458
|
-
return null;
|
|
403459
|
-
const runtime = getConversationRuntime(params.listener, params.agentId, params.conversationId);
|
|
403460
|
-
if (runtime && hasAcceptedInputsWaiting(runtime, false))
|
|
403461
|
-
return null;
|
|
403462
|
-
}
|
|
403463
|
-
const connection = params.listener.connections.get(pending.connectionId);
|
|
403464
|
-
if (!connection || !isListenerTransportOpen(connection.writer))
|
|
403465
|
-
return null;
|
|
403466
|
-
pending.readyAt = Date.now();
|
|
403467
|
-
pending.activeTurn = params.activeTurn;
|
|
403468
|
-
pending.continuation = params.continuation;
|
|
403469
|
-
return pending;
|
|
403470
|
-
}
|
|
403471
|
-
function emitClaimedTeleportReady(listener, pending) {
|
|
403472
|
-
const sent = sendTeleportReady(listener, pending, { success: true });
|
|
403473
|
-
if (sent) {
|
|
403474
|
-
retainTeleportForRecovery(listener, pending);
|
|
403475
|
-
}
|
|
403476
|
-
return sent;
|
|
403477
|
-
}
|
|
403478
|
-
function finishTeleport(runtime, lease, pending) {
|
|
403479
|
-
const transition = runtime.turnLifecycle.finish(lease, "cancelled");
|
|
403480
|
-
if (!transition.finished)
|
|
403481
|
-
return transition;
|
|
403482
|
-
emitRuntimeStateUpdates(runtime, {
|
|
403483
|
-
agent_id: pending.agentId,
|
|
403484
|
-
conversation_id: pending.conversationId
|
|
403485
|
-
});
|
|
403486
|
-
emitClaimedTeleportReady(runtime.listener, pending);
|
|
403487
|
-
return transition;
|
|
403488
|
-
}
|
|
403489
|
-
function finishPendingTeleport(runtime) {
|
|
403490
|
-
if (!runtime.agentId)
|
|
403491
|
-
return;
|
|
403492
|
-
const pending = findPendingTeleportForRuntime(runtime.listener, runtime.agentId, runtime.conversationId);
|
|
403493
|
-
if (!pending || runtime.lastStopReason !== "end_turn" && !pending.drainAcceptedInputs) {
|
|
403494
|
-
return;
|
|
403495
|
-
}
|
|
403496
|
-
const claimed = claimPendingTeleportAtBoundary({
|
|
403497
|
-
listener: runtime.listener,
|
|
403498
|
-
agentId: runtime.agentId,
|
|
403499
|
-
conversationId: runtime.conversationId,
|
|
403500
|
-
activeTurn: false
|
|
403501
|
-
});
|
|
403502
|
-
if (claimed)
|
|
403503
|
-
emitClaimedTeleportReady(runtime.listener, claimed);
|
|
403504
|
-
}
|
|
403505
|
-
function takeFailedTeleport(params) {
|
|
403506
|
-
const pending = params.listener.pendingTeleports?.get(params.teleportId);
|
|
403507
|
-
if (!pending || pending.agentId !== params.agentId || pending.conversationId !== params.conversationId) {
|
|
403508
|
-
return null;
|
|
403509
|
-
}
|
|
403510
|
-
params.listener.pendingTeleports?.delete(params.teleportId);
|
|
403511
|
-
return pending;
|
|
403512
|
-
}
|
|
403513
|
-
function handleTeleportFailure(params) {
|
|
403514
|
-
const pending = takeFailedTeleport({
|
|
403515
|
-
listener: params.listener,
|
|
403516
|
-
teleportId: params.command.teleport_id,
|
|
403517
|
-
agentId: params.command.runtime.agent_id,
|
|
403518
|
-
conversationId: params.command.runtime.conversation_id
|
|
403519
|
-
});
|
|
403520
|
-
if (!pending || pending.error)
|
|
403521
|
-
return;
|
|
403522
|
-
const runtime = params.getOrCreateScopedRuntime(params.listener, pending.agentId, pending.conversationId);
|
|
403523
|
-
emitLoopErrorNotice(params.socket, runtime, {
|
|
403524
|
-
message: `Teleport failed: ${params.command.error}`,
|
|
403525
|
-
stopReason: "error",
|
|
403526
|
-
isTerminal: false,
|
|
403527
|
-
agentId: pending.agentId,
|
|
403528
|
-
conversationId: pending.conversationId
|
|
403529
|
-
});
|
|
403530
|
-
params.runDetachedListenerTask("teleport_failed", async () => {
|
|
403531
|
-
await params.processIncomingMessage({
|
|
403532
|
-
type: "message",
|
|
403533
|
-
connectionId: pending.connectionId,
|
|
403534
|
-
agentId: pending.agentId,
|
|
403535
|
-
conversationId: pending.conversationId,
|
|
403536
|
-
messages: buildTeleportFailureMessages({
|
|
403537
|
-
teleportId: params.command.teleport_id,
|
|
403538
|
-
error: params.command.error,
|
|
403539
|
-
approvals: pending.continuation?.approvals
|
|
403540
|
-
})
|
|
403541
|
-
}, params.socket, runtime, params.onStatusChange, pending.connectionId);
|
|
403542
|
-
});
|
|
403543
|
-
}
|
|
403544
|
-
var TELEPORT_RECOVERY_TTL_MS;
|
|
403545
|
-
var init_teleport = __esm(() => {
|
|
403546
|
-
init_backend_mode();
|
|
403547
|
-
init_teleport_guard();
|
|
403548
|
-
init_connection();
|
|
403549
|
-
init_permission_mode();
|
|
403550
|
-
init_protocol_outbound();
|
|
403551
|
-
init_recoverable_notices();
|
|
403552
|
-
init_runtime();
|
|
403553
|
-
init_transport();
|
|
403554
|
-
TELEPORT_RECOVERY_TTL_MS = 5 * 60000;
|
|
403555
|
-
});
|
|
403556
|
-
|
|
403557
403681
|
// node_modules/diff/libesm/diff/base.js
|
|
403558
403682
|
class Diff2 {
|
|
403559
403683
|
diff(oldStr, newStr, options = {}) {
|
|
@@ -405988,9 +406112,7 @@ async function handleApprovalStop(params) {
|
|
|
405988
406112
|
]);
|
|
405989
406113
|
let continuationBatchId = dequeuedBatchId;
|
|
405990
406114
|
const sendOptions = buildSendOptions() ?? {};
|
|
405991
|
-
const consumedQueuedTurn = consumeQueuedTurn(runtime
|
|
405992
|
-
actingUserId: sendOptions.actingUserId
|
|
405993
|
-
});
|
|
406115
|
+
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
405994
406116
|
if (consumedQueuedTurn) {
|
|
405995
406117
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
405996
406118
|
turnCorrelation?.appendDequeuedBatch(dequeuedBatch.batchId);
|
|
@@ -418806,6 +418928,7 @@ function createListenerMessageHandler(params) {
|
|
|
418806
418928
|
currentTeleportId: teleportId
|
|
418807
418929
|
});
|
|
418808
418930
|
const scopedRuntime2 = getOrCreateScopedRuntime2(runtime, parsed.runtime.agent_id, parsed.runtime.conversation_id);
|
|
418931
|
+
clearExpectedInboundTeleport(scopedRuntime2);
|
|
418809
418932
|
const acceptedKey = `teleport:${teleportId}`;
|
|
418810
418933
|
const previousDisposition = scopedRuntime2.acceptedInputDispositions.get(acceptedKey);
|
|
418811
418934
|
if (previousDisposition) {
|
|
@@ -419348,6 +419471,10 @@ async function recoverApprovalStateForSync(runtime, scope, deps = {}) {
|
|
|
419348
419471
|
clearRecoveredApprovalState(runtime);
|
|
419349
419472
|
return;
|
|
419350
419473
|
}
|
|
419474
|
+
if (!await canRecoverConversation(runtime)) {
|
|
419475
|
+
clearRecoveredApprovalState(runtime);
|
|
419476
|
+
return "deferred";
|
|
419477
|
+
}
|
|
419351
419478
|
const existingRecovered = runtime.recoveredApprovalState;
|
|
419352
419479
|
if (existingRecovered && existingRecovered.agentId === scope.agent_id && existingRecovered.conversationId === scope.conversation_id && existingRecovered.pendingRequestIds.size > 0) {
|
|
419353
419480
|
return;
|
|
@@ -419380,6 +419507,8 @@ async function recoverApprovalStateForSync(runtime, scope, deps = {}) {
|
|
|
419380
419507
|
clearRecoveredApprovalState(runtime);
|
|
419381
419508
|
return;
|
|
419382
419509
|
}
|
|
419510
|
+
if (!await canRecoverConversation(runtime))
|
|
419511
|
+
return "deferred";
|
|
419383
419512
|
if (hasInterruptedCacheForScope(runtime.listener, scope) || sameActiveScope && (runtime.turnLifecycle.kind !== "idle" || runtime.pendingApprovalResolvers.size > 0)) {
|
|
419384
419513
|
return;
|
|
419385
419514
|
}
|
|
@@ -419424,6 +419553,7 @@ async function recoverApprovalStateForSync(runtime, scope, deps = {}) {
|
|
|
419424
419553
|
autoDecisions: staleDenialDecisions,
|
|
419425
419554
|
allApprovals: pendingApprovals
|
|
419426
419555
|
};
|
|
419556
|
+
return;
|
|
419427
419557
|
}
|
|
419428
419558
|
var init_recovery_sync = __esm(() => {
|
|
419429
419559
|
init_error();
|
|
@@ -419431,6 +419561,7 @@ var init_recovery_sync = __esm(() => {
|
|
|
419431
419561
|
init_turn_recovery_policy();
|
|
419432
419562
|
init_backend2();
|
|
419433
419563
|
init_interactive_policy();
|
|
419564
|
+
init_recovery_ownership();
|
|
419434
419565
|
init_runtime();
|
|
419435
419566
|
});
|
|
419436
419567
|
|
|
@@ -419440,8 +419571,8 @@ async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
|
|
|
419440
419571
|
const recoverFn = opts?.recoverApprovalStateForSync ?? recoverApprovalStateForSync;
|
|
419441
419572
|
if ((opts?.recoverApprovals ?? true) || !syncScopedRuntime.syncApprovalRecoveryCompleted) {
|
|
419442
419573
|
try {
|
|
419443
|
-
await recoverFn(syncScopedRuntime, scope);
|
|
419444
|
-
syncScopedRuntime.syncApprovalRecoveryCompleted =
|
|
419574
|
+
const recovered = await recoverFn(syncScopedRuntime, scope);
|
|
419575
|
+
syncScopedRuntime.syncApprovalRecoveryCompleted = recovered !== "deferred";
|
|
419445
419576
|
} catch (error4) {
|
|
419446
419577
|
trackBoundaryError({
|
|
419447
419578
|
errorType: "listener_sync_recovery_failed",
|
|
@@ -440813,7 +440944,7 @@ var init_mcp_client = __esm(() => {
|
|
|
440813
440944
|
init_streamableHttp();
|
|
440814
440945
|
DEFAULT_CLIENT_INFO = {
|
|
440815
440946
|
name: "letta-code",
|
|
440816
|
-
version: "0.32.
|
|
440947
|
+
version: "0.32.8"
|
|
440817
440948
|
};
|
|
440818
440949
|
});
|
|
440819
440950
|
|
|
@@ -442650,25 +442781,6 @@ var init_message_search = __esm(() => {
|
|
|
442650
442781
|
init_transcript_search();
|
|
442651
442782
|
});
|
|
442652
442783
|
|
|
442653
|
-
// src/backend/api/agents.ts
|
|
442654
|
-
async function getAgentContextOverview(agentId, options) {
|
|
442655
|
-
return apiRequest("GET", `/v1/agents/${agentId}/context`, undefined, {
|
|
442656
|
-
signal: options?.signal
|
|
442657
|
-
});
|
|
442658
|
-
}
|
|
442659
|
-
async function createMinimalAgent(apiKey, name) {
|
|
442660
|
-
return apiRequest("POST", "/v1/agents", { name }, {
|
|
442661
|
-
baseUrl: "https://api.letta.com",
|
|
442662
|
-
apiKey
|
|
442663
|
-
});
|
|
442664
|
-
}
|
|
442665
|
-
async function getAgentRuntimeStatus(agentId, conversationIds) {
|
|
442666
|
-
return apiRequest("GET", `/v1/agents/${encodeURIComponent(agentId)}/runtime-status`, undefined, { query: { conversation_ids: conversationIds.join(",") } });
|
|
442667
|
-
}
|
|
442668
|
-
var init_agents7 = __esm(() => {
|
|
442669
|
-
init_request();
|
|
442670
|
-
});
|
|
442671
|
-
|
|
442672
442784
|
// src/cli/subcommands/message-status.ts
|
|
442673
442785
|
async function readMessageStatus(conversationId, agentId, backend3, deps = { getAgentRuntimeStatus, getLatestConversationSuperRun }) {
|
|
442674
442786
|
if (!backend3.capabilities.environmentRouting)
|
|
@@ -455161,9 +455273,6 @@ function shouldEnqueueCloudSend(values4, cloud, isAgentLaunch) {
|
|
|
455161
455273
|
function validateSendOptions(values4) {
|
|
455162
455274
|
if (values4.resume)
|
|
455163
455275
|
throw new Error("--resume is interactive-only; use --conversation <id> in headless mode.");
|
|
455164
|
-
const computer = values4.computer ?? values4.environment ?? values4.env;
|
|
455165
|
-
if (computer !== undefined && !computer.trim())
|
|
455166
|
-
throw new Error("Computer selector must not be empty.");
|
|
455167
455276
|
if (values4["input-format"])
|
|
455168
455277
|
throw new Error("Cloud message delivery does not support --input-format stream-json.");
|
|
455169
455278
|
if (values4.new && values4.conversation)
|
|
@@ -455221,6 +455330,7 @@ async function tryCloudHeadlessSend(values4, prompt, backend3, isAgentLaunch, de
|
|
|
455221
455330
|
if (!["text", "json", "stream-json"].includes(format5))
|
|
455222
455331
|
throw new Error(`Invalid output format: ${format5}`);
|
|
455223
455332
|
validateSendOptions(values4);
|
|
455333
|
+
const computer = normalizeAgentMessageComputer(values4.computer ?? values4.environment ?? values4.env);
|
|
455224
455334
|
const explicitSender = values4["from-agent"];
|
|
455225
455335
|
const ambientSender = env5.AGENT_ID || env5.LETTA_AGENT_ID;
|
|
455226
455336
|
const sender = {
|
|
@@ -455238,7 +455348,15 @@ async function tryCloudHeadlessSend(values4, prompt, backend3, isAgentLaunch, de
|
|
|
455238
455348
|
}
|
|
455239
455349
|
if (!agentId && !conversationId)
|
|
455240
455350
|
throw new Error("Choose a destination with --agent or --conversation. Ambient AGENT_ID identifies the sender.");
|
|
455241
|
-
({ agentId, conversationId } = await resolveAgentMessageDestination({
|
|
455351
|
+
({ agentId, conversationId } = await resolveAgentMessageDestination({
|
|
455352
|
+
agentId,
|
|
455353
|
+
conversationId,
|
|
455354
|
+
senderAgentId: sender.agentId,
|
|
455355
|
+
currentConversation: {
|
|
455356
|
+
agentId: ambientSender,
|
|
455357
|
+
conversationId: env5.CONVERSATION_ID || env5.LETTA_CONVERSATION_ID
|
|
455358
|
+
}
|
|
455359
|
+
}, backend3, controller.signal));
|
|
455242
455360
|
const recovery = {
|
|
455243
455361
|
status_command: `letta messages status --agent ${agentId} --conversation ${conversationId}`,
|
|
455244
455362
|
messages_command: `letta messages list --agent ${agentId} --conversation ${conversationId}`
|
|
@@ -455253,7 +455371,7 @@ async function tryCloudHeadlessSend(values4, prompt, backend3, isAgentLaunch, de
|
|
|
455253
455371
|
conversationId,
|
|
455254
455372
|
clientMessageId,
|
|
455255
455373
|
content: buildAgentSendContent(sender, noWait, prompt),
|
|
455256
|
-
computer
|
|
455374
|
+
computer
|
|
455257
455375
|
}, AbortSignal.any([controller.signal, AbortSignal.timeout(30000)]));
|
|
455258
455376
|
clearTimeout(submissionTimeout);
|
|
455259
455377
|
if (noWait) {
|
|
@@ -456005,6 +456123,49 @@ var init_headless_tool_events = __esm(async () => {
|
|
|
456005
456123
|
await init_approval_execution();
|
|
456006
456124
|
});
|
|
456007
456125
|
|
|
456126
|
+
// src/queue/turn-queue-runtime.ts
|
|
456127
|
+
function stringifyUnexpectedContent(content) {
|
|
456128
|
+
try {
|
|
456129
|
+
return JSON.stringify(content) ?? String(content);
|
|
456130
|
+
} catch {
|
|
456131
|
+
return String(content);
|
|
456132
|
+
}
|
|
456133
|
+
}
|
|
456134
|
+
function appendContentParts(target2, content) {
|
|
456135
|
+
if (typeof content === "string") {
|
|
456136
|
+
target2.push({ type: "text", text: content });
|
|
456137
|
+
return;
|
|
456138
|
+
}
|
|
456139
|
+
if (!Array.isArray(content)) {
|
|
456140
|
+
if (content === null || content === undefined)
|
|
456141
|
+
return;
|
|
456142
|
+
target2.push({ type: "text", text: stringifyUnexpectedContent(content) });
|
|
456143
|
+
return;
|
|
456144
|
+
}
|
|
456145
|
+
target2.push(...content);
|
|
456146
|
+
}
|
|
456147
|
+
function mergeQueuedTurnInput(queued, options) {
|
|
456148
|
+
if (queued.length === 0) {
|
|
456149
|
+
return null;
|
|
456150
|
+
}
|
|
456151
|
+
const separatorText = options.separatorText ?? `
|
|
456152
|
+
`;
|
|
456153
|
+
const mergedParts = [];
|
|
456154
|
+
let isFirst = true;
|
|
456155
|
+
for (const item of queued) {
|
|
456156
|
+
if (!isFirst) {
|
|
456157
|
+
mergedParts.push({ type: "text", text: separatorText });
|
|
456158
|
+
}
|
|
456159
|
+
isFirst = false;
|
|
456160
|
+
if (item.kind === "task_notification" || item.kind === "cron_prompt") {
|
|
456161
|
+
mergedParts.push({ type: "text", text: item.text });
|
|
456162
|
+
continue;
|
|
456163
|
+
}
|
|
456164
|
+
appendContentParts(mergedParts, options.normalizeUserContent(item.content));
|
|
456165
|
+
}
|
|
456166
|
+
return mergedParts.length > 0 ? mergedParts : null;
|
|
456167
|
+
}
|
|
456168
|
+
|
|
456008
456169
|
// src/agent/defaults.ts
|
|
456009
456170
|
var exports_defaults = {};
|
|
456010
456171
|
__export(exports_defaults, {
|
|
@@ -463023,6 +463184,46 @@ var init_use_local_mod_adapter = __esm(async () => {
|
|
|
463023
463184
|
import_react44 = __toESM(require_react(), 1);
|
|
463024
463185
|
});
|
|
463025
463186
|
|
|
463187
|
+
// src/cli/helpers/ask-user-questions.ts
|
|
463188
|
+
function parseAskUserQuestions(approval) {
|
|
463189
|
+
const parsed = safeJsonParseOr(approval.toolArgs, {});
|
|
463190
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
463191
|
+
return [];
|
|
463192
|
+
}
|
|
463193
|
+
const questions = parsed.questions;
|
|
463194
|
+
if (!Array.isArray(questions) || questions.length < 1 || questions.length > 4) {
|
|
463195
|
+
return [];
|
|
463196
|
+
}
|
|
463197
|
+
return questions.every(isWellFormedQuestion) ? questions : [];
|
|
463198
|
+
}
|
|
463199
|
+
function isWellFormedQuestion(q2) {
|
|
463200
|
+
if (q2 == null || typeof q2 !== "object")
|
|
463201
|
+
return false;
|
|
463202
|
+
const question = q2;
|
|
463203
|
+
if (typeof question.question !== "string")
|
|
463204
|
+
return false;
|
|
463205
|
+
if (typeof question.header !== "string")
|
|
463206
|
+
return false;
|
|
463207
|
+
if (question.multiSelect !== undefined && typeof question.multiSelect !== "boolean") {
|
|
463208
|
+
return false;
|
|
463209
|
+
}
|
|
463210
|
+
if (question.allowOther !== undefined && typeof question.allowOther !== "boolean") {
|
|
463211
|
+
return false;
|
|
463212
|
+
}
|
|
463213
|
+
const options = question.options;
|
|
463214
|
+
if (!Array.isArray(options) || options.length < 2 || options.length > 4) {
|
|
463215
|
+
return false;
|
|
463216
|
+
}
|
|
463217
|
+
return options.every(isWellFormedOption);
|
|
463218
|
+
}
|
|
463219
|
+
function isWellFormedOption(o3) {
|
|
463220
|
+
if (o3 == null || typeof o3 !== "object")
|
|
463221
|
+
return false;
|
|
463222
|
+
const option2 = o3;
|
|
463223
|
+
return typeof option2.label === "string" && option2.label.length > 0 && typeof option2.description === "string";
|
|
463224
|
+
}
|
|
463225
|
+
var init_ask_user_questions = () => {};
|
|
463226
|
+
|
|
463026
463227
|
// src/cli/hooks/use-progress-indicator.ts
|
|
463027
463228
|
function useProgressIndicator(active = true) {
|
|
463028
463229
|
import_react45.useEffect(() => {
|
|
@@ -465271,7 +465472,7 @@ var init_InlineQuestionApproval = __esm(async () => {
|
|
|
465271
465472
|
const currentQuestion = questions[currentQuestionIndex];
|
|
465272
465473
|
const showOther = currentQuestion?.allowOther !== false;
|
|
465273
465474
|
const baseOptions = currentQuestion ? [
|
|
465274
|
-
...currentQuestion.options,
|
|
465475
|
+
...Array.isArray(currentQuestion.options) ? currentQuestion.options.filter((o3) => o3 != null && typeof o3 === "object" && typeof o3.label === "string" && typeof o3.description === "string") : [],
|
|
465275
465476
|
...showOther ? [{ label: "Type something.", description: "" }] : []
|
|
465276
465477
|
] : [];
|
|
465277
465478
|
const optionsWithOther = currentQuestion?.multiSelect ? [...baseOptions, { label: "Submit", description: "" }] : baseOptions;
|
|
@@ -466066,15 +466267,11 @@ function getMemoryFileEditInfo(approval) {
|
|
|
466066
466267
|
}
|
|
466067
466268
|
}
|
|
466068
466269
|
function getQuestions(approval) {
|
|
466069
|
-
|
|
466070
|
-
const args = JSON.parse(approval.toolArgs || "{}");
|
|
466071
|
-
return args.questions || [];
|
|
466072
|
-
} catch {
|
|
466073
|
-
return [];
|
|
466074
|
-
}
|
|
466270
|
+
return parseAskUserQuestions(approval);
|
|
466075
466271
|
}
|
|
466076
466272
|
var import_react54, jsx_dev_runtime30, ApprovalSwitch;
|
|
466077
466273
|
var init_ApprovalSwitch = __esm(async () => {
|
|
466274
|
+
init_ask_user_questions();
|
|
466078
466275
|
await __promiseAll([
|
|
466079
466276
|
init_tool_name_mapping(),
|
|
466080
466277
|
init_InlineBashApproval(),
|
|
@@ -503256,10 +503453,11 @@ function buildApprovalBatchKey(approvals) {
|
|
|
503256
503453
|
|
|
503257
503454
|
// src/cli/app/approval-questions.ts
|
|
503258
503455
|
function getQuestionsFromApproval(approval) {
|
|
503259
|
-
|
|
503260
|
-
return parsed.questions || [];
|
|
503456
|
+
return parseAskUserQuestions(approval);
|
|
503261
503457
|
}
|
|
503262
|
-
var init_approval_questions = () => {
|
|
503458
|
+
var init_approval_questions = __esm(() => {
|
|
503459
|
+
init_ask_user_questions();
|
|
503460
|
+
});
|
|
503263
503461
|
|
|
503264
503462
|
// src/cli/app/errors.ts
|
|
503265
503463
|
function extractErrorMeta(e2) {
|
|
@@ -522119,4 +522317,4 @@ function registerBunOAuthFlows() {
|
|
|
522119
522317
|
registerBunOAuthFlows();
|
|
522120
522318
|
await init_src5().then(() => exports_src2);
|
|
522121
522319
|
|
|
522122
|
-
//# debugId=
|
|
522320
|
+
//# debugId=A89D538A98A9FFDD64756E2164756E21
|