@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
- let secureTokens = { ...this.secureTokensCache };
3872
+ const secureTokens = { ...this.secureTokensCache };
3850
3873
  if (!getRuntimeContext()) {
3851
3874
  const secretsAvailable2 = await this.isKeychainAvailable();
3852
3875
  if (secretsAvailable2) {
3853
- secureTokens = {
3854
- ...secureTokens,
3855
- ...await this.getSecureTokens()
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.4",
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 refreshAccessToken(settings.refreshToken, deviceId, deviceName);
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 Error(`Failed to refresh access token from ${authHost}: ${error.error_description || error.error}`);
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
- throw toOAuthActionError("refresh access token", error);
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 = `${APP_BASE}/chat/${agentId}`;
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 buildAppUrl(path5) {
176070
- return `${APP_BASE}${path5}`;
176116
+ function buildChatWebUrl(path5) {
176117
+ return `${CHAT_BASE}${path5}`;
176071
176118
  }
176072
- var APP_BASE = "https://app.letta.com";
176073
- var init_app_urls = () => {};
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
- return true;
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
- args.push("--new-agent", "--system", type3);
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, baseURL, subagentId, isRetry = false, signal, existingAgentId, existingConversationId, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope) {
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, baseURL, subagentId, true, signal, undefined, undefined, maxTurns, parentAgentIdOverride, transcriptPath);
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, baseURL, subagentId, false, signal, existingAgentId, existingConversationId, maxTurns, resolvedParentAgentId, transcriptPath, memoryScope);
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, content, contentIndex, date6, agentId, conversationId) {
393740
- if (content.thinking.length === 0)
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:${contentIndex}`,
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: content.thinking
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
- const reasoningMessage = projectThinkingContent(message, content, contentIndex, date6, agentId, conversationId);
393841
- if (reasoningMessage)
393842
- messages.push(reasoningMessage);
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 = buildAppUrl("/settings/organization/usage");
397079
- LETTA_AGENTS_URL = buildAppUrl("/projects/default-project/agents");
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 otidForContentIndex(otids, prefix, contentIndex) {
399305
- const existing = otids.get(contentIndex);
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}-${contentIndex}-${randomUUID20()}`;
399309
- otids.set(contentIndex, otid);
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: otidForContentIndex(assistantOtids, "provider-assistant", part.contentIndex),
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: otidForContentIndex(reasoningOtids, "provider-reasoning", part.contentIndex),
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 Error(`Failed to refresh access token from ${authHost}: ${error54.error_description || error54.error}`);
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
- throw toOAuthActionError2("refresh access token", error54);
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 parentMemory = await buildParentMemorySnapshot(worktree.worktreeDir);
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 errorMessage = e2 instanceof Error ? e2.message : String(e2);
450096
+ const errorMessage2 = e2 instanceof Error ? e2.message : String(e2);
449689
450097
  const sdkDiagnostic = consumeLastSDKDiagnostic();
449690
- const errorMessageWithDiagnostic = sdkDiagnostic ? `${errorMessage} [${sdkDiagnostic}]` : errorMessage;
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 errorMessage = errorDetail || `Unexpected stop reason: ${stopReason}`;
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: errorMessage,
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 ?? errorMessage;
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 errorMessage = error54 instanceof Error ? error54.message : String(error54);
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: errorMessage,
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 ?? errorMessage;
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 errorMessage = error54 instanceof Error ? error54.message : String(error54);
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: ${errorMessage}`,
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 settings3 = await settingsManager.getSettingsWithSecureTokens();
465807
- const apiKey = process.env.LETTA_API_KEY || settings3.env?.LETTA_API_KEY;
465808
- if (!apiKey) {
465809
- throw new Error("Missing LETTA_API_KEY");
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 errorMessage = errorMessages2.length > 0 ? errorMessages2.join("; ") : `Unexpected stop reason: ${stopReason}`;
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
- errorMessage = formatErrorDetails2(errorObject, agent2.id);
476536
+ errorMessage2 = formatErrorDetails2(errorObject, agent2.id);
476261
476537
  }
476262
476538
  } catch (_e) {
476263
- errorMessage = `${errorMessage}
476539
+ errorMessage2 = `${errorMessage2}
476264
476540
  (Unable to fetch additional error details from server)`;
476265
476541
  }
476266
476542
  }
476267
- trackHeadlessBoundaryError("headless_turn_failed", errorMessage, "headless_turn_execution");
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: errorMessage,
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: ${errorMessage}`);
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 = buildAppUrl("/settings/organization/usage");
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
- "View agent runs and conversations at [app.letta.com](https://app.letta.com).",
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 [errorMessage, setErrorMessage] = import_react87.useState("");
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
- errorMessage.split(`
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
- errorMessage.split(`
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 adeBase;
496863
- if (serverUrl) {
496864
- adeBase = serverUrl.replace(/\\/v1\\/?$/, '').replace('api.letta.com', 'app.letta.com');
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
- adeBase = 'https://app.letta.com';
497145
+ chatBase = 'https://chat.letta.com';
496867
497146
  }
496868
- agentIdEl.href = adeBase + '/chat/' + encodeURIComponent(agentId);
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}]`, buildAppUrl("/settings/organization/usage"), "", `Available credits: ◎${formatNumber2(totalCredits)} ($${toDollars(totalCredits)})`, `Monthly credits: ◎${formatNumber2(monthlyCredits)} ($${toDollars(monthlyCredits)})`, `Purchased credits: ◎${formatNumber2(purchasedCredits)} ($${toDollars(purchasedCredits)})`);
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 errorMessage = `processLine: line ${line}, contains no state.lineInfo`;
516965
- console.error(errorMessage, {
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(errorMessage);
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 errorMessage = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
520443
- console.error(errorMessage, { file: fileDiff.name });
520444
- throw new Error(errorMessage);
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 errorMessage = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
520487
- console.error(errorMessage, { file: fileDiff.name });
520488
- throw new Error(errorMessage);
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 serverUrl = getServerUrl();
530593
- const settings3 = await settingsManager.getSettingsWithSecureTokens();
530594
- const apiKey = process.env.LETTA_API_KEY || settings3.env?.LETTA_API_KEY;
530595
- if (!apiKey) {
530596
- throw new Error("Missing LETTA_API_KEY");
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 reregisterResult = await registerWithCloudRetry({
530659
- serverUrl,
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 = buildAppUrl("/settings/organization/usage");
542516
- var LETTA_AGENTS_URL2 = buildAppUrl("/projects/default-project/agents");
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 createHash6 } from "node:crypto";
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 = createHash6("sha1").update(`${parsed.adapter.type}:${parsed.locator}`).digest("hex").slice(0, 12);
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
- let secureTokens = { ...this.secureTokensCache };
551896
+ const secureTokens = { ...this.secureTokensCache };
551723
551897
  if (!getRuntimeContext()) {
551724
551898
  const secretsAvailable2 = await this.isKeychainAvailable();
551725
551899
  if (secretsAvailable2) {
551726
- secureTokens = {
551727
- ...secureTokens,
551728
- ...await this.getSecureTokens()
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("Get an API key at https://app.letta.com/api-keys");
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=EA7311931B35FB9664756E2164756E21
554969
+ //# debugId=8218A0B8DF5E5AFE64756E2164756E21