@letta-ai/letta-code 0.28.4 → 0.28.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js
CHANGED
|
@@ -3138,6 +3138,29 @@ var init_letta_client = __esm(() => {
|
|
|
3138
3138
|
init_error();
|
|
3139
3139
|
});
|
|
3140
3140
|
|
|
3141
|
+
// src/auth/oauth-refresh.ts
|
|
3142
|
+
async function refreshAccessTokenSingleFlight(refreshToken, deviceId, deviceName, refresh = refreshAccessToken) {
|
|
3143
|
+
const refreshKey = `${refreshToken}\x00${deviceId}`;
|
|
3144
|
+
const existing = inFlightRefreshes.get(refreshKey);
|
|
3145
|
+
if (existing) {
|
|
3146
|
+
return await existing;
|
|
3147
|
+
}
|
|
3148
|
+
const pending = refresh(refreshToken, deviceId, deviceName);
|
|
3149
|
+
inFlightRefreshes.set(refreshKey, pending);
|
|
3150
|
+
try {
|
|
3151
|
+
return await pending;
|
|
3152
|
+
} finally {
|
|
3153
|
+
if (inFlightRefreshes.get(refreshKey) === pending) {
|
|
3154
|
+
inFlightRefreshes.delete(refreshKey);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
var inFlightRefreshes;
|
|
3159
|
+
var init_oauth_refresh = __esm(() => {
|
|
3160
|
+
init_oauth();
|
|
3161
|
+
inFlightRefreshes = new Map;
|
|
3162
|
+
});
|
|
3163
|
+
|
|
3141
3164
|
// src/agent/agent-id.ts
|
|
3142
3165
|
function isLocalAgentId(agentId) {
|
|
3143
3166
|
return agentId.startsWith("agent-local-");
|
|
@@ -3846,14 +3869,13 @@ class SettingsManager {
|
|
|
3846
3869
|
}
|
|
3847
3870
|
async getSettingsWithSecureTokens() {
|
|
3848
3871
|
const baseSettings = this.getSettings();
|
|
3849
|
-
|
|
3872
|
+
const secureTokens = { ...this.secureTokensCache };
|
|
3850
3873
|
if (!getRuntimeContext()) {
|
|
3851
3874
|
const secretsAvailable2 = await this.isKeychainAvailable();
|
|
3852
3875
|
if (secretsAvailable2) {
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
};
|
|
3876
|
+
const storedTokens = await this.getSecureTokens();
|
|
3877
|
+
secureTokens.apiKey = storedTokens.apiKey ?? secureTokens.apiKey;
|
|
3878
|
+
secureTokens.refreshToken = storedTokens.refreshToken ?? secureTokens.refreshToken;
|
|
3857
3879
|
}
|
|
3858
3880
|
}
|
|
3859
3881
|
const fallbackRefreshToken = !secureTokens.refreshToken && baseSettings.refreshToken ? baseSettings.refreshToken : secureTokens.refreshToken;
|
|
@@ -4815,7 +4837,7 @@ var package_default;
|
|
|
4815
4837
|
var init_package = __esm(() => {
|
|
4816
4838
|
package_default = {
|
|
4817
4839
|
name: "@letta-ai/letta-code",
|
|
4818
|
-
version: "0.28.
|
|
4840
|
+
version: "0.28.5",
|
|
4819
4841
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
4820
4842
|
type: "module",
|
|
4821
4843
|
packageManager: "bun@1.3.0",
|
|
@@ -5113,7 +5135,7 @@ async function getClient() {
|
|
|
5113
5135
|
try {
|
|
5114
5136
|
const deviceId = settingsManager.getOrCreateDeviceId();
|
|
5115
5137
|
const deviceName = hostname();
|
|
5116
|
-
const tokens = await
|
|
5138
|
+
const tokens = await refreshAccessTokenSingleFlight(settings.refreshToken, deviceId, deviceName);
|
|
5117
5139
|
settingsManager.updateSettings({
|
|
5118
5140
|
env: { LETTA_API_KEY: tokens.access_token },
|
|
5119
5141
|
refreshToken: tokens.refresh_token || settings.refreshToken,
|
|
@@ -5176,6 +5198,7 @@ var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnosti
|
|
|
5176
5198
|
var init_client2 = __esm(() => {
|
|
5177
5199
|
init_letta_client();
|
|
5178
5200
|
init_oauth();
|
|
5201
|
+
init_oauth_refresh();
|
|
5179
5202
|
init_settings_manager();
|
|
5180
5203
|
init_error_reporting();
|
|
5181
5204
|
init_debug();
|
|
@@ -5855,6 +5878,7 @@ __export(exports_oauth, {
|
|
|
5855
5878
|
requestDeviceCode: () => requestDeviceCode,
|
|
5856
5879
|
refreshAccessToken: () => refreshAccessToken,
|
|
5857
5880
|
pollForToken: () => pollForToken,
|
|
5881
|
+
OAuthRefreshError: () => OAuthRefreshError,
|
|
5858
5882
|
OAUTH_CONFIG: () => OAUTH_CONFIG,
|
|
5859
5883
|
LETTA_CLOUD_API_URL: () => LETTA_CLOUD_API_URL
|
|
5860
5884
|
});
|
|
@@ -6035,11 +6059,22 @@ async function refreshAccessToken(refreshToken, deviceId, deviceName) {
|
|
|
6035
6059
|
});
|
|
6036
6060
|
if (!response.ok) {
|
|
6037
6061
|
const error = await response.json();
|
|
6038
|
-
throw new
|
|
6062
|
+
throw new OAuthRefreshError(`Failed to refresh access token from ${authHost}: ${error.error_description || error.error}`, {
|
|
6063
|
+
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
6064
|
+
status: response.status,
|
|
6065
|
+
oauthCode: error.error
|
|
6066
|
+
});
|
|
6039
6067
|
}
|
|
6040
6068
|
return await response.json();
|
|
6041
6069
|
} catch (error) {
|
|
6042
|
-
|
|
6070
|
+
if (error instanceof OAuthRefreshError) {
|
|
6071
|
+
throw error;
|
|
6072
|
+
}
|
|
6073
|
+
const actionError = toOAuthActionError("refresh access token", error);
|
|
6074
|
+
throw new OAuthRefreshError(actionError.message, {
|
|
6075
|
+
retryable: true,
|
|
6076
|
+
cause: error
|
|
6077
|
+
});
|
|
6043
6078
|
}
|
|
6044
6079
|
}
|
|
6045
6080
|
async function revokeToken(refreshToken) {
|
|
@@ -6125,7 +6160,7 @@ function classifyCredentialValidationError(error) {
|
|
|
6125
6160
|
}
|
|
6126
6161
|
return { ok: false, reason: "unknown", message };
|
|
6127
6162
|
}
|
|
6128
|
-
var LETTA_CLOUD_API_URL = "https://api.letta.com", OAUTH_CONFIG;
|
|
6163
|
+
var LETTA_CLOUD_API_URL = "https://api.letta.com", OAUTH_CONFIG, OAuthRefreshError;
|
|
6129
6164
|
var init_oauth = __esm(() => {
|
|
6130
6165
|
init_letta_client();
|
|
6131
6166
|
init_error();
|
|
@@ -6136,6 +6171,18 @@ var init_oauth = __esm(() => {
|
|
|
6136
6171
|
authBaseUrl: "https://app.letta.com",
|
|
6137
6172
|
apiBaseUrl: LETTA_CLOUD_API_URL
|
|
6138
6173
|
};
|
|
6174
|
+
OAuthRefreshError = class OAuthRefreshError extends Error {
|
|
6175
|
+
retryable;
|
|
6176
|
+
status;
|
|
6177
|
+
oauthCode;
|
|
6178
|
+
constructor(message, options) {
|
|
6179
|
+
super(message, { cause: options.cause });
|
|
6180
|
+
this.name = "OAuthRefreshError";
|
|
6181
|
+
this.retryable = options.retryable;
|
|
6182
|
+
this.status = options.status;
|
|
6183
|
+
this.oauthCode = options.oauthCode;
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6139
6186
|
});
|
|
6140
6187
|
|
|
6141
6188
|
// src/backend/backend-mode.ts
|
|
@@ -176039,7 +176086,7 @@ function isLocalAgentId2(agentId) {
|
|
|
176039
176086
|
return isLocalAgentId(agentId);
|
|
176040
176087
|
}
|
|
176041
176088
|
function buildChatUrl(agentId, options3) {
|
|
176042
|
-
const base2 = `${
|
|
176089
|
+
const base2 = `${CHAT_BASE}/chat/${agentId}`;
|
|
176043
176090
|
const params = new URLSearchParams;
|
|
176044
176091
|
if (options3?.view) {
|
|
176045
176092
|
params.set("view", options3.view);
|
|
@@ -176066,11 +176113,16 @@ function buildAgentTerminalLink(agentId, options3, label = agentId) {
|
|
|
176066
176113
|
const url2 = buildChatUrl(agentId, options3);
|
|
176067
176114
|
return `\x1B]8;;${url2}\x1B\\${label}\x1B]8;;\x1B\\`;
|
|
176068
176115
|
}
|
|
176069
|
-
function
|
|
176070
|
-
return `${
|
|
176116
|
+
function buildChatWebUrl(path5) {
|
|
176117
|
+
return `${CHAT_BASE}${path5}`;
|
|
176071
176118
|
}
|
|
176072
|
-
|
|
176073
|
-
|
|
176119
|
+
function buildPlatformUrl(path5) {
|
|
176120
|
+
return `${PLATFORM_BASE}${path5}`;
|
|
176121
|
+
}
|
|
176122
|
+
var CHAT_BASE = "https://chat.letta.com", PLATFORM_BASE = "https://platform.letta.com", LETTA_CHAT_API_KEYS_URL;
|
|
176123
|
+
var init_app_urls = __esm(() => {
|
|
176124
|
+
LETTA_CHAT_API_KEYS_URL = `${CHAT_BASE}/preferences/api-keys`;
|
|
176125
|
+
});
|
|
176074
176126
|
|
|
176075
176127
|
// src/channels/registry-presentation.ts
|
|
176076
176128
|
function channelDisplayName2(channelId) {
|
|
@@ -368054,6 +368106,13 @@ async function switchCurrentRuntimeWorkingDirectory(workingDirectory) {
|
|
|
368054
368106
|
process.env.USER_CWD = workingDirectory;
|
|
368055
368107
|
updateRuntimeContext({ workingDirectory });
|
|
368056
368108
|
}
|
|
368109
|
+
async function updateToolExecutionContextCwd(executionContextId, workingDirectory) {
|
|
368110
|
+
if (!executionContextId) {
|
|
368111
|
+
return;
|
|
368112
|
+
}
|
|
368113
|
+
const { updateToolExecutionContextWorkingDirectory } = await init_manager4().then(() => exports_manager2);
|
|
368114
|
+
updateToolExecutionContextWorkingDirectory(executionContextId, workingDirectory);
|
|
368115
|
+
}
|
|
368057
368116
|
async function switchConversationWorkingDirectory(params) {
|
|
368058
368117
|
const { runtime, workingDirectory } = params;
|
|
368059
368118
|
const agentId = normalizeCwdAgentId(params.agentId);
|
|
@@ -368657,13 +368716,10 @@ async function switchSessionToWorktree(params) {
|
|
|
368657
368716
|
agentId: runtimeContext.agentId ?? null,
|
|
368658
368717
|
conversationId: runtimeContext.conversationId
|
|
368659
368718
|
});
|
|
368660
|
-
|
|
368661
|
-
|
|
368662
|
-
await switchCurrentRuntimeWorkingDirectory(worktreePath);
|
|
368663
|
-
if (params.executionContextId) {
|
|
368664
|
-
const { updateToolExecutionContextWorkingDirectory } = await init_manager4().then(() => exports_manager2);
|
|
368665
|
-
updateToolExecutionContextWorkingDirectory(params.executionContextId, worktreePath);
|
|
368719
|
+
} else {
|
|
368720
|
+
await switchCurrentRuntimeWorkingDirectory(worktreePath);
|
|
368666
368721
|
}
|
|
368722
|
+
await updateToolExecutionContextCwd(params.executionContextId, worktreePath);
|
|
368667
368723
|
return true;
|
|
368668
368724
|
}
|
|
368669
368725
|
async function resolveWorktreeGitDir(worktreePath) {
|
|
@@ -383124,7 +383180,11 @@ function buildSubagentArgs(type3, config3, model, userPrompt, existingAgentId, e
|
|
|
383124
383180
|
args.push("--agent", existingAgentId, "--new");
|
|
383125
383181
|
}
|
|
383126
383182
|
} else {
|
|
383127
|
-
|
|
383183
|
+
if (options3.systemPromptOverride) {
|
|
383184
|
+
args.push("--new-agent", "--system-custom", options3.systemPromptOverride);
|
|
383185
|
+
} else {
|
|
383186
|
+
args.push("--new-agent", "--system", type3);
|
|
383187
|
+
}
|
|
383128
383188
|
const subagentTags = [`type:${type3}`];
|
|
383129
383189
|
if (options3.parentAgentId) {
|
|
383130
383190
|
subagentTags.push(`parent:${options3.parentAgentId}`);
|
|
@@ -383171,7 +383231,7 @@ function buildSubagentArgs(type3, config3, model, userPrompt, existingAgentId, e
|
|
|
383171
383231
|
}
|
|
383172
383232
|
return args;
|
|
383173
383233
|
}
|
|
383174
|
-
async function executeSubagent(type3, config3, model, userPrompt,
|
|
383234
|
+
async function executeSubagent(type3, config3, model, userPrompt, subagentId, isRetry = false, signal, existingAgentId, existingConversationId, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope, systemPromptOverride) {
|
|
383175
383235
|
if (signal?.aborted) {
|
|
383176
383236
|
return {
|
|
383177
383237
|
agentId: "",
|
|
@@ -383199,7 +383259,8 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383199
383259
|
backendMode,
|
|
383200
383260
|
promptTransport: "stdin",
|
|
383201
383261
|
parentAgentId,
|
|
383202
|
-
extraTools: config3.fork && inheritedChannelContext ? ["MessageChannel"] : undefined
|
|
383262
|
+
extraTools: config3.fork && inheritedChannelContext ? ["MessageChannel"] : undefined,
|
|
383263
|
+
systemPromptOverride
|
|
383203
383264
|
});
|
|
383204
383265
|
const launcher = resolveSubagentLauncher(cliArgs);
|
|
383205
383266
|
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
@@ -383314,7 +383375,7 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383314
383375
|
agentId: parentAgentIdOverride
|
|
383315
383376
|
});
|
|
383316
383377
|
if (primaryModel) {
|
|
383317
|
-
return executeSubagent(type3, config3, primaryModel, userPrompt,
|
|
383378
|
+
return executeSubagent(type3, config3, primaryModel, userPrompt, subagentId, true, signal, undefined, undefined, maxTurns, parentAgentIdOverride, transcriptPath);
|
|
383318
383379
|
}
|
|
383319
383380
|
}
|
|
383320
383381
|
const propagatedError = state.finalError?.trim();
|
|
@@ -383369,14 +383430,6 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383369
383430
|
};
|
|
383370
383431
|
}
|
|
383371
383432
|
}
|
|
383372
|
-
function getBaseURL() {
|
|
383373
|
-
const settings3 = settingsManager.getSettings();
|
|
383374
|
-
const baseURL = process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || "https://api.letta.com";
|
|
383375
|
-
if (baseURL === "https://api.letta.com") {
|
|
383376
|
-
return "https://app.letta.com";
|
|
383377
|
-
}
|
|
383378
|
-
return baseURL;
|
|
383379
|
-
}
|
|
383380
383433
|
function buildDeploySystemReminder(senderAgentName, senderAgentId) {
|
|
383381
383434
|
return `${SYSTEM_REMINDER_OPEN}
|
|
383382
383435
|
This task is from "${senderAgentName}" (agent ID: ${senderAgentId}), which deployed you as a subagent inside the Letta Code CLI (docs.letta.com/letta-code).
|
|
@@ -383420,7 +383473,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
383420
383473
|
|
|
383421
383474
|
`;
|
|
383422
383475
|
}
|
|
383423
|
-
async function spawnSubagent(type3, prompt, userModel, subagentId, signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentId, transcriptPath, parentConversationId, memoryScope) {
|
|
383476
|
+
async function spawnSubagent(type3, prompt, userModel, subagentId, signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentId, transcriptPath, parentConversationId, memoryScope, systemPromptOverride) {
|
|
383424
383477
|
const allConfigs = await getAllSubagentConfigs();
|
|
383425
383478
|
const config3 = allConfigs[type3];
|
|
383426
383479
|
if (!config3) {
|
|
@@ -383459,7 +383512,6 @@ async function spawnSubagent(type3, prompt, userModel, subagentId, signal, exist
|
|
|
383459
383512
|
subagentType: type3,
|
|
383460
383513
|
backendMode
|
|
383461
383514
|
});
|
|
383462
|
-
const baseURL = getBaseURL();
|
|
383463
383515
|
let finalPrompt = prompt;
|
|
383464
383516
|
if (isDeployingExisting && resolvedParentAgentId) {
|
|
383465
383517
|
try {
|
|
@@ -383479,7 +383531,7 @@ async function spawnSubagent(type3, prompt, userModel, subagentId, signal, exist
|
|
|
383479
383531
|
});
|
|
383480
383532
|
updateSubagent(subagentId, { agentURL: forkAgentURL });
|
|
383481
383533
|
}
|
|
383482
|
-
const result = await executeSubagent(type3, config3, model, finalPrompt,
|
|
383534
|
+
const result = await executeSubagent(type3, config3, model, finalPrompt, subagentId, false, signal, existingAgentId, existingConversationId, maxTurns, resolvedParentAgentId, transcriptPath, memoryScope, systemPromptOverride);
|
|
383483
383535
|
return result;
|
|
383484
383536
|
}
|
|
383485
383537
|
var NO_BASE_TOOL_SUBAGENT_TYPES;
|
|
@@ -383734,6 +383786,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
383734
383786
|
prompt,
|
|
383735
383787
|
description,
|
|
383736
383788
|
model,
|
|
383789
|
+
systemPromptOverride,
|
|
383737
383790
|
toolCallId,
|
|
383738
383791
|
existingAgentId,
|
|
383739
383792
|
existingConversationId,
|
|
@@ -383776,7 +383829,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
383776
383829
|
backgroundTasks.set(taskId, bgTask);
|
|
383777
383830
|
writeTaskTranscriptStart(outputFile, description, subagentType);
|
|
383778
383831
|
const parentAgentIdForSpawn = resolvedParentScope?.agentId;
|
|
383779
|
-
spawnSubagentFn(subagentType, prompt, model, subagentId, abortController.signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentIdForSpawn, transcriptPath, resolvedParentScope?.conversationId, memoryScope).then(async (result) => {
|
|
383832
|
+
spawnSubagentFn(subagentType, prompt, model, subagentId, abortController.signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentIdForSpawn, transcriptPath, resolvedParentScope?.conversationId, memoryScope, systemPromptOverride).then(async (result) => {
|
|
383780
383833
|
bgTask.status = result.success ? "completed" : "failed";
|
|
383781
383834
|
if (result.error) {
|
|
383782
383835
|
bgTask.error = result.error;
|
|
@@ -393736,16 +393789,16 @@ function toolResultToStoredReturnValue(message) {
|
|
|
393736
393789
|
};
|
|
393737
393790
|
});
|
|
393738
393791
|
}
|
|
393739
|
-
function projectThinkingContent(message,
|
|
393740
|
-
if (
|
|
393792
|
+
function projectThinkingContent(message, reasoning, contentStartIndex, date6, agentId, conversationId) {
|
|
393793
|
+
if (reasoning.length === 0)
|
|
393741
393794
|
return;
|
|
393742
393795
|
return {
|
|
393743
|
-
id: `${message.id}:reasoning:${
|
|
393796
|
+
id: `${message.id}:reasoning:${contentStartIndex}`,
|
|
393744
393797
|
date: date6,
|
|
393745
393798
|
agent_id: agentId,
|
|
393746
393799
|
conversation_id: conversationId,
|
|
393747
393800
|
message_type: "reasoning_message",
|
|
393748
|
-
reasoning
|
|
393801
|
+
reasoning
|
|
393749
393802
|
};
|
|
393750
393803
|
}
|
|
393751
393804
|
function projectToolCallContent(message, content, date6, agentId, conversationId) {
|
|
@@ -393815,6 +393868,8 @@ function projectLocalMessageToStoredMessages(message, fallbackAgentId, fallbackC
|
|
|
393815
393868
|
const messages = [];
|
|
393816
393869
|
let pendingTextContent = [];
|
|
393817
393870
|
let pendingTextStartIndex = -1;
|
|
393871
|
+
let pendingReasoningContent = [];
|
|
393872
|
+
let pendingReasoningStartIndex = -1;
|
|
393818
393873
|
const flushPendingText = () => {
|
|
393819
393874
|
if (pendingTextContent.length === 0)
|
|
393820
393875
|
return;
|
|
@@ -393831,29 +393886,46 @@ function projectLocalMessageToStoredMessages(message, fallbackAgentId, fallbackC
|
|
|
393831
393886
|
pendingTextContent = [];
|
|
393832
393887
|
pendingTextStartIndex = -1;
|
|
393833
393888
|
};
|
|
393889
|
+
const flushPendingReasoning = () => {
|
|
393890
|
+
if (pendingReasoningContent.length > 0) {
|
|
393891
|
+
const reasoningMessage = projectThinkingContent(message, pendingReasoningContent.join(`
|
|
393892
|
+
|
|
393893
|
+
`), pendingReasoningStartIndex, date6, agentId, conversationId);
|
|
393894
|
+
if (reasoningMessage)
|
|
393895
|
+
messages.push(reasoningMessage);
|
|
393896
|
+
}
|
|
393897
|
+
pendingReasoningContent = [];
|
|
393898
|
+
pendingReasoningStartIndex = -1;
|
|
393899
|
+
};
|
|
393834
393900
|
for (let contentIndex = 0;contentIndex < message.content.length; contentIndex++) {
|
|
393835
393901
|
const content = message.content[contentIndex];
|
|
393836
393902
|
if (!content)
|
|
393837
393903
|
continue;
|
|
393838
393904
|
if (isThinkingContent(content)) {
|
|
393839
393905
|
flushPendingText();
|
|
393840
|
-
|
|
393841
|
-
|
|
393842
|
-
|
|
393906
|
+
if (content.thinking.length > 0) {
|
|
393907
|
+
if (pendingReasoningStartIndex === -1) {
|
|
393908
|
+
pendingReasoningStartIndex = contentIndex;
|
|
393909
|
+
}
|
|
393910
|
+
pendingReasoningContent.push(content.thinking);
|
|
393911
|
+
}
|
|
393843
393912
|
continue;
|
|
393844
393913
|
}
|
|
393845
393914
|
if (isLocalToolCallContent(content)) {
|
|
393846
393915
|
flushPendingText();
|
|
393916
|
+
flushPendingReasoning();
|
|
393847
393917
|
messages.push(projectToolCallContent(message, content, date6, agentId, conversationId));
|
|
393848
393918
|
continue;
|
|
393849
393919
|
}
|
|
393850
393920
|
if (isTextContent(content)) {
|
|
393921
|
+
flushPendingReasoning();
|
|
393851
393922
|
if (pendingTextStartIndex === -1)
|
|
393852
393923
|
pendingTextStartIndex = contentIndex;
|
|
393853
393924
|
pendingTextContent.push({ type: "text", text: content.text });
|
|
393854
393925
|
}
|
|
393855
393926
|
}
|
|
393856
393927
|
flushPendingText();
|
|
393928
|
+
flushPendingReasoning();
|
|
393857
393929
|
return messages;
|
|
393858
393930
|
}
|
|
393859
393931
|
function withProjectedMessageDates(messages, _sourceMessageIndex) {
|
|
@@ -397075,8 +397147,8 @@ var init_error_formatter = __esm(() => {
|
|
|
397075
397147
|
init_app_urls();
|
|
397076
397148
|
init_error_context();
|
|
397077
397149
|
init_zai_errors();
|
|
397078
|
-
LETTA_USAGE_URL =
|
|
397079
|
-
LETTA_AGENTS_URL =
|
|
397150
|
+
LETTA_USAGE_URL = buildChatWebUrl("/preferences/usage");
|
|
397151
|
+
LETTA_AGENTS_URL = buildPlatformUrl("/projects/default-project/agents");
|
|
397080
397152
|
CLOUDFLARE_EDGE_5XX_MARKER_PATTERN = /(^|\s)(502|52[0-6])\s*<!doctype html|error code\s*(502|52[0-6])/i;
|
|
397081
397153
|
CLOUDFLARE_EDGE_5XX_TITLE_PATTERN = /\|\s*(502|52[0-6])\s*:/i;
|
|
397082
397154
|
CLOUDFLARE_EDGE_5XX_FORMATTED_PATTERN = /\bCloudflare\s+(502|52[0-6])\b/i;
|
|
@@ -399301,12 +399373,26 @@ function errorFromAssistantEvent(part) {
|
|
|
399301
399373
|
return new Error("Unknown provider stream error");
|
|
399302
399374
|
return new Error(part.error.errorMessage ?? "Unknown local provider error");
|
|
399303
399375
|
}
|
|
399304
|
-
function
|
|
399305
|
-
|
|
399376
|
+
function contentMatchesMessageType(content, messageType) {
|
|
399377
|
+
if (!content || typeof content !== "object" || !("type" in content)) {
|
|
399378
|
+
return false;
|
|
399379
|
+
}
|
|
399380
|
+
return messageType === "assistant_message" ? content.type === "text" : content.type === "thinking";
|
|
399381
|
+
}
|
|
399382
|
+
function contiguousContentStartIndex(partial4, contentIndex, messageType) {
|
|
399383
|
+
let startIndex = contentIndex;
|
|
399384
|
+
while (startIndex > 0 && contentMatchesMessageType(partial4.content[startIndex - 1], messageType)) {
|
|
399385
|
+
startIndex -= 1;
|
|
399386
|
+
}
|
|
399387
|
+
return startIndex;
|
|
399388
|
+
}
|
|
399389
|
+
function otidForContentSegment(otids, prefix, contentIndex, partial4, messageType) {
|
|
399390
|
+
const segmentStartIndex = contiguousContentStartIndex(partial4, contentIndex, messageType);
|
|
399391
|
+
const existing = otids.get(segmentStartIndex);
|
|
399306
399392
|
if (existing)
|
|
399307
399393
|
return existing;
|
|
399308
|
-
const otid = `${prefix}-${
|
|
399309
|
-
otids.set(
|
|
399394
|
+
const otid = `${prefix}-${segmentStartIndex}-${randomUUID20()}`;
|
|
399395
|
+
otids.set(segmentStartIndex, otid);
|
|
399310
399396
|
return otid;
|
|
399311
399397
|
}
|
|
399312
399398
|
function createProviderLettaStream(events, contextTokensEstimate) {
|
|
@@ -399337,7 +399423,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
|
|
|
399337
399423
|
if (part.type === "text_delta") {
|
|
399338
399424
|
yield {
|
|
399339
399425
|
message_type: "assistant_message",
|
|
399340
|
-
otid:
|
|
399426
|
+
otid: otidForContentSegment(assistantOtids, "provider-assistant", part.contentIndex, part.partial, "assistant_message"),
|
|
399341
399427
|
content: [{ type: "text", text: part.delta }]
|
|
399342
399428
|
};
|
|
399343
399429
|
continue;
|
|
@@ -399345,7 +399431,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
|
|
|
399345
399431
|
if (part.type === "thinking_delta") {
|
|
399346
399432
|
yield {
|
|
399347
399433
|
message_type: "reasoning_message",
|
|
399348
|
-
otid:
|
|
399434
|
+
otid: otidForContentSegment(reasoningOtids, "provider-reasoning", part.contentIndex, part.partial, "reasoning_message"),
|
|
399349
399435
|
reasoning: part.delta
|
|
399350
399436
|
};
|
|
399351
399437
|
continue;
|
|
@@ -402208,6 +402294,7 @@ __export(exports_oauth2, {
|
|
|
402208
402294
|
requestDeviceCode: () => requestDeviceCode2,
|
|
402209
402295
|
refreshAccessToken: () => refreshAccessToken3,
|
|
402210
402296
|
pollForToken: () => pollForToken2,
|
|
402297
|
+
OAuthRefreshError: () => OAuthRefreshError2,
|
|
402211
402298
|
OAUTH_CONFIG: () => OAUTH_CONFIG2,
|
|
402212
402299
|
LETTA_CLOUD_API_URL: () => LETTA_CLOUD_API_URL2
|
|
402213
402300
|
});
|
|
@@ -402388,11 +402475,22 @@ async function refreshAccessToken3(refreshToken, deviceId, deviceName) {
|
|
|
402388
402475
|
});
|
|
402389
402476
|
if (!response.ok) {
|
|
402390
402477
|
const error54 = await response.json();
|
|
402391
|
-
throw new
|
|
402478
|
+
throw new OAuthRefreshError2(`Failed to refresh access token from ${authHost}: ${error54.error_description || error54.error}`, {
|
|
402479
|
+
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
402480
|
+
status: response.status,
|
|
402481
|
+
oauthCode: error54.error
|
|
402482
|
+
});
|
|
402392
402483
|
}
|
|
402393
402484
|
return await response.json();
|
|
402394
402485
|
} catch (error54) {
|
|
402395
|
-
|
|
402486
|
+
if (error54 instanceof OAuthRefreshError2) {
|
|
402487
|
+
throw error54;
|
|
402488
|
+
}
|
|
402489
|
+
const actionError = toOAuthActionError2("refresh access token", error54);
|
|
402490
|
+
throw new OAuthRefreshError2(actionError.message, {
|
|
402491
|
+
retryable: true,
|
|
402492
|
+
cause: error54
|
|
402493
|
+
});
|
|
402396
402494
|
}
|
|
402397
402495
|
}
|
|
402398
402496
|
async function revokeToken2(refreshToken) {
|
|
@@ -402478,7 +402576,7 @@ function classifyCredentialValidationError2(error54) {
|
|
|
402478
402576
|
}
|
|
402479
402577
|
return { ok: false, reason: "unknown", message };
|
|
402480
402578
|
}
|
|
402481
|
-
var LETTA_CLOUD_API_URL2 = "https://api.letta.com", OAUTH_CONFIG2;
|
|
402579
|
+
var LETTA_CLOUD_API_URL2 = "https://api.letta.com", OAUTH_CONFIG2, OAuthRefreshError2;
|
|
402482
402580
|
var init_oauth4 = __esm(() => {
|
|
402483
402581
|
init_letta_client();
|
|
402484
402582
|
init_error();
|
|
@@ -402489,6 +402587,18 @@ var init_oauth4 = __esm(() => {
|
|
|
402489
402587
|
authBaseUrl: "https://app.letta.com",
|
|
402490
402588
|
apiBaseUrl: LETTA_CLOUD_API_URL2
|
|
402491
402589
|
};
|
|
402590
|
+
OAuthRefreshError2 = class OAuthRefreshError2 extends Error {
|
|
402591
|
+
retryable;
|
|
402592
|
+
status;
|
|
402593
|
+
oauthCode;
|
|
402594
|
+
constructor(message, options3) {
|
|
402595
|
+
super(message, { cause: options3.cause });
|
|
402596
|
+
this.name = "OAuthRefreshError";
|
|
402597
|
+
this.retryable = options3.retryable;
|
|
402598
|
+
this.status = options3.status;
|
|
402599
|
+
this.oauthCode = options3.oauthCode;
|
|
402600
|
+
}
|
|
402601
|
+
};
|
|
402492
402602
|
});
|
|
402493
402603
|
|
|
402494
402604
|
// node_modules/react/cjs/react.development.js
|
|
@@ -442898,10 +443008,9 @@ async function prepareReflectionMemoryWorktreeLaunch(params) {
|
|
|
442898
443008
|
parentMemoryDir: memoryDir
|
|
442899
443009
|
});
|
|
442900
443010
|
try {
|
|
442901
|
-
const
|
|
442902
|
-
const reflectionPrompt = buildReflectionSubagentPrompt({
|
|
443011
|
+
const reflectionPrompt = params.reflectionPromptOverride ?? buildReflectionSubagentPrompt({
|
|
442903
443012
|
instruction: params.instruction,
|
|
442904
|
-
parentMemory
|
|
443013
|
+
parentMemory: await buildParentMemorySnapshot(worktree.worktreeDir)
|
|
442905
443014
|
});
|
|
442906
443015
|
return { worktree, reflectionPrompt };
|
|
442907
443016
|
} catch (error54) {
|
|
@@ -442982,7 +443091,8 @@ async function launchReflectionSubagent(options3) {
|
|
|
442982
443091
|
}
|
|
442983
443092
|
const { worktree, reflectionPrompt } = await prepareReflectionMemoryWorktreeLaunch({
|
|
442984
443093
|
agentId,
|
|
442985
|
-
instruction: options3.instruction
|
|
443094
|
+
instruction: options3.instruction,
|
|
443095
|
+
reflectionPromptOverride: options3.reflectionPromptOverride
|
|
442986
443096
|
});
|
|
442987
443097
|
preparedWorktree = worktree;
|
|
442988
443098
|
const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
|
|
@@ -443001,6 +443111,7 @@ async function launchReflectionSubagent(options3) {
|
|
|
443001
443111
|
prompt: reflectionPrompt,
|
|
443002
443112
|
description,
|
|
443003
443113
|
model: options3.model,
|
|
443114
|
+
systemPromptOverride: options3.reflectionSystemPromptOverride,
|
|
443004
443115
|
silentCompletion: true,
|
|
443005
443116
|
transcriptPath: autoPayload.payloadPath,
|
|
443006
443117
|
memoryScope: buildReflectionMemoryScope(worktree),
|
|
@@ -445421,6 +445532,303 @@ var init_approval = __esm(async () => {
|
|
|
445421
445532
|
]);
|
|
445422
445533
|
});
|
|
445423
445534
|
|
|
445535
|
+
// src/websocket/listen-register.ts
|
|
445536
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
445537
|
+
function deriveListenerInstanceId(surface, connectionName) {
|
|
445538
|
+
const nameHash = createHash6("sha256").update(connectionName).digest("hex").slice(0, 16);
|
|
445539
|
+
return `${surface}-${nameHash}`;
|
|
445540
|
+
}
|
|
445541
|
+
function isTransientRegistrationError(error54) {
|
|
445542
|
+
if (error54 instanceof RegistrationError) {
|
|
445543
|
+
return error54.statusCode === 0 || error54.statusCode === 429 || error54.statusCode >= 500;
|
|
445544
|
+
}
|
|
445545
|
+
return true;
|
|
445546
|
+
}
|
|
445547
|
+
function parseRetryAfterMs(value) {
|
|
445548
|
+
if (!value) {
|
|
445549
|
+
return;
|
|
445550
|
+
}
|
|
445551
|
+
const seconds = Number(value);
|
|
445552
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
445553
|
+
return seconds * 1000;
|
|
445554
|
+
}
|
|
445555
|
+
const dateMs = Date.parse(value);
|
|
445556
|
+
if (Number.isFinite(dateMs)) {
|
|
445557
|
+
return Math.max(0, dateMs - Date.now());
|
|
445558
|
+
}
|
|
445559
|
+
return;
|
|
445560
|
+
}
|
|
445561
|
+
async function registerWithCloud(opts, fetchImpl = fetch) {
|
|
445562
|
+
const registerUrl = `${opts.serverUrl}/v1/environments/register`;
|
|
445563
|
+
const response = await fetchImpl(registerUrl, {
|
|
445564
|
+
method: "POST",
|
|
445565
|
+
headers: {
|
|
445566
|
+
"Content-Type": "application/json",
|
|
445567
|
+
Authorization: `Bearer ${opts.apiKey}`,
|
|
445568
|
+
"X-Letta-Source": "letta-code"
|
|
445569
|
+
},
|
|
445570
|
+
body: JSON.stringify({
|
|
445571
|
+
deviceId: opts.deviceId,
|
|
445572
|
+
...opts.listenerInstanceId ? { listenerInstanceId: opts.listenerInstanceId } : {},
|
|
445573
|
+
connectionName: opts.connectionName,
|
|
445574
|
+
metadata: {
|
|
445575
|
+
lettaCodeVersion: getVersion(),
|
|
445576
|
+
os: process.platform,
|
|
445577
|
+
nodeVersion: process.version,
|
|
445578
|
+
environmentMessageProtocol: "v2-input",
|
|
445579
|
+
supported_commands: SUPPORTED_REMOTE_COMMANDS,
|
|
445580
|
+
self_update: getSelfUpdateStatus()
|
|
445581
|
+
}
|
|
445582
|
+
})
|
|
445583
|
+
}).catch((fetchError) => {
|
|
445584
|
+
const msg = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
445585
|
+
throw new RegistrationError(`Network error: ${msg}`, 0);
|
|
445586
|
+
});
|
|
445587
|
+
if (!response.ok) {
|
|
445588
|
+
let detail = `HTTP ${response.status}`;
|
|
445589
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
445590
|
+
const text2 = await response.text().catch(() => "");
|
|
445591
|
+
if (text2) {
|
|
445592
|
+
try {
|
|
445593
|
+
const parsed = JSON.parse(text2);
|
|
445594
|
+
if (parsed.message) {
|
|
445595
|
+
detail = parsed.message;
|
|
445596
|
+
} else if (parsed.error) {
|
|
445597
|
+
detail = `HTTP ${response.status}: ${parsed.error}`;
|
|
445598
|
+
if (parsed.errorCode) {
|
|
445599
|
+
detail += ` (${parsed.errorCode})`;
|
|
445600
|
+
}
|
|
445601
|
+
} else {
|
|
445602
|
+
detail += `: ${text2.slice(0, 200)}`;
|
|
445603
|
+
}
|
|
445604
|
+
} catch {
|
|
445605
|
+
detail += `: ${text2.slice(0, 200)}`;
|
|
445606
|
+
}
|
|
445607
|
+
}
|
|
445608
|
+
throw new RegistrationError(detail, response.status, retryAfterMs);
|
|
445609
|
+
}
|
|
445610
|
+
let body3;
|
|
445611
|
+
try {
|
|
445612
|
+
body3 = await response.json();
|
|
445613
|
+
} catch {
|
|
445614
|
+
throw new RegistrationError("Server returned non-JSON response — is the server running?", response.status);
|
|
445615
|
+
}
|
|
445616
|
+
const result = body3;
|
|
445617
|
+
if (typeof result.connectionId !== "string" || typeof result.wsUrl !== "string") {
|
|
445618
|
+
throw new RegistrationError("Server returned unexpected response shape (missing connectionId or wsUrl)", response.status);
|
|
445619
|
+
}
|
|
445620
|
+
return {
|
|
445621
|
+
connectionId: result.connectionId,
|
|
445622
|
+
wsUrl: result.wsUrl,
|
|
445623
|
+
supportsSplitStatusChannels: result.supportsSplitStatusChannels === true
|
|
445624
|
+
};
|
|
445625
|
+
}
|
|
445626
|
+
async function registerWithCloudRetry(opts, callbacks) {
|
|
445627
|
+
const startTime = Date.now();
|
|
445628
|
+
const maxDurationMs = callbacks?.maxDurationMs ?? REGISTER_MAX_DURATION_MS;
|
|
445629
|
+
const sleep9 = callbacks?.sleep ?? ((delayMs) => new Promise((resolve31) => setTimeout(resolve31, delayMs)));
|
|
445630
|
+
let attempt = 0;
|
|
445631
|
+
for (;; ) {
|
|
445632
|
+
try {
|
|
445633
|
+
return await registerWithCloud(opts, callbacks?.fetchImpl);
|
|
445634
|
+
} catch (error54) {
|
|
445635
|
+
const elapsed = Date.now() - startTime;
|
|
445636
|
+
if (!isTransientRegistrationError(error54) || elapsed >= maxDurationMs) {
|
|
445637
|
+
throw error54;
|
|
445638
|
+
}
|
|
445639
|
+
attempt++;
|
|
445640
|
+
const backoffDelay = Math.min(REGISTER_INITIAL_DELAY_MS * 2 ** (attempt - 1), REGISTER_MAX_DELAY_MS);
|
|
445641
|
+
const delay2 = error54 instanceof RegistrationError && error54.retryAfterMs !== undefined ? Math.max(error54.retryAfterMs, backoffDelay) : backoffDelay;
|
|
445642
|
+
const jitterWindow = Math.min(REGISTER_MAX_JITTER_MS, Math.floor(delay2 * REGISTER_JITTER_RATIO));
|
|
445643
|
+
const jitter = jitterWindow > 0 ? Math.floor((callbacks?.random ?? Math.random)() * jitterWindow) : 0;
|
|
445644
|
+
const retryDelay = delay2 + jitter;
|
|
445645
|
+
if (error54 instanceof Error) {
|
|
445646
|
+
callbacks?.onRetry?.(attempt, retryDelay, error54);
|
|
445647
|
+
}
|
|
445648
|
+
await sleep9(retryDelay);
|
|
445649
|
+
}
|
|
445650
|
+
}
|
|
445651
|
+
}
|
|
445652
|
+
var RegistrationError, REGISTER_INITIAL_DELAY_MS = 1000, REGISTER_MAX_DELAY_MS = 30000, REGISTER_MAX_DURATION_MS, REGISTER_MAX_JITTER_MS = 1000, REGISTER_JITTER_RATIO = 0.25;
|
|
445653
|
+
var init_listen_register = __esm(() => {
|
|
445654
|
+
init_auto_update();
|
|
445655
|
+
init_version();
|
|
445656
|
+
init_listener_constants();
|
|
445657
|
+
RegistrationError = class RegistrationError extends Error {
|
|
445658
|
+
statusCode;
|
|
445659
|
+
retryAfterMs;
|
|
445660
|
+
constructor(message, statusCode2, retryAfterMs) {
|
|
445661
|
+
super(message);
|
|
445662
|
+
this.name = "RegistrationError";
|
|
445663
|
+
this.statusCode = statusCode2;
|
|
445664
|
+
this.retryAfterMs = retryAfterMs;
|
|
445665
|
+
}
|
|
445666
|
+
};
|
|
445667
|
+
REGISTER_MAX_DURATION_MS = 2 * 60 * 1000;
|
|
445668
|
+
});
|
|
445669
|
+
|
|
445670
|
+
// src/websocket/listener/auth.ts
|
|
445671
|
+
function getListenerOAuthDeps() {
|
|
445672
|
+
return listenerOAuthDepsOverride ?? defaultListenerOAuthDeps;
|
|
445673
|
+
}
|
|
445674
|
+
function errorMessage(error54) {
|
|
445675
|
+
return error54 instanceof Error ? error54.message : String(error54);
|
|
445676
|
+
}
|
|
445677
|
+
function getListenerServerUrl(settings3) {
|
|
445678
|
+
return process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || getListenerOAuthDeps().LETTA_CLOUD_API_URL;
|
|
445679
|
+
}
|
|
445680
|
+
function normalizeListenerBaseUrl(url2) {
|
|
445681
|
+
return url2.trim().replace(/\/+$/, "");
|
|
445682
|
+
}
|
|
445683
|
+
function isCloudListenerServerUrl(serverUrl) {
|
|
445684
|
+
return normalizeListenerBaseUrl(serverUrl) === normalizeListenerBaseUrl(getListenerOAuthDeps().LETTA_CLOUD_API_URL);
|
|
445685
|
+
}
|
|
445686
|
+
function shouldRefreshListenerAccessToken(settings3, apiKey) {
|
|
445687
|
+
if (!settings3.refreshToken) {
|
|
445688
|
+
return false;
|
|
445689
|
+
}
|
|
445690
|
+
if (!apiKey) {
|
|
445691
|
+
return true;
|
|
445692
|
+
}
|
|
445693
|
+
return settings3.tokenExpiresAt !== undefined && Date.now() >= settings3.tokenExpiresAt - LISTENER_TOKEN_REFRESH_WINDOW_MS;
|
|
445694
|
+
}
|
|
445695
|
+
function isAccessTokenStillValid(settings3, apiKey) {
|
|
445696
|
+
return Boolean(apiKey && (settings3.tokenExpiresAt === undefined || Date.now() < settings3.tokenExpiresAt));
|
|
445697
|
+
}
|
|
445698
|
+
async function refreshListenerAccessToken(settings3, deviceId, connectionName) {
|
|
445699
|
+
if (!settings3.refreshToken) {
|
|
445700
|
+
throw new MissingListenerApiKeyError;
|
|
445701
|
+
}
|
|
445702
|
+
const now = Date.now();
|
|
445703
|
+
console.log("Access token expired, refreshing...");
|
|
445704
|
+
const tokens = await refreshAccessTokenSingleFlight(settings3.refreshToken, deviceId, connectionName, getListenerOAuthDeps().refreshAccessToken);
|
|
445705
|
+
settingsManager.updateSettings({
|
|
445706
|
+
env: { LETTA_API_KEY: tokens.access_token },
|
|
445707
|
+
refreshToken: tokens.refresh_token ?? settings3.refreshToken,
|
|
445708
|
+
tokenExpiresAt: now + tokens.expires_in * 1000
|
|
445709
|
+
});
|
|
445710
|
+
await settingsManager.flush();
|
|
445711
|
+
console.log("Token refreshed successfully.");
|
|
445712
|
+
return tokens.access_token;
|
|
445713
|
+
}
|
|
445714
|
+
async function runListenerOAuthLogin(deviceId, connectionName) {
|
|
445715
|
+
const oauthDeps = getListenerOAuthDeps();
|
|
445716
|
+
console.log(`No API key found. Starting OAuth login...
|
|
445717
|
+
`);
|
|
445718
|
+
const deviceData = await oauthDeps.requestDeviceCode();
|
|
445719
|
+
console.log(`To authenticate, visit: ${deviceData.verification_uri_complete}`);
|
|
445720
|
+
console.log(`Your code: ${deviceData.user_code}
|
|
445721
|
+
`);
|
|
445722
|
+
console.log(`Waiting for authorization...
|
|
445723
|
+
`);
|
|
445724
|
+
const tokens = await oauthDeps.pollForToken(deviceData.device_code, deviceData.interval, deviceData.expires_in, deviceId, connectionName);
|
|
445725
|
+
const now = Date.now();
|
|
445726
|
+
settingsManager.updateSettings({
|
|
445727
|
+
env: { LETTA_API_KEY: tokens.access_token },
|
|
445728
|
+
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {},
|
|
445729
|
+
tokenExpiresAt: now + tokens.expires_in * 1000
|
|
445730
|
+
});
|
|
445731
|
+
await settingsManager.flush();
|
|
445732
|
+
console.log(`Authenticated successfully.
|
|
445733
|
+
`);
|
|
445734
|
+
return tokens.access_token;
|
|
445735
|
+
}
|
|
445736
|
+
async function resolveListenerAuth(deviceId, connectionName, options3) {
|
|
445737
|
+
const allowInteractiveOAuth = options3.allowInteractiveOAuth ?? true;
|
|
445738
|
+
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
445739
|
+
const serverUrl = getListenerServerUrl(settings3);
|
|
445740
|
+
const envApiKey = process.env.LETTA_API_KEY;
|
|
445741
|
+
if (envApiKey) {
|
|
445742
|
+
return { serverUrl, apiKey: envApiKey };
|
|
445743
|
+
}
|
|
445744
|
+
let apiKey = settings3.env?.LETTA_API_KEY;
|
|
445745
|
+
if (!isCloudListenerServerUrl(serverUrl)) {
|
|
445746
|
+
if (!apiKey) {
|
|
445747
|
+
throw new MissingListenerApiKeyError;
|
|
445748
|
+
}
|
|
445749
|
+
return { serverUrl, apiKey };
|
|
445750
|
+
}
|
|
445751
|
+
if (shouldRefreshListenerAccessToken(settings3, apiKey)) {
|
|
445752
|
+
try {
|
|
445753
|
+
apiKey = await refreshListenerAccessToken(settings3, deviceId, connectionName);
|
|
445754
|
+
} catch (refreshError) {
|
|
445755
|
+
const retryable = !(refreshError instanceof OAuthRefreshError) || refreshError.retryable;
|
|
445756
|
+
if (retryable && isAccessTokenStillValid(settings3, apiKey)) {
|
|
445757
|
+
console.warn(`Token refresh failed; using the current access token: ${errorMessage(refreshError)}`);
|
|
445758
|
+
return { serverUrl, apiKey };
|
|
445759
|
+
}
|
|
445760
|
+
if (retryable) {
|
|
445761
|
+
throw new ListenerAuthRetryableError(refreshError);
|
|
445762
|
+
}
|
|
445763
|
+
if (!allowInteractiveOAuth) {
|
|
445764
|
+
throw new ListenerReauthenticationRequiredError(refreshError);
|
|
445765
|
+
}
|
|
445766
|
+
console.warn(`Token refresh failed: ${errorMessage(refreshError)}`);
|
|
445767
|
+
apiKey = undefined;
|
|
445768
|
+
}
|
|
445769
|
+
}
|
|
445770
|
+
if (!apiKey) {
|
|
445771
|
+
if (!allowInteractiveOAuth) {
|
|
445772
|
+
throw new ListenerReauthenticationRequiredError;
|
|
445773
|
+
}
|
|
445774
|
+
apiKey = await runListenerOAuthLogin(deviceId, connectionName);
|
|
445775
|
+
}
|
|
445776
|
+
return { serverUrl, apiKey };
|
|
445777
|
+
}
|
|
445778
|
+
async function resolveListenerRegistrationOptions(deviceId, connectionName, options3 = {}) {
|
|
445779
|
+
const auth = await resolveListenerAuth(deviceId, connectionName, options3);
|
|
445780
|
+
return {
|
|
445781
|
+
...auth,
|
|
445782
|
+
deviceId,
|
|
445783
|
+
connectionName,
|
|
445784
|
+
listenerInstanceId: deriveListenerInstanceId(options3.surface ?? "server", connectionName)
|
|
445785
|
+
};
|
|
445786
|
+
}
|
|
445787
|
+
async function resolveListenerReconnectAuth(options3) {
|
|
445788
|
+
try {
|
|
445789
|
+
const auth = await resolveListenerAuth(options3.deviceId, options3.connectionName, { allowInteractiveOAuth: false });
|
|
445790
|
+
return { kind: "ready", apiKey: auth.apiKey };
|
|
445791
|
+
} catch (error54) {
|
|
445792
|
+
if (error54 instanceof ListenerAuthRetryableError) {
|
|
445793
|
+
return { kind: "retry" };
|
|
445794
|
+
}
|
|
445795
|
+
throw error54;
|
|
445796
|
+
}
|
|
445797
|
+
}
|
|
445798
|
+
var LISTENER_TOKEN_REFRESH_WINDOW_MS, defaultListenerOAuthDeps, listenerOAuthDepsOverride = null, MissingListenerApiKeyError, ListenerAuthRetryableError, ListenerReauthenticationRequiredError;
|
|
445799
|
+
var init_auth = __esm(() => {
|
|
445800
|
+
init_oauth();
|
|
445801
|
+
init_oauth_refresh();
|
|
445802
|
+
init_settings_manager();
|
|
445803
|
+
init_listen_register();
|
|
445804
|
+
LISTENER_TOKEN_REFRESH_WINDOW_MS = 5 * 60 * 1000;
|
|
445805
|
+
defaultListenerOAuthDeps = {
|
|
445806
|
+
LETTA_CLOUD_API_URL,
|
|
445807
|
+
pollForToken,
|
|
445808
|
+
refreshAccessToken,
|
|
445809
|
+
requestDeviceCode
|
|
445810
|
+
};
|
|
445811
|
+
MissingListenerApiKeyError = class MissingListenerApiKeyError extends Error {
|
|
445812
|
+
constructor() {
|
|
445813
|
+
super("LETTA_API_KEY not found");
|
|
445814
|
+
this.name = "MissingListenerApiKeyError";
|
|
445815
|
+
}
|
|
445816
|
+
};
|
|
445817
|
+
ListenerAuthRetryableError = class ListenerAuthRetryableError extends Error {
|
|
445818
|
+
constructor(refreshError) {
|
|
445819
|
+
super(`Could not refresh listener credentials: ${errorMessage(refreshError)}`);
|
|
445820
|
+
this.name = "ListenerAuthRetryableError";
|
|
445821
|
+
}
|
|
445822
|
+
};
|
|
445823
|
+
ListenerReauthenticationRequiredError = class ListenerReauthenticationRequiredError extends Error {
|
|
445824
|
+
constructor(refreshError) {
|
|
445825
|
+
const detail = refreshError ? `: ${errorMessage(refreshError)}` : "";
|
|
445826
|
+
super(`Saved Letta API credentials require reauthentication${detail}. Run letta to sign in again, or set LETTA_API_KEY.`);
|
|
445827
|
+
this.name = "ListenerReauthenticationRequiredError";
|
|
445828
|
+
}
|
|
445829
|
+
};
|
|
445830
|
+
});
|
|
445831
|
+
|
|
445424
445832
|
// src/agent/acting-user.ts
|
|
445425
445833
|
function actingUserRequestOptions(actingUserId) {
|
|
445426
445834
|
if (!actingUserId) {
|
|
@@ -449685,9 +450093,9 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
449685
450093
|
}
|
|
449686
450094
|
}
|
|
449687
450095
|
} catch (e2) {
|
|
449688
|
-
const
|
|
450096
|
+
const errorMessage2 = e2 instanceof Error ? e2.message : String(e2);
|
|
449689
450097
|
const sdkDiagnostic = consumeLastSDKDiagnostic();
|
|
449690
|
-
const errorMessageWithDiagnostic = sdkDiagnostic ? `${
|
|
450098
|
+
const errorMessageWithDiagnostic = sdkDiagnostic ? `${errorMessage2} [${sdkDiagnostic}]` : errorMessage2;
|
|
449691
450099
|
debugWarn("drainStream", "Stream error caught: %s last_chunk=%s stream=%s", errorMessageWithDiagnostic, lastChunkDebugSummary, summarizeStreamForDebug(stream12));
|
|
449692
450100
|
if (e2 instanceof Error && e2.stack) {
|
|
449693
450101
|
debugWarn("drainStream", "Stream error stack: %s", e2.stack);
|
|
@@ -456706,7 +457114,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456706
457114
|
});
|
|
456707
457115
|
break;
|
|
456708
457116
|
}
|
|
456709
|
-
const
|
|
457117
|
+
const errorMessage2 = errorDetail || `Unexpected stop reason: ${stopReason}`;
|
|
456710
457118
|
const terminalRunId = runId || runtime.activeRunId || runErrorInfo2?.run_id;
|
|
456711
457119
|
const transition = finishTurn({
|
|
456712
457120
|
stopReason: effectiveStopReason,
|
|
@@ -456717,7 +457125,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456717
457125
|
break;
|
|
456718
457126
|
}
|
|
456719
457127
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
456720
|
-
message:
|
|
457128
|
+
message: errorMessage2,
|
|
456721
457129
|
stopReason: effectiveStopReason,
|
|
456722
457130
|
isTerminal: true,
|
|
456723
457131
|
runId: terminalRunId,
|
|
@@ -456727,7 +457135,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456727
457135
|
cancelRequested: turnAbortSignal.aborted,
|
|
456728
457136
|
abortSignal: turnAbortSignal
|
|
456729
457137
|
});
|
|
456730
|
-
runtime.lastTerminalLoopErrorMessage = formattedError ??
|
|
457138
|
+
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
456731
457139
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
456732
457140
|
break;
|
|
456733
457141
|
}
|
|
@@ -456849,7 +457257,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456849
457257
|
});
|
|
456850
457258
|
return;
|
|
456851
457259
|
}
|
|
456852
|
-
const
|
|
457260
|
+
const errorMessage2 = error54 instanceof Error ? error54.message : String(error54);
|
|
456853
457261
|
const terminalRunId = runtime.activeRunId;
|
|
456854
457262
|
const transition = finishTurn({
|
|
456855
457263
|
stopReason: "error",
|
|
@@ -456860,7 +457268,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456860
457268
|
return;
|
|
456861
457269
|
}
|
|
456862
457270
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
456863
|
-
message:
|
|
457271
|
+
message: errorMessage2,
|
|
456864
457272
|
stopReason: "error",
|
|
456865
457273
|
isTerminal: true,
|
|
456866
457274
|
runId: terminalRunId,
|
|
@@ -456870,7 +457278,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456870
457278
|
cancelRequested: turnAbortSignal.aborted,
|
|
456871
457279
|
abortSignal: turnAbortSignal
|
|
456872
457280
|
});
|
|
456873
|
-
runtime.lastTerminalLoopErrorMessage = formattedError ??
|
|
457281
|
+
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
456874
457282
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
456875
457283
|
if (isDebugEnabled()) {
|
|
456876
457284
|
console.error("[Listen] Error handling message:", error54);
|
|
@@ -458343,11 +458751,11 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
|
|
|
458343
458751
|
error: error54,
|
|
458344
458752
|
context: "listener_command_execution"
|
|
458345
458753
|
});
|
|
458346
|
-
const
|
|
458754
|
+
const errorMessage2 = error54 instanceof Error ? error54.message : String(error54);
|
|
458347
458755
|
emitSlashCommandEnd(socket, conversationRuntime, scope, {
|
|
458348
458756
|
command_id: command.command_id,
|
|
458349
458757
|
input,
|
|
458350
|
-
output: `Failed: ${
|
|
458758
|
+
output: `Failed: ${errorMessage2}`,
|
|
458351
458759
|
success: false
|
|
458352
458760
|
});
|
|
458353
458761
|
}
|
|
@@ -465803,11 +466211,13 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465803
466211
|
if (attempt === 0) {
|
|
465804
466212
|
await loadTools();
|
|
465805
466213
|
}
|
|
465806
|
-
const
|
|
465807
|
-
|
|
465808
|
-
|
|
465809
|
-
|
|
466214
|
+
const auth = await resolveListenerReconnectAuth(opts);
|
|
466215
|
+
if (auth.kind === "retry")
|
|
466216
|
+
return connectWithRetry(runtime, opts, attempt + 1, startTime);
|
|
466217
|
+
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
466218
|
+
return;
|
|
465810
466219
|
}
|
|
466220
|
+
const apiKey = auth.apiKey;
|
|
465811
466221
|
const url2 = new URL(opts.wsUrl);
|
|
465812
466222
|
url2.searchParams.set("deviceId", opts.deviceId);
|
|
465813
466223
|
url2.searchParams.set("connectionName", opts.connectionName);
|
|
@@ -465994,6 +466404,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
465994
466404
|
init_debug();
|
|
465995
466405
|
init_message_queue_bridge();
|
|
465996
466406
|
init_terminal_handler();
|
|
466407
|
+
init_auth();
|
|
465997
466408
|
init_channel_turn_session();
|
|
465998
466409
|
init_constants3();
|
|
465999
466410
|
init_cwd();
|
|
@@ -468857,141 +469268,6 @@ var init_startup = __esm(() => {
|
|
|
468857
469268
|
init_mode();
|
|
468858
469269
|
});
|
|
468859
469270
|
|
|
468860
|
-
// src/websocket/listen-register.ts
|
|
468861
|
-
import { createHash as createHash7 } from "node:crypto";
|
|
468862
|
-
function deriveListenerInstanceId(surface, connectionName) {
|
|
468863
|
-
const nameHash = createHash7("sha256").update(connectionName).digest("hex").slice(0, 16);
|
|
468864
|
-
return `${surface}-${nameHash}`;
|
|
468865
|
-
}
|
|
468866
|
-
function isTransientRegistrationError(error54) {
|
|
468867
|
-
if (error54 instanceof RegistrationError) {
|
|
468868
|
-
return error54.statusCode === 0 || error54.statusCode === 429 || error54.statusCode >= 500;
|
|
468869
|
-
}
|
|
468870
|
-
return true;
|
|
468871
|
-
}
|
|
468872
|
-
function parseRetryAfterMs(value) {
|
|
468873
|
-
if (!value) {
|
|
468874
|
-
return;
|
|
468875
|
-
}
|
|
468876
|
-
const seconds = Number(value);
|
|
468877
|
-
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
468878
|
-
return seconds * 1000;
|
|
468879
|
-
}
|
|
468880
|
-
const dateMs = Date.parse(value);
|
|
468881
|
-
if (Number.isFinite(dateMs)) {
|
|
468882
|
-
return Math.max(0, dateMs - Date.now());
|
|
468883
|
-
}
|
|
468884
|
-
return;
|
|
468885
|
-
}
|
|
468886
|
-
async function registerWithCloud(opts, fetchImpl = fetch) {
|
|
468887
|
-
const registerUrl = `${opts.serverUrl}/v1/environments/register`;
|
|
468888
|
-
const response = await fetchImpl(registerUrl, {
|
|
468889
|
-
method: "POST",
|
|
468890
|
-
headers: {
|
|
468891
|
-
"Content-Type": "application/json",
|
|
468892
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
468893
|
-
"X-Letta-Source": "letta-code"
|
|
468894
|
-
},
|
|
468895
|
-
body: JSON.stringify({
|
|
468896
|
-
deviceId: opts.deviceId,
|
|
468897
|
-
...opts.listenerInstanceId ? { listenerInstanceId: opts.listenerInstanceId } : {},
|
|
468898
|
-
connectionName: opts.connectionName,
|
|
468899
|
-
metadata: {
|
|
468900
|
-
lettaCodeVersion: getVersion(),
|
|
468901
|
-
os: process.platform,
|
|
468902
|
-
nodeVersion: process.version,
|
|
468903
|
-
environmentMessageProtocol: "v2-input",
|
|
468904
|
-
supported_commands: SUPPORTED_REMOTE_COMMANDS,
|
|
468905
|
-
self_update: getSelfUpdateStatus()
|
|
468906
|
-
}
|
|
468907
|
-
})
|
|
468908
|
-
}).catch((fetchError) => {
|
|
468909
|
-
const msg = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
468910
|
-
throw new RegistrationError(`Network error: ${msg}`, 0);
|
|
468911
|
-
});
|
|
468912
|
-
if (!response.ok) {
|
|
468913
|
-
let detail = `HTTP ${response.status}`;
|
|
468914
|
-
const retryAfterMs2 = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
468915
|
-
const text2 = await response.text().catch(() => "");
|
|
468916
|
-
if (text2) {
|
|
468917
|
-
try {
|
|
468918
|
-
const parsed = JSON.parse(text2);
|
|
468919
|
-
if (parsed.message) {
|
|
468920
|
-
detail = parsed.message;
|
|
468921
|
-
} else if (parsed.error) {
|
|
468922
|
-
detail = `HTTP ${response.status}: ${parsed.error}`;
|
|
468923
|
-
if (parsed.errorCode) {
|
|
468924
|
-
detail += ` (${parsed.errorCode})`;
|
|
468925
|
-
}
|
|
468926
|
-
} else {
|
|
468927
|
-
detail += `: ${text2.slice(0, 200)}`;
|
|
468928
|
-
}
|
|
468929
|
-
} catch {
|
|
468930
|
-
detail += `: ${text2.slice(0, 200)}`;
|
|
468931
|
-
}
|
|
468932
|
-
}
|
|
468933
|
-
throw new RegistrationError(detail, response.status, retryAfterMs2);
|
|
468934
|
-
}
|
|
468935
|
-
let body3;
|
|
468936
|
-
try {
|
|
468937
|
-
body3 = await response.json();
|
|
468938
|
-
} catch {
|
|
468939
|
-
throw new RegistrationError("Server returned non-JSON response — is the server running?", response.status);
|
|
468940
|
-
}
|
|
468941
|
-
const result = body3;
|
|
468942
|
-
if (typeof result.connectionId !== "string" || typeof result.wsUrl !== "string") {
|
|
468943
|
-
throw new RegistrationError("Server returned unexpected response shape (missing connectionId or wsUrl)", response.status);
|
|
468944
|
-
}
|
|
468945
|
-
return {
|
|
468946
|
-
connectionId: result.connectionId,
|
|
468947
|
-
wsUrl: result.wsUrl,
|
|
468948
|
-
supportsSplitStatusChannels: result.supportsSplitStatusChannels === true
|
|
468949
|
-
};
|
|
468950
|
-
}
|
|
468951
|
-
async function registerWithCloudRetry(opts, callbacks) {
|
|
468952
|
-
const startTime = Date.now();
|
|
468953
|
-
const maxDurationMs = callbacks?.maxDurationMs ?? REGISTER_MAX_DURATION_MS;
|
|
468954
|
-
const sleep9 = callbacks?.sleep ?? ((delayMs) => new Promise((resolve31) => setTimeout(resolve31, delayMs)));
|
|
468955
|
-
let attempt = 0;
|
|
468956
|
-
for (;; ) {
|
|
468957
|
-
try {
|
|
468958
|
-
return await registerWithCloud(opts, callbacks?.fetchImpl);
|
|
468959
|
-
} catch (error54) {
|
|
468960
|
-
const elapsed = Date.now() - startTime;
|
|
468961
|
-
if (!isTransientRegistrationError(error54) || elapsed >= maxDurationMs) {
|
|
468962
|
-
throw error54;
|
|
468963
|
-
}
|
|
468964
|
-
attempt++;
|
|
468965
|
-
const backoffDelay = Math.min(REGISTER_INITIAL_DELAY_MS * 2 ** (attempt - 1), REGISTER_MAX_DELAY_MS);
|
|
468966
|
-
const delay2 = error54 instanceof RegistrationError && error54.retryAfterMs !== undefined ? Math.max(error54.retryAfterMs, backoffDelay) : backoffDelay;
|
|
468967
|
-
const jitterWindow = Math.min(REGISTER_MAX_JITTER_MS, Math.floor(delay2 * REGISTER_JITTER_RATIO));
|
|
468968
|
-
const jitter = jitterWindow > 0 ? Math.floor((callbacks?.random ?? Math.random)() * jitterWindow) : 0;
|
|
468969
|
-
const retryDelay = delay2 + jitter;
|
|
468970
|
-
if (error54 instanceof Error) {
|
|
468971
|
-
callbacks?.onRetry?.(attempt, retryDelay, error54);
|
|
468972
|
-
}
|
|
468973
|
-
await sleep9(retryDelay);
|
|
468974
|
-
}
|
|
468975
|
-
}
|
|
468976
|
-
}
|
|
468977
|
-
var RegistrationError, REGISTER_INITIAL_DELAY_MS = 1000, REGISTER_MAX_DELAY_MS = 30000, REGISTER_MAX_DURATION_MS, REGISTER_MAX_JITTER_MS = 1000, REGISTER_JITTER_RATIO = 0.25;
|
|
468978
|
-
var init_listen_register = __esm(() => {
|
|
468979
|
-
init_auto_update();
|
|
468980
|
-
init_version();
|
|
468981
|
-
init_listener_constants();
|
|
468982
|
-
RegistrationError = class RegistrationError extends Error {
|
|
468983
|
-
statusCode;
|
|
468984
|
-
retryAfterMs;
|
|
468985
|
-
constructor(message, statusCode2, retryAfterMs2) {
|
|
468986
|
-
super(message);
|
|
468987
|
-
this.name = "RegistrationError";
|
|
468988
|
-
this.statusCode = statusCode2;
|
|
468989
|
-
this.retryAfterMs = retryAfterMs2;
|
|
468990
|
-
}
|
|
468991
|
-
};
|
|
468992
|
-
REGISTER_MAX_DURATION_MS = 2 * 60 * 1000;
|
|
468993
|
-
});
|
|
468994
|
-
|
|
468995
469271
|
// src/websocket/listener/client.ts
|
|
468996
469272
|
function asListenerRuntimeForTests(runtime) {
|
|
468997
469273
|
return "listener" in runtime ? runtime.listener : runtime;
|
|
@@ -476245,7 +476521,7 @@ ${loadedContents.join(`
|
|
|
476245
476521
|
markIncompleteToolsAsCancelled(buffers, true, "stream_error");
|
|
476246
476522
|
const errorLines = toLines(buffers).filter((line) => line.kind === "error");
|
|
476247
476523
|
const errorMessages2 = errorLines.map((line) => ("text" in line) ? line.text : "").filter(Boolean);
|
|
476248
|
-
let
|
|
476524
|
+
let errorMessage2 = errorMessages2.length > 0 ? errorMessages2.join("; ") : `Unexpected stop reason: ${stopReason}`;
|
|
476249
476525
|
if (lastRunId && errorMessages2.length === 0) {
|
|
476250
476526
|
try {
|
|
476251
476527
|
const run = await getBackend().retrieveRun(lastRunId);
|
|
@@ -476257,18 +476533,18 @@ ${loadedContents.join(`
|
|
|
476257
476533
|
run_id: lastRunId
|
|
476258
476534
|
}
|
|
476259
476535
|
};
|
|
476260
|
-
|
|
476536
|
+
errorMessage2 = formatErrorDetails2(errorObject, agent2.id);
|
|
476261
476537
|
}
|
|
476262
476538
|
} catch (_e) {
|
|
476263
|
-
|
|
476539
|
+
errorMessage2 = `${errorMessage2}
|
|
476264
476540
|
(Unable to fetch additional error details from server)`;
|
|
476265
476541
|
}
|
|
476266
476542
|
}
|
|
476267
|
-
trackHeadlessBoundaryError("headless_turn_failed",
|
|
476543
|
+
trackHeadlessBoundaryError("headless_turn_failed", errorMessage2, "headless_turn_execution");
|
|
476268
476544
|
if (outputFormat === "stream-json") {
|
|
476269
476545
|
const errorMsg = {
|
|
476270
476546
|
type: "error",
|
|
476271
|
-
message:
|
|
476547
|
+
message: errorMessage2,
|
|
476272
476548
|
stop_reason: stopReason,
|
|
476273
476549
|
run_id: lastRunId ?? undefined,
|
|
476274
476550
|
session_id: sessionId,
|
|
@@ -476276,7 +476552,7 @@ ${loadedContents.join(`
|
|
|
476276
476552
|
};
|
|
476277
476553
|
await writeWireMessageAsync(errorMsg);
|
|
476278
476554
|
} else {
|
|
476279
|
-
console.error(`Error: ${
|
|
476555
|
+
console.error(`Error: ${errorMessage2}`);
|
|
476280
476556
|
}
|
|
476281
476557
|
await exitHeadless(1, "headless_stop_reason_error");
|
|
476282
476558
|
}
|
|
@@ -489773,7 +490049,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
489773
490049
|
const isLocalAgent = agentId ? isLocalAgentId2(agentId) : false;
|
|
489774
490050
|
const showCloudLinks = Boolean(isCloudUser && agentId && !isLocalAgent);
|
|
489775
490051
|
const adeConversationUrl = showCloudLinks && agentId && agentId !== "loading" ? buildChatUrl(agentId, { conversationId }) : "";
|
|
489776
|
-
const usageUrl =
|
|
490052
|
+
const usageUrl = buildChatWebUrl("/preferences/usage");
|
|
489777
490053
|
const showBottomBar = agentId && agentId !== "loading";
|
|
489778
490054
|
const reasoningLabel = shouldHideReasoningForModelDisplay(currentModel) ? null : formatReasoningLabel(currentReasoningEffort);
|
|
489779
490055
|
const modelLine = currentModel ? `${currentModel}${reasoningLabel ? ` (${reasoningLabel})` : ""}` : null;
|
|
@@ -493294,7 +493570,7 @@ function buildInstallPrBody(workflowPath) {
|
|
|
493294
493570
|
"",
|
|
493295
493571
|
"You can also specify a particular agent: `@letta-code [--agent agent-xxx]`",
|
|
493296
493572
|
"",
|
|
493297
|
-
"
|
|
493573
|
+
"Chat with your agent at [chat.letta.com](https://chat.letta.com).",
|
|
493298
493574
|
"",
|
|
493299
493575
|
"### Important Notes",
|
|
493300
493576
|
"",
|
|
@@ -493615,7 +493891,7 @@ var init_InstallGithubAppFlow = __esm(async () => {
|
|
|
493615
493891
|
const solidLine = SOLID_LINE12.repeat(Math.max(terminalWidth, 10));
|
|
493616
493892
|
const [step, setStep] = import_react87.useState("checking");
|
|
493617
493893
|
const [status, setStatus] = import_react87.useState("Checking GitHub CLI prerequisites...");
|
|
493618
|
-
const [
|
|
493894
|
+
const [errorMessage2, setErrorMessage] = import_react87.useState("");
|
|
493619
493895
|
const [currentRepo, setCurrentRepo] = import_react87.useState(null);
|
|
493620
493896
|
const [repoChoiceIndex, setRepoChoiceIndex] = import_react87.useState(0);
|
|
493621
493897
|
const [repoInput, setRepoInput] = import_react87.useState("");
|
|
@@ -494183,14 +494459,14 @@ var init_InstallGithubAppFlow = __esm(async () => {
|
|
|
494183
494459
|
color: "red",
|
|
494184
494460
|
children: [
|
|
494185
494461
|
"Error: ",
|
|
494186
|
-
|
|
494462
|
+
errorMessage2.split(`
|
|
494187
494463
|
`)[0] || "Unknown error"
|
|
494188
494464
|
]
|
|
494189
494465
|
}, undefined, true, undefined, this),
|
|
494190
494466
|
/* @__PURE__ */ jsx_dev_runtime61.jsxDEV(Box_default, {
|
|
494191
494467
|
height: 1
|
|
494192
494468
|
}, undefined, false, undefined, this),
|
|
494193
|
-
|
|
494469
|
+
errorMessage2.split(`
|
|
494194
494470
|
`).slice(1).filter((line) => line.trim().length > 0).map((line, idx) => /* @__PURE__ */ jsx_dev_runtime61.jsxDEV(Text2, {
|
|
494195
494471
|
dimColor: true,
|
|
494196
494472
|
children: line
|
|
@@ -496859,13 +497135,16 @@ html.dark .warning-badge { background: hsl(42, 30%, 18%); color: hsl(42, 80%, 70
|
|
|
496859
497135
|
var agentIdEl = document.getElementById('agent-id');
|
|
496860
497136
|
agentIdEl.textContent = agentId;
|
|
496861
497137
|
if (agentId) {
|
|
496862
|
-
var
|
|
496863
|
-
|
|
496864
|
-
|
|
497138
|
+
var chatBase;
|
|
497139
|
+
var normalizedServerUrl = serverUrl.replace(/\\/+$/, '');
|
|
497140
|
+
if (normalizedServerUrl === 'https://api.letta.com' || normalizedServerUrl === 'https://api.letta.com/v1') {
|
|
497141
|
+
chatBase = 'https://chat.letta.com';
|
|
497142
|
+
} else if (normalizedServerUrl) {
|
|
497143
|
+
chatBase = normalizedServerUrl.replace(/\\/v1$/, '');
|
|
496865
497144
|
} else {
|
|
496866
|
-
|
|
497145
|
+
chatBase = 'https://chat.letta.com';
|
|
496867
497146
|
}
|
|
496868
|
-
agentIdEl.href =
|
|
497147
|
+
agentIdEl.href = chatBase + '/chat/' + encodeURIComponent(agentId);
|
|
496869
497148
|
agentIdEl.target = '_blank';
|
|
496870
497149
|
}
|
|
496871
497150
|
document.getElementById('generated-at').textContent = 'Generated ' + new Date(DATA.generatedAt).toLocaleString();
|
|
@@ -505910,7 +506189,7 @@ function formatUsageStats({
|
|
|
505910
506189
|
const monthlyCredits = Math.round(balance.monthly_credit_balance);
|
|
505911
506190
|
const purchasedCredits = Math.round(balance.purchased_credit_balance);
|
|
505912
506191
|
const toDollars = (credits) => (credits / 1000).toFixed(2);
|
|
505913
|
-
outputLines.push(`Plan: [${balance.billing_tier}]`,
|
|
506192
|
+
outputLines.push(`Plan: [${balance.billing_tier}]`, buildChatWebUrl("/preferences/usage"), "", `Available credits: ◎${formatNumber2(totalCredits)} ($${toDollars(totalCredits)})`, `Monthly credits: ◎${formatNumber2(monthlyCredits)} ($${toDollars(monthlyCredits)})`, `Purchased credits: ◎${formatNumber2(purchasedCredits)} ($${toDollars(purchasedCredits)})`);
|
|
505914
506193
|
}
|
|
505915
506194
|
return outputLines.join(`
|
|
505916
506195
|
`);
|
|
@@ -516961,13 +517240,13 @@ var init_cleanLastNewline = () => {};
|
|
|
516961
517240
|
function processLine(node, line, state) {
|
|
516962
517241
|
const lineInfo = typeof state.lineInfo === "function" ? state.lineInfo(line) : state.lineInfo[line - 1];
|
|
516963
517242
|
if (lineInfo == null) {
|
|
516964
|
-
const
|
|
516965
|
-
console.error(
|
|
517243
|
+
const errorMessage2 = `processLine: line ${line}, contains no state.lineInfo`;
|
|
517244
|
+
console.error(errorMessage2, {
|
|
516966
517245
|
node,
|
|
516967
517246
|
line,
|
|
516968
517247
|
state
|
|
516969
517248
|
});
|
|
516970
|
-
throw new Error(
|
|
517249
|
+
throw new Error(errorMessage2);
|
|
516971
517250
|
}
|
|
516972
517251
|
node.tagName = "div";
|
|
516973
517252
|
node.properties["data-line"] = lineInfo.lineNumber;
|
|
@@ -520439,9 +520718,9 @@ var instanceId = -1, DiffHunksRenderer = class {
|
|
|
520439
520718
|
let deletionLineContent = deletionLine != null ? deletionLines[deletionLine.lineIndex] : undefined;
|
|
520440
520719
|
let additionLineContent = additionLine != null ? additionLines[additionLine.lineIndex] : undefined;
|
|
520441
520720
|
if (deletionLineContent == null && additionLineContent == null) {
|
|
520442
|
-
const
|
|
520443
|
-
console.error(
|
|
520444
|
-
throw new Error(
|
|
520721
|
+
const errorMessage2 = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
|
|
520722
|
+
console.error(errorMessage2, { file: fileDiff.name });
|
|
520723
|
+
throw new Error(errorMessage2);
|
|
520445
520724
|
}
|
|
520446
520725
|
const lineType = type3 === "change" ? additionLine != null ? "change-addition" : "change-deletion" : type3;
|
|
520447
520726
|
const lineDecoration = this.getUnifiedLineDecoration({
|
|
@@ -520483,9 +520762,9 @@ var instanceId = -1, DiffHunksRenderer = class {
|
|
|
520483
520762
|
lineIndex: additionLine?.lineIndex
|
|
520484
520763
|
});
|
|
520485
520764
|
if (deletionLineContent == null && additionLineContent == null) {
|
|
520486
|
-
const
|
|
520487
|
-
console.error(
|
|
520488
|
-
throw new Error(
|
|
520765
|
+
const errorMessage2 = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
|
|
520766
|
+
console.error(errorMessage2, { file: fileDiff.name });
|
|
520767
|
+
throw new Error(errorMessage2);
|
|
520489
520768
|
}
|
|
520490
520769
|
const missingSide = (() => {
|
|
520491
520770
|
if (type3 === "change") {
|
|
@@ -530589,19 +530868,12 @@ Messages will be executed locally using your letta-code environment.`, true);
|
|
|
530589
530868
|
const deviceName = hostname8();
|
|
530590
530869
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Registering listener "${connectionName}"...
|
|
530591
530870
|
Device: ${deviceName} (${deviceId.slice(0, 8)}...)`, true, "running");
|
|
530592
|
-
const
|
|
530593
|
-
|
|
530594
|
-
|
|
530595
|
-
|
|
530596
|
-
|
|
530597
|
-
}
|
|
530598
|
-
const { connectionId, wsUrl, supportsSplitStatusChannels } = await registerWithCloudRetry({
|
|
530599
|
-
serverUrl,
|
|
530600
|
-
apiKey,
|
|
530601
|
-
deviceId,
|
|
530602
|
-
connectionName,
|
|
530603
|
-
listenerInstanceId: deriveListenerInstanceId("listen", connectionName)
|
|
530604
|
-
}, {
|
|
530871
|
+
const resolveRegisterOptions = () => resolveListenerRegistrationOptions(deviceId, connectionName, {
|
|
530872
|
+
allowInteractiveOAuth: false,
|
|
530873
|
+
surface: "listen"
|
|
530874
|
+
});
|
|
530875
|
+
const registerOptions = await resolveRegisterOptions();
|
|
530876
|
+
const { connectionId, wsUrl, supportsSplitStatusChannels } = await registerWithCloudRetry(registerOptions, {
|
|
530605
530877
|
onRetry: (attempt, delayMs, error54) => {
|
|
530606
530878
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Registering listener "${connectionName}"...
|
|
530607
530879
|
Retry ${attempt} in ${Math.round(delayMs / 1000)}s: ${error54.message}`, true, "running");
|
|
@@ -530655,13 +530927,8 @@ Awaiting instructions${urlText}`, true, "finished");
|
|
|
530655
530927
|
onNeedsReregister: async () => {
|
|
530656
530928
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment expired, re-registering "${connectionName}"...`, true, "running");
|
|
530657
530929
|
try {
|
|
530658
|
-
const
|
|
530659
|
-
|
|
530660
|
-
apiKey,
|
|
530661
|
-
deviceId,
|
|
530662
|
-
connectionName,
|
|
530663
|
-
listenerInstanceId: deriveListenerInstanceId("listen", connectionName)
|
|
530664
|
-
}, {
|
|
530930
|
+
const nextRegisterOptions = await resolveRegisterOptions();
|
|
530931
|
+
const reregisterResult = await registerWithCloudRetry(nextRegisterOptions, {
|
|
530665
530932
|
maxDurationMs: Infinity,
|
|
530666
530933
|
onRetry: (attempt, delayMs, error54) => {
|
|
530667
530934
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Re-registering "${connectionName}"...
|
|
@@ -530694,10 +530961,10 @@ Retry ${attempt} in ${Math.round(delayMs / 1000)}s: ${error54.message}`, true, "
|
|
|
530694
530961
|
}
|
|
530695
530962
|
var activeCommandId3 = null;
|
|
530696
530963
|
var init_listen = __esm(() => {
|
|
530697
|
-
init_client2();
|
|
530698
530964
|
init_app_urls();
|
|
530699
530965
|
init_settings_manager();
|
|
530700
530966
|
init_listen_register();
|
|
530967
|
+
init_auth();
|
|
530701
530968
|
});
|
|
530702
530969
|
|
|
530703
530970
|
// src/cli/app/submit-connection-commands.ts
|
|
@@ -542506,14 +542773,18 @@ function resolveImportFlagAlias(options3) {
|
|
|
542506
542773
|
return options3.importFlagValue ?? options3.fromAfFlagValue;
|
|
542507
542774
|
}
|
|
542508
542775
|
|
|
542776
|
+
// src/cli/helpers/app-urls.ts
|
|
542777
|
+
var CHAT_BASE2 = "https://chat.letta.com";
|
|
542778
|
+
var LETTA_CHAT_API_KEYS_URL2 = `${CHAT_BASE2}/preferences/api-keys`;
|
|
542779
|
+
|
|
542509
542780
|
// src/cli/helpers/error-formatter.ts
|
|
542510
542781
|
init_error();
|
|
542511
542782
|
init_conversation_busy_error();
|
|
542512
542783
|
init_app_urls();
|
|
542513
542784
|
init_error_context();
|
|
542514
542785
|
init_zai_errors();
|
|
542515
|
-
var LETTA_USAGE_URL2 =
|
|
542516
|
-
var LETTA_AGENTS_URL2 =
|
|
542786
|
+
var LETTA_USAGE_URL2 = buildChatWebUrl("/preferences/usage");
|
|
542787
|
+
var LETTA_AGENTS_URL2 = buildPlatformUrl("/projects/default-project/agents");
|
|
542517
542788
|
function formatConversationBusyErrorForDisplay2(errorText, runId, options3) {
|
|
542518
542789
|
if (!isConversationBusyErrorText(errorText))
|
|
542519
542790
|
return null;
|
|
@@ -546350,7 +546621,7 @@ import { parseArgs as parseArgs7 } from "node:util";
|
|
|
546350
546621
|
|
|
546351
546622
|
// src/cli/subcommands/dream-sources/index.ts
|
|
546352
546623
|
init_reflection_transcript();
|
|
546353
|
-
import { createHash as
|
|
546624
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
546354
546625
|
|
|
546355
546626
|
// src/cli/subcommands/dream-sources/openhands.ts
|
|
546356
546627
|
import { readdir as readdir12, readFile as readFile19, stat as stat14 } from "node:fs/promises";
|
|
@@ -546543,7 +546814,7 @@ function parseFromSource(spec) {
|
|
|
546543
546814
|
return { adapter, locator };
|
|
546544
546815
|
}
|
|
546545
546816
|
function conversationIdForSource(parsed) {
|
|
546546
|
-
const hash4 =
|
|
546817
|
+
const hash4 = createHash7("sha1").update(`${parsed.adapter.type}:${parsed.locator}`).digest("hex").slice(0, 12);
|
|
546547
546818
|
return `from-${parsed.adapter.type}-${hash4}`;
|
|
546548
546819
|
}
|
|
546549
546820
|
async function stageFromSource(agentId, parsed) {
|
|
@@ -546721,6 +546992,11 @@ Options:
|
|
|
546721
546992
|
--timeout <seconds> Fail if the reflection pass has not completed
|
|
546722
546993
|
in this many seconds (default: 1500)
|
|
546723
546994
|
-i, --instruction <text> Additional instruction for the reflection pass
|
|
546995
|
+
--prompt <text> Advanced: replace the reflection task prompt
|
|
546996
|
+
entirely (you supply the transcript/memory
|
|
546997
|
+
mechanics via $TRANSCRIPT_PATH and $MEMORY_DIR)
|
|
546998
|
+
--system <text> Advanced: replace the reflection subagent's
|
|
546999
|
+
system prompt
|
|
546724
547000
|
--json Emit machine-readable JSON output
|
|
546725
547001
|
-h, --help Show this help
|
|
546726
547002
|
|
|
@@ -546739,6 +547015,8 @@ var DREAM_OPTIONS = {
|
|
|
546739
547015
|
effort: { type: "string" },
|
|
546740
547016
|
timeout: { type: "string" },
|
|
546741
547017
|
instruction: { type: "string", short: "i" },
|
|
547018
|
+
prompt: { type: "string" },
|
|
547019
|
+
system: { type: "string" },
|
|
546742
547020
|
json: { type: "boolean" }
|
|
546743
547021
|
};
|
|
546744
547022
|
var DEFAULT_TIMEOUT_SECONDS = 1500;
|
|
@@ -546871,6 +547149,8 @@ ${targetInstruction}` : targetInstruction;
|
|
|
546871
547149
|
description: "Reflect on recent conversations",
|
|
546872
547150
|
model: parsed.values.model,
|
|
546873
547151
|
instruction,
|
|
547152
|
+
reflectionPromptOverride: parsed.values.prompt,
|
|
547153
|
+
reflectionSystemPromptOverride: parsed.values.system,
|
|
546874
547154
|
recompileByConversation: new Map,
|
|
546875
547155
|
recompileQueuedByConversation: new Set,
|
|
546876
547156
|
onCompletionMessage: (message, completionResult) => {
|
|
@@ -547125,7 +547405,6 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
|
|
|
547125
547405
|
}
|
|
547126
547406
|
|
|
547127
547407
|
// src/cli/subcommands/listen.tsx
|
|
547128
|
-
init_oauth();
|
|
547129
547408
|
init_paths();
|
|
547130
547409
|
init_restore_scope();
|
|
547131
547410
|
await __promiseAll([
|
|
@@ -547298,26 +547577,9 @@ class RemoteSessionLog {
|
|
|
547298
547577
|
|
|
547299
547578
|
// src/cli/subcommands/listen.tsx
|
|
547300
547579
|
init_listen_register();
|
|
547580
|
+
init_auth();
|
|
547301
547581
|
var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
547302
|
-
var LISTENER_TOKEN_REFRESH_WINDOW_MS = 5 * 60 * 1000;
|
|
547303
547582
|
var activeListenerProcessAnchors = new Set;
|
|
547304
|
-
var defaultListenerOAuthDeps = {
|
|
547305
|
-
LETTA_CLOUD_API_URL,
|
|
547306
|
-
pollForToken,
|
|
547307
|
-
refreshAccessToken,
|
|
547308
|
-
requestDeviceCode
|
|
547309
|
-
};
|
|
547310
|
-
var listenerOAuthDepsOverride = null;
|
|
547311
|
-
function getListenerOAuthDeps() {
|
|
547312
|
-
return listenerOAuthDepsOverride ?? defaultListenerOAuthDeps;
|
|
547313
|
-
}
|
|
547314
|
-
|
|
547315
|
-
class MissingListenerApiKeyError extends Error {
|
|
547316
|
-
constructor() {
|
|
547317
|
-
super("LETTA_API_KEY not found");
|
|
547318
|
-
this.name = "MissingListenerApiKeyError";
|
|
547319
|
-
}
|
|
547320
|
-
}
|
|
547321
547583
|
function PromptEnvName(props) {
|
|
547322
547584
|
const [value, setValue] = import_react33.useState("");
|
|
547323
547585
|
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -547367,16 +547629,6 @@ async function flushListenerTelemetryEnd(exitReason) {
|
|
|
547367
547629
|
await telemetry.flush();
|
|
547368
547630
|
} catch {}
|
|
547369
547631
|
}
|
|
547370
|
-
function getListenerServerUrl(settings3) {
|
|
547371
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547372
|
-
return process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || oauthDeps.LETTA_CLOUD_API_URL;
|
|
547373
|
-
}
|
|
547374
|
-
function normalizeListenerBaseUrl(url2) {
|
|
547375
|
-
return url2.trim().replace(/\/+$/, "");
|
|
547376
|
-
}
|
|
547377
|
-
function isCloudListenerServerUrl(serverUrl) {
|
|
547378
|
-
return normalizeListenerBaseUrl(serverUrl) === normalizeListenerBaseUrl(getListenerOAuthDeps().LETTA_CLOUD_API_URL);
|
|
547379
|
-
}
|
|
547380
547632
|
async function resolveListenerStartupMode(channelNames) {
|
|
547381
547633
|
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
547382
547634
|
const serverUrl = getListenerServerUrl(settings3);
|
|
@@ -547404,84 +547656,6 @@ function getScopedChannelRestoreAgentScope() {
|
|
|
547404
547656
|
function resolveChannelRestoreAgentScope(scopedRestoreAgentScope) {
|
|
547405
547657
|
return scopedRestoreAgentScope ?? parseChannelRestoreAgentScope(process.env[RESTORE_CHANNEL_AGENT_SCOPE_ENV]) ?? (isLocalBackendEnvEnabled() ? "local" : "cloud");
|
|
547406
547658
|
}
|
|
547407
|
-
async function refreshListenerAccessToken(settings3, deviceId, connectionName) {
|
|
547408
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547409
|
-
const now = Date.now();
|
|
547410
|
-
console.log("Access token expired, refreshing...");
|
|
547411
|
-
const tokens = await oauthDeps.refreshAccessToken(settings3.refreshToken, deviceId, connectionName);
|
|
547412
|
-
settingsManager.updateSettings({
|
|
547413
|
-
env: { LETTA_API_KEY: tokens.access_token },
|
|
547414
|
-
tokenExpiresAt: now + tokens.expires_in * 1000,
|
|
547415
|
-
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {}
|
|
547416
|
-
});
|
|
547417
|
-
await settingsManager.flush();
|
|
547418
|
-
console.log("Token refreshed successfully.");
|
|
547419
|
-
return tokens.access_token;
|
|
547420
|
-
}
|
|
547421
|
-
async function runListenerOAuthLogin(deviceId, connectionName) {
|
|
547422
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547423
|
-
console.log(`No API key found. Starting OAuth login...
|
|
547424
|
-
`);
|
|
547425
|
-
const deviceData = await oauthDeps.requestDeviceCode();
|
|
547426
|
-
console.log(`To authenticate, visit: ${deviceData.verification_uri_complete}`);
|
|
547427
|
-
console.log(`Your code: ${deviceData.user_code}
|
|
547428
|
-
`);
|
|
547429
|
-
console.log(`Waiting for authorization...
|
|
547430
|
-
`);
|
|
547431
|
-
const tokens = await oauthDeps.pollForToken(deviceData.device_code, deviceData.interval, deviceData.expires_in, deviceId, connectionName);
|
|
547432
|
-
const now = Date.now();
|
|
547433
|
-
settingsManager.updateSettings({
|
|
547434
|
-
env: { LETTA_API_KEY: tokens.access_token },
|
|
547435
|
-
tokenExpiresAt: now + tokens.expires_in * 1000,
|
|
547436
|
-
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {}
|
|
547437
|
-
});
|
|
547438
|
-
await settingsManager.flush();
|
|
547439
|
-
console.log(`Authenticated successfully.
|
|
547440
|
-
`);
|
|
547441
|
-
return tokens.access_token;
|
|
547442
|
-
}
|
|
547443
|
-
async function resolveListenerRegistrationOptions(deviceId, connectionName) {
|
|
547444
|
-
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
547445
|
-
const serverUrl = getListenerServerUrl(settings3);
|
|
547446
|
-
const envApiKey = process.env.LETTA_API_KEY;
|
|
547447
|
-
if (envApiKey) {
|
|
547448
|
-
return {
|
|
547449
|
-
serverUrl,
|
|
547450
|
-
apiKey: envApiKey,
|
|
547451
|
-
deviceId,
|
|
547452
|
-
connectionName,
|
|
547453
|
-
listenerInstanceId: deriveListenerInstanceId("server", connectionName)
|
|
547454
|
-
};
|
|
547455
|
-
}
|
|
547456
|
-
let apiKey = settings3.env?.LETTA_API_KEY;
|
|
547457
|
-
if (isCloudListenerServerUrl(serverUrl)) {
|
|
547458
|
-
const expiresAt = settings3.tokenExpiresAt;
|
|
547459
|
-
if (settings3.refreshToken && expiresAt) {
|
|
547460
|
-
const now = Date.now();
|
|
547461
|
-
if (!apiKey || now >= expiresAt - LISTENER_TOKEN_REFRESH_WINDOW_MS) {
|
|
547462
|
-
try {
|
|
547463
|
-
apiKey = await refreshListenerAccessToken(settings3, deviceId, connectionName);
|
|
547464
|
-
} catch (refreshErr) {
|
|
547465
|
-
console.warn("Token refresh failed:", refreshErr instanceof Error ? refreshErr.message : String(refreshErr));
|
|
547466
|
-
apiKey = undefined;
|
|
547467
|
-
}
|
|
547468
|
-
}
|
|
547469
|
-
}
|
|
547470
|
-
if (!apiKey) {
|
|
547471
|
-
apiKey = await runListenerOAuthLogin(deviceId, connectionName);
|
|
547472
|
-
}
|
|
547473
|
-
}
|
|
547474
|
-
if (!apiKey) {
|
|
547475
|
-
throw new MissingListenerApiKeyError;
|
|
547476
|
-
}
|
|
547477
|
-
return {
|
|
547478
|
-
serverUrl,
|
|
547479
|
-
apiKey,
|
|
547480
|
-
deviceId,
|
|
547481
|
-
connectionName,
|
|
547482
|
-
listenerInstanceId: deriveListenerInstanceId("server", connectionName)
|
|
547483
|
-
};
|
|
547484
|
-
}
|
|
547485
547659
|
var LISTEN_OPTIONS = {
|
|
547486
547660
|
"env-name": { type: "string" },
|
|
547487
547661
|
channels: { type: "string" },
|
|
@@ -551719,14 +551893,13 @@ class SettingsManager2 {
|
|
|
551719
551893
|
}
|
|
551720
551894
|
async getSettingsWithSecureTokens() {
|
|
551721
551895
|
const baseSettings = this.getSettings();
|
|
551722
|
-
|
|
551896
|
+
const secureTokens = { ...this.secureTokensCache };
|
|
551723
551897
|
if (!getRuntimeContext()) {
|
|
551724
551898
|
const secretsAvailable2 = await this.isKeychainAvailable();
|
|
551725
551899
|
if (secretsAvailable2) {
|
|
551726
|
-
|
|
551727
|
-
|
|
551728
|
-
|
|
551729
|
-
};
|
|
551900
|
+
const storedTokens = await this.getSecureTokens();
|
|
551901
|
+
secureTokens.apiKey = storedTokens.apiKey ?? secureTokens.apiKey;
|
|
551902
|
+
secureTokens.refreshToken = storedTokens.refreshToken ?? secureTokens.refreshToken;
|
|
551730
551903
|
}
|
|
551731
551904
|
}
|
|
551732
551905
|
const fallbackRefreshToken = !secureTokens.refreshToken && baseSettings.refreshToken ? baseSettings.refreshToken : secureTokens.refreshToken;
|
|
@@ -553786,7 +553959,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
553786
553959
|
if (isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !process.env.LETTA_API_KEY) {
|
|
553787
553960
|
console.error("Missing LETTA_API_KEY");
|
|
553788
553961
|
console.error("Headless mode requires an API key set via the LETTA_API_KEY environment variable.");
|
|
553789
|
-
console.error(
|
|
553962
|
+
console.error(`Get an API key at ${LETTA_CHAT_API_KEYS_URL2}`);
|
|
553790
553963
|
process.exit(1);
|
|
553791
553964
|
}
|
|
553792
553965
|
if (!isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !settings3.refreshToken && !apiKey) {
|
|
@@ -554793,4 +554966,4 @@ Error during initialization: ${message}`);
|
|
|
554793
554966
|
}
|
|
554794
554967
|
main2();
|
|
554795
554968
|
|
|
554796
|
-
//# debugId=
|
|
554969
|
+
//# debugId=8218A0B8DF5E5AFE64756E2164756E21
|