@letta-ai/letta-code 0.27.28 → 0.27.29

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
@@ -4719,12 +4719,98 @@ var init_settings_manager = __esm(() => {
4719
4719
  settingsManager = globalThis.__lettaSettingsManager;
4720
4720
  });
4721
4721
 
4722
+ // src/utils/timing.ts
4723
+ function isTimingsEnabled() {
4724
+ const val = process.env.LETTA_DEBUG_TIMINGS;
4725
+ return val === "1" || val === "true";
4726
+ }
4727
+ function formatDuration(ms) {
4728
+ if (ms < 1000)
4729
+ return `${Math.round(ms)}ms`;
4730
+ return `${(ms / 1000).toFixed(2)}s`;
4731
+ }
4732
+ function formatTimestamp(date) {
4733
+ return date.toISOString().slice(11, 23);
4734
+ }
4735
+ function logTiming(message) {
4736
+ if (isTimingsEnabled()) {
4737
+ console.error(`[timing] ${message}`);
4738
+ }
4739
+ }
4740
+ function markMilestone(name) {
4741
+ const now = performance.now();
4742
+ milestones.set(name, now);
4743
+ if (firstMilestoneTime === null) {
4744
+ firstMilestoneTime = now;
4745
+ }
4746
+ if (isTimingsEnabled()) {
4747
+ const relative = now - firstMilestoneTime;
4748
+ console.error(`[timing] MILESTONE ${name} at +${formatDuration(relative)} (${formatTimestamp(new Date)})`);
4749
+ }
4750
+ }
4751
+ function measureSinceMilestone(label, fromMilestone) {
4752
+ if (!isTimingsEnabled())
4753
+ return;
4754
+ const startTime = milestones.get(fromMilestone);
4755
+ if (startTime === undefined) {
4756
+ console.error(`[timing] WARNING: milestone "${fromMilestone}" not found for measurement "${label}"`);
4757
+ return;
4758
+ }
4759
+ const duration = performance.now() - startTime;
4760
+ console.error(`[timing] ${label}: ${formatDuration(duration)}`);
4761
+ }
4762
+ function reportAllMilestones() {
4763
+ if (!isTimingsEnabled() || milestones.size === 0)
4764
+ return;
4765
+ const first = firstMilestoneTime ?? 0;
4766
+ console.error(`[timing] ======== MILESTONE SUMMARY ========`);
4767
+ const sorted = [...milestones.entries()].sort((a, b) => a[1] - b[1]);
4768
+ let prevTime = first;
4769
+ for (const [name, time] of sorted) {
4770
+ const relativeToStart = time - first;
4771
+ const delta = time - prevTime;
4772
+ const deltaStr = prevTime === first ? "" : ` (+${formatDuration(delta)})`;
4773
+ console.error(`[timing] +${formatDuration(relativeToStart).padStart(8)} ${name}${deltaStr}`);
4774
+ prevTime = time;
4775
+ }
4776
+ console.error(`[timing] =====================================`);
4777
+ }
4778
+ function createTimingFetch(baseFetch) {
4779
+ return async (input, init) => {
4780
+ const start = performance.now();
4781
+ const startTime = formatTimestamp(new Date);
4782
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
4783
+ const method = init?.method || "GET";
4784
+ let path2;
4785
+ try {
4786
+ path2 = new URL(url).pathname;
4787
+ } catch {
4788
+ path2 = url;
4789
+ }
4790
+ logTiming(`${method} ${path2} started at ${startTime}`);
4791
+ try {
4792
+ const response = await baseFetch(input, init);
4793
+ const duration = performance.now() - start;
4794
+ logTiming(`${method} ${path2} -> ${formatDuration(duration)} (status: ${response.status})`);
4795
+ return response;
4796
+ } catch (error) {
4797
+ const duration = performance.now() - start;
4798
+ logTiming(`${method} ${path2} -> FAILED after ${formatDuration(duration)}`);
4799
+ throw error;
4800
+ }
4801
+ };
4802
+ }
4803
+ var milestones, firstMilestoneTime = null;
4804
+ var init_timing = __esm(() => {
4805
+ milestones = new Map;
4806
+ });
4807
+
4722
4808
  // package.json
4723
4809
  var package_default;
4724
4810
  var init_package = __esm(() => {
4725
4811
  package_default = {
4726
4812
  name: "@letta-ai/letta-code",
4727
- version: "0.27.28",
4813
+ version: "0.27.29",
4728
4814
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
4729
4815
  type: "module",
4730
4816
  packageManager: "bun@1.3.0",
@@ -4856,474 +4942,6 @@ var init_package = __esm(() => {
4856
4942
  };
4857
4943
  });
4858
4944
 
4859
- // src/backend/api/http-headers.ts
4860
- function getLettaCodeHeaders(apiKey) {
4861
- return {
4862
- "Content-Type": "application/json",
4863
- "User-Agent": `letta-code/${package_default.version}`,
4864
- "X-Letta-Source": "letta-code",
4865
- ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
4866
- };
4867
- }
4868
- var init_http_headers = __esm(() => {
4869
- init_package();
4870
- });
4871
-
4872
- // src/backend/api/request.ts
4873
- async function getApiRequestConfig() {
4874
- const settings = await settingsManager.getSettingsWithSecureTokens();
4875
- return {
4876
- baseUrl: process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL,
4877
- apiKey: process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY || ""
4878
- };
4879
- }
4880
- function maybeMapKnownApiError(status, responseText) {
4881
- if (status !== 403) {
4882
- return null;
4883
- }
4884
- try {
4885
- const errorData = JSON.parse(responseText);
4886
- if (typeof errorData.error === "string" && errorData.error.includes("only available for pro or enterprise")) {
4887
- return new Error("PLAN_UPGRADE_REQUIRED");
4888
- }
4889
- } catch {}
4890
- return null;
4891
- }
4892
- async function apiFetch(path2, options = {}) {
4893
- const config = options.baseUrl === undefined || options.apiKey === undefined ? await getApiRequestConfig() : null;
4894
- const baseUrl = options.baseUrl ?? config?.baseUrl;
4895
- const apiKey = options.apiKey ?? config?.apiKey ?? "";
4896
- if (!baseUrl) {
4897
- throw new Error("Missing Letta API base URL");
4898
- }
4899
- const url = new URL(`${baseUrl}${path2}`);
4900
- if (options.query) {
4901
- for (const [key, value] of Object.entries(options.query)) {
4902
- if (value !== undefined && value !== null) {
4903
- url.searchParams.set(key, String(value));
4904
- }
4905
- }
4906
- }
4907
- return fetch(url, {
4908
- method: options.method ?? "GET",
4909
- headers: {
4910
- ...getLettaCodeHeaders(apiKey),
4911
- ...options.headers
4912
- },
4913
- ...options.body && { body: JSON.stringify(options.body) },
4914
- ...options.signal && { signal: options.signal }
4915
- });
4916
- }
4917
- async function apiRequest(method, path2, body, options = {}) {
4918
- const response = await apiFetch(path2, {
4919
- ...options,
4920
- method,
4921
- body
4922
- });
4923
- const text = await response.text();
4924
- if (!response.ok) {
4925
- const mapped = maybeMapKnownApiError(response.status, text);
4926
- if (mapped) {
4927
- throw mapped;
4928
- }
4929
- throw new ApiRequestError(`API error (${response.status}): ${text}`, response.status, text);
4930
- }
4931
- if (!text) {
4932
- return {};
4933
- }
4934
- return JSON.parse(text);
4935
- }
4936
- var ApiRequestError;
4937
- var init_request = __esm(() => {
4938
- init_oauth();
4939
- init_settings_manager();
4940
- init_http_headers();
4941
- ApiRequestError = class ApiRequestError extends Error {
4942
- status;
4943
- responseText;
4944
- constructor(message, status, responseText) {
4945
- super(message);
4946
- this.status = status;
4947
- this.responseText = responseText;
4948
- this.name = "ApiRequestError";
4949
- }
4950
- };
4951
- });
4952
-
4953
- // src/backend/api/conversations.ts
4954
- var exports_conversations = {};
4955
- __export(exports_conversations, {
4956
- updateConversationDescription: () => updateConversationDescription,
4957
- summarizeConversation: () => summarizeConversation,
4958
- forkConversation: () => forkConversation
4959
- });
4960
- async function forkConversation(conversationId, options = {}) {
4961
- const query = {
4962
- ...options.agentId ? { agent_id: options.agentId } : {},
4963
- ...options.hidden !== undefined ? { hidden: options.hidden } : {}
4964
- };
4965
- return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query, ...options.headers ? { headers: options.headers } : {} });
4966
- }
4967
- async function updateConversationDescription(conversationId, body) {
4968
- return apiRequest("PATCH", `/v1/conversations/${encodeURIComponent(conversationId)}`, body);
4969
- }
4970
- async function summarizeConversation(conversationId, body, options = {}) {
4971
- return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/summarize`, body, options);
4972
- }
4973
- var init_conversations2 = __esm(() => {
4974
- init_request();
4975
- });
4976
-
4977
- // src/constants.ts
4978
- var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_TITLE_SUMMARIZATION_MODEL = "letta/auto-fast", DEFAULT_AGENT_NAME = "Letta Code", INTERRUPTED_BY_USER = "Interrupted by user", TURN_DID_NOT_COMPLETE = "Turn did not complete", SYSTEM_REMINDER_TAG = "system-reminder", SYSTEM_REMINDER_OPEN, SYSTEM_REMINDER_CLOSE, SYSTEM_ALERT_TAG = "system-alert", SYSTEM_ALERT_OPEN, SYSTEM_ALERT_CLOSE, COMPACTION_SUMMARY_HEADER = "(Earlier messages in this conversation have been compacted to free up context, summarized below)", TOKEN_DISPLAY_THRESHOLD = 100, ELAPSED_DISPLAY_THRESHOLD_MS;
4979
- var init_constants = __esm(() => {
4980
- SYSTEM_REMINDER_OPEN = `<${SYSTEM_REMINDER_TAG}>`;
4981
- SYSTEM_REMINDER_CLOSE = `</${SYSTEM_REMINDER_TAG}>`;
4982
- SYSTEM_ALERT_OPEN = `<${SYSTEM_ALERT_TAG}>`;
4983
- SYSTEM_ALERT_CLOSE = `</${SYSTEM_ALERT_TAG}>`;
4984
- ELAPSED_DISPLAY_THRESHOLD_MS = 60 * 1000;
4985
- });
4986
-
4987
- // src/cli/helpers/conversation-title.ts
4988
- function getConversationTitleSettings() {
4989
- try {
4990
- return {
4991
- enabled: settingsManager.getSettings().autoConversationTitles === true
4992
- };
4993
- } catch {
4994
- return { enabled: false };
4995
- }
4996
- }
4997
- function setConversationTitleSettings(enabled) {
4998
- settingsManager.updateSettings({ autoConversationTitles: enabled });
4999
- return getConversationTitleSettings();
5000
- }
5001
- function normalizeConversationTitle(value) {
5002
- let normalized = value.replace(/\s+/g, " ").trim();
5003
- if (normalized.startsWith('"') && normalized.endsWith('"') || normalized.startsWith("'") && normalized.endsWith("'")) {
5004
- normalized = normalized.slice(1, -1).trim();
5005
- }
5006
- if (!normalized || normalized.startsWith("/")) {
5007
- return null;
5008
- }
5009
- return normalized.slice(0, CONVERSATION_TITLE_MAX_LENGTH);
5010
- }
5011
- function paginatedItems(value) {
5012
- if (Array.isArray(value))
5013
- return value;
5014
- return value.getPaginatedItems?.() ?? [];
5015
- }
5016
- function extractAssistantText(content) {
5017
- if (typeof content === "string") {
5018
- return content;
5019
- }
5020
- if (Array.isArray(content)) {
5021
- let collected = "";
5022
- for (const part of content) {
5023
- if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
5024
- collected += part.text;
5025
- }
5026
- }
5027
- return collected;
5028
- }
5029
- return "";
5030
- }
5031
- function stripSystemReminders(content) {
5032
- return content.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
5033
- }
5034
- function extractUserText(content) {
5035
- if (typeof content === "string") {
5036
- return stripSystemReminders(content);
5037
- }
5038
- if (Array.isArray(content)) {
5039
- const parts = [];
5040
- for (const part of content) {
5041
- if (!part || typeof part !== "object")
5042
- continue;
5043
- const record = part;
5044
- if (typeof record.text === "string") {
5045
- parts.push(record.text);
5046
- } else if (record.type === "image") {
5047
- parts.push("[image]");
5048
- }
5049
- }
5050
- return stripSystemReminders(parts.join(`
5051
- `));
5052
- }
5053
- return "";
5054
- }
5055
- function messageToTitleMessage(message) {
5056
- if (message.message_type === "user_message") {
5057
- const content = extractUserText(message.content).trim();
5058
- return content ? { role: "user", content } : null;
5059
- }
5060
- if (message.message_type === "assistant_message") {
5061
- const content = extractAssistantText(message.content).trim();
5062
- return content ? { role: "assistant", content } : null;
5063
- }
5064
- return null;
5065
- }
5066
- function buildConversationTitleMessages(messages) {
5067
- const titleMessages = [];
5068
- for (const message of messages) {
5069
- const titleMessage = messageToTitleMessage(message);
5070
- if (titleMessage) {
5071
- titleMessages.push(titleMessage);
5072
- }
5073
- }
5074
- return titleMessages;
5075
- }
5076
- async function listConversationTitleMessages(backend, conversationId) {
5077
- const page = await backend.listConversationMessages(conversationId, {
5078
- limit: CONVERSATION_TITLE_MESSAGE_LIMIT,
5079
- order: "desc",
5080
- include_return_message_types: ["user_message", "assistant_message"]
5081
- });
5082
- return buildConversationTitleMessages(paginatedItems(page).reverse());
5083
- }
5084
- async function generateConversationTitleFromSummary(conversationId, messages, model = DEFAULT_TITLE_SUMMARIZATION_MODEL) {
5085
- if (messages.length === 0) {
5086
- return null;
5087
- }
5088
- const abortController = new AbortController;
5089
- const timeoutId = setTimeout(() => abortController.abort(), CONVERSATION_TITLE_TIMEOUT_MS);
5090
- try {
5091
- const response = await summarizeConversation(conversationId, {
5092
- prompt: CONVERSATION_TITLE_SYSTEM_PROMPT,
5093
- messages,
5094
- model
5095
- }, {
5096
- signal: abortController.signal
5097
- });
5098
- return normalizeConversationTitle(response.summary);
5099
- } catch (err) {
5100
- if (isDebugEnabled()) {
5101
- console.error("[DEBUG] generateConversationTitleFromSummary failed:", err);
5102
- }
5103
- return null;
5104
- } finally {
5105
- clearTimeout(timeoutId);
5106
- }
5107
- }
5108
- var CONVERSATION_TITLE_MAX_LENGTH = 100, CONVERSATION_TITLE_TIMEOUT_MS = 30000, CONVERSATION_TITLE_SYSTEM_PROMPT = `You are a conversation title generator.
5109
-
5110
- Output ONLY a short, descriptive title for the conversation above.
5111
- Rules:
5112
- - 2 to 7 words
5113
- - describe the actual topic, not the mood
5114
- - no quotes, markdown, prefixes, or trailing punctuation
5115
- - never call any tools — reply with plain text only
5116
- - avoid generic titles like "New conversation" or "Help request"`, CONVERSATION_TITLE_MESSAGE_LIMIT = 1e4;
5117
- var init_conversation_title = __esm(() => {
5118
- init_conversations2();
5119
- init_constants();
5120
- init_settings_manager();
5121
- init_debug();
5122
- });
5123
-
5124
- // src/experiments/manager.ts
5125
- function isEnabledToggle(value) {
5126
- if (!value) {
5127
- return false;
5128
- }
5129
- return ENABLED_TOGGLE_VALUES.has(value.trim().toLowerCase());
5130
- }
5131
- function getExperimentDefinition(id) {
5132
- const definition = EXPERIMENT_DEFINITIONS.find((entry) => entry.id === id);
5133
- if (!definition) {
5134
- throw new Error(`Unknown experiment: ${id}`);
5135
- }
5136
- return definition;
5137
- }
5138
-
5139
- class ExperimentManager {
5140
- getStoredOverrides() {
5141
- try {
5142
- return settingsManager.getSettings().experiments ?? {};
5143
- } catch {
5144
- return {};
5145
- }
5146
- }
5147
- list() {
5148
- return EXPERIMENT_DEFINITIONS.map((definition) => this.getSnapshot(definition.id));
5149
- }
5150
- getSnapshot(id) {
5151
- const definition = getExperimentDefinition(id);
5152
- if (id === "conversation_titles") {
5153
- return {
5154
- ...definition,
5155
- enabled: getConversationTitleSettings().enabled,
5156
- source: "default",
5157
- override: null
5158
- };
5159
- }
5160
- const override = this.getStoredOverrides()[id];
5161
- if (typeof override === "boolean") {
5162
- return {
5163
- ...definition,
5164
- enabled: override,
5165
- source: "override",
5166
- override
5167
- };
5168
- }
5169
- const envEnabled = definition.envVar ? isEnabledToggle(process.env[definition.envVar]) : false;
5170
- return {
5171
- ...definition,
5172
- enabled: envEnabled,
5173
- source: envEnabled ? "env" : "default",
5174
- override: null
5175
- };
5176
- }
5177
- isEnabled(id) {
5178
- return this.getSnapshot(id).enabled;
5179
- }
5180
- set(id, enabled) {
5181
- if (id === "conversation_titles") {
5182
- setConversationTitleSettings(enabled);
5183
- return this.getSnapshot(id);
5184
- }
5185
- const settings = settingsManager.getSettings();
5186
- settingsManager.updateSettings({
5187
- experiments: {
5188
- ...settings.experiments ?? {},
5189
- [id]: enabled
5190
- }
5191
- });
5192
- return this.getSnapshot(id);
5193
- }
5194
- toggle(id) {
5195
- const snapshot = this.getSnapshot(id);
5196
- return this.set(id, !snapshot.enabled);
5197
- }
5198
- }
5199
- var ENABLED_TOGGLE_VALUES, EXPERIMENT_DEFINITIONS, experimentManager;
5200
- var init_manager = __esm(() => {
5201
- init_conversation_title();
5202
- init_settings_manager();
5203
- ENABLED_TOGGLE_VALUES = new Set(["1", "true", "yes"]);
5204
- EXPERIMENT_DEFINITIONS = [
5205
- {
5206
- id: "artifacts",
5207
- label: "artifacts",
5208
- description: "Expose Letta Code Desktop artifact creation tools and artifact UI surfaces.",
5209
- envVar: "LETTA_ARTIFACTS"
5210
- },
5211
- {
5212
- id: "conversation_titles",
5213
- label: "conversation titles",
5214
- description: "Generate AI conversation titles automatically when possible."
5215
- },
5216
- {
5217
- id: "desktop_conversation_bootstrap",
5218
- label: "conversation bootstrap",
5219
- description: "Inject lightweight prior-conversation context into the first turn of brand-new Letta Code conversations."
5220
- },
5221
- {
5222
- id: "diffs",
5223
- label: "diffs",
5224
- description: "Open browser-based worktree diff previews powered by Diffs from Pierre."
5225
- },
5226
- {
5227
- id: "node",
5228
- label: "node",
5229
- description: "Route API requests through the Letta Node / TS core path.",
5230
- envVar: "LETTA_NODE"
5231
- },
5232
- {
5233
- id: "tui_cron",
5234
- label: "TUI cron scheduler",
5235
- description: "Fire scheduled tasks from the CLI when the desktop app isn't running."
5236
- }
5237
- ];
5238
- experimentManager = new ExperimentManager;
5239
- });
5240
-
5241
- // src/utils/timing.ts
5242
- function isTimingsEnabled() {
5243
- const val = process.env.LETTA_DEBUG_TIMINGS;
5244
- return val === "1" || val === "true";
5245
- }
5246
- function formatDuration(ms) {
5247
- if (ms < 1000)
5248
- return `${Math.round(ms)}ms`;
5249
- return `${(ms / 1000).toFixed(2)}s`;
5250
- }
5251
- function formatTimestamp(date) {
5252
- return date.toISOString().slice(11, 23);
5253
- }
5254
- function logTiming(message) {
5255
- if (isTimingsEnabled()) {
5256
- console.error(`[timing] ${message}`);
5257
- }
5258
- }
5259
- function markMilestone(name) {
5260
- const now = performance.now();
5261
- milestones.set(name, now);
5262
- if (firstMilestoneTime === null) {
5263
- firstMilestoneTime = now;
5264
- }
5265
- if (isTimingsEnabled()) {
5266
- const relative = now - firstMilestoneTime;
5267
- console.error(`[timing] MILESTONE ${name} at +${formatDuration(relative)} (${formatTimestamp(new Date)})`);
5268
- }
5269
- }
5270
- function measureSinceMilestone(label, fromMilestone) {
5271
- if (!isTimingsEnabled())
5272
- return;
5273
- const startTime = milestones.get(fromMilestone);
5274
- if (startTime === undefined) {
5275
- console.error(`[timing] WARNING: milestone "${fromMilestone}" not found for measurement "${label}"`);
5276
- return;
5277
- }
5278
- const duration = performance.now() - startTime;
5279
- console.error(`[timing] ${label}: ${formatDuration(duration)}`);
5280
- }
5281
- function reportAllMilestones() {
5282
- if (!isTimingsEnabled() || milestones.size === 0)
5283
- return;
5284
- const first = firstMilestoneTime ?? 0;
5285
- console.error(`[timing] ======== MILESTONE SUMMARY ========`);
5286
- const sorted = [...milestones.entries()].sort((a, b) => a[1] - b[1]);
5287
- let prevTime = first;
5288
- for (const [name, time] of sorted) {
5289
- const relativeToStart = time - first;
5290
- const delta = time - prevTime;
5291
- const deltaStr = prevTime === first ? "" : ` (+${formatDuration(delta)})`;
5292
- console.error(`[timing] +${formatDuration(relativeToStart).padStart(8)} ${name}${deltaStr}`);
5293
- prevTime = time;
5294
- }
5295
- console.error(`[timing] =====================================`);
5296
- }
5297
- function createTimingFetch(baseFetch) {
5298
- return async (input, init) => {
5299
- const start = performance.now();
5300
- const startTime = formatTimestamp(new Date);
5301
- const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
5302
- const method = init?.method || "GET";
5303
- let path2;
5304
- try {
5305
- path2 = new URL(url).pathname;
5306
- } catch {
5307
- path2 = url;
5308
- }
5309
- logTiming(`${method} ${path2} started at ${startTime}`);
5310
- try {
5311
- const response = await baseFetch(input, init);
5312
- const duration = performance.now() - start;
5313
- logTiming(`${method} ${path2} -> ${formatDuration(duration)} (status: ${response.status})`);
5314
- return response;
5315
- } catch (error) {
5316
- const duration = performance.now() - start;
5317
- logTiming(`${method} ${path2} -> FAILED after ${formatDuration(duration)}`);
5318
- throw error;
5319
- }
5320
- };
5321
- }
5322
- var milestones, firstMilestoneTime = null;
5323
- var init_timing = __esm(() => {
5324
- milestones = new Map;
5325
- });
5326
-
5327
4945
  // src/backend/api/memfs-git-proxy.ts
5328
4946
  var exports_memfs_git_proxy = {};
5329
4947
  __export(exports_memfs_git_proxy, {
@@ -5441,13 +5059,20 @@ function getServerUrl() {
5441
5059
  const settings = settingsManager.getSettings();
5442
5060
  return process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL;
5443
5061
  }
5062
+ function getNodeRoutingHeader() {
5063
+ const raw = process.env.LETTA_NODE;
5064
+ if (raw === undefined || raw.trim() === "") {
5065
+ return {};
5066
+ }
5067
+ const enabled = NODE_HEADER_ENABLED_VALUES.has(raw.trim().toLowerCase());
5068
+ return { "x-letta-node": enabled ? "1" : "0" };
5069
+ }
5444
5070
  function getClientDefaultHeaders() {
5445
- const nodeExperiment = experimentManager.getSnapshot("node");
5446
5071
  return {
5447
5072
  "X-Letta-Source": "letta-code",
5448
5073
  "User-Agent": `letta-code/${package_default.version}`,
5449
5074
  "X-Letta-Environment-Device-Id": settingsManager.getOrCreateDeviceId(),
5450
- ...nodeExperiment.source === "override" ? { "x-letta-node": nodeExperiment.enabled ? "1" : "0" } : nodeExperiment.enabled ? { "x-letta-node": "1" } : {},
5075
+ ...getNodeRoutingHeader(),
5451
5076
  ...process.env.LETTA_MEMFS_BACKEND === "hosted" ? { "x-letta-memfs-backend": "hosted" } : {}
5452
5077
  };
5453
5078
  }
@@ -5540,11 +5165,10 @@ If you experience this issue multiple times, move ~/.letta to ~/.letta_backup, a
5540
5165
  };
5541
5166
  return client;
5542
5167
  }
5543
- var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger;
5168
+ var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnostic = null, _cachedApiKey, _testClientOverride = null, sdkLogger, NODE_HEADER_ENABLED_VALUES;
5544
5169
  var init_client2 = __esm(() => {
5545
5170
  init_letta_client();
5546
5171
  init_oauth();
5547
- init_manager();
5548
5172
  init_settings_manager();
5549
5173
  init_error_reporting();
5550
5174
  init_debug();
@@ -5570,6 +5194,101 @@ var init_client2 = __esm(() => {
5570
5194
  console.debug(...args);
5571
5195
  }
5572
5196
  };
5197
+ NODE_HEADER_ENABLED_VALUES = new Set(["1", "true", "yes"]);
5198
+ });
5199
+
5200
+ // src/backend/api/http-headers.ts
5201
+ function getLettaCodeHeaders(apiKey) {
5202
+ return {
5203
+ "Content-Type": "application/json",
5204
+ "User-Agent": `letta-code/${package_default.version}`,
5205
+ "X-Letta-Source": "letta-code",
5206
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
5207
+ };
5208
+ }
5209
+ var init_http_headers = __esm(() => {
5210
+ init_package();
5211
+ });
5212
+
5213
+ // src/backend/api/request.ts
5214
+ async function getApiRequestConfig() {
5215
+ const settings = await settingsManager.getSettingsWithSecureTokens();
5216
+ return {
5217
+ baseUrl: process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL,
5218
+ apiKey: process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY || ""
5219
+ };
5220
+ }
5221
+ function maybeMapKnownApiError(status, responseText) {
5222
+ if (status !== 403) {
5223
+ return null;
5224
+ }
5225
+ try {
5226
+ const errorData = JSON.parse(responseText);
5227
+ if (typeof errorData.error === "string" && errorData.error.includes("only available for pro or enterprise")) {
5228
+ return new Error("PLAN_UPGRADE_REQUIRED");
5229
+ }
5230
+ } catch {}
5231
+ return null;
5232
+ }
5233
+ async function apiFetch(path2, options = {}) {
5234
+ const config = options.baseUrl === undefined || options.apiKey === undefined ? await getApiRequestConfig() : null;
5235
+ const baseUrl = options.baseUrl ?? config?.baseUrl;
5236
+ const apiKey = options.apiKey ?? config?.apiKey ?? "";
5237
+ if (!baseUrl) {
5238
+ throw new Error("Missing Letta API base URL");
5239
+ }
5240
+ const url = new URL(`${baseUrl}${path2}`);
5241
+ if (options.query) {
5242
+ for (const [key, value] of Object.entries(options.query)) {
5243
+ if (value !== undefined && value !== null) {
5244
+ url.searchParams.set(key, String(value));
5245
+ }
5246
+ }
5247
+ }
5248
+ return fetch(url, {
5249
+ method: options.method ?? "GET",
5250
+ headers: {
5251
+ ...getLettaCodeHeaders(apiKey),
5252
+ ...options.headers
5253
+ },
5254
+ ...options.body && { body: JSON.stringify(options.body) },
5255
+ ...options.signal && { signal: options.signal }
5256
+ });
5257
+ }
5258
+ async function apiRequest(method, path2, body, options = {}) {
5259
+ const response = await apiFetch(path2, {
5260
+ ...options,
5261
+ method,
5262
+ body
5263
+ });
5264
+ const text = await response.text();
5265
+ if (!response.ok) {
5266
+ const mapped = maybeMapKnownApiError(response.status, text);
5267
+ if (mapped) {
5268
+ throw mapped;
5269
+ }
5270
+ throw new ApiRequestError(`API error (${response.status}): ${text}`, response.status, text);
5271
+ }
5272
+ if (!text) {
5273
+ return {};
5274
+ }
5275
+ return JSON.parse(text);
5276
+ }
5277
+ var ApiRequestError;
5278
+ var init_request = __esm(() => {
5279
+ init_oauth();
5280
+ init_settings_manager();
5281
+ init_http_headers();
5282
+ ApiRequestError = class ApiRequestError extends Error {
5283
+ status;
5284
+ responseText;
5285
+ constructor(message, status, responseText) {
5286
+ super(message);
5287
+ this.status = status;
5288
+ this.responseText = responseText;
5289
+ this.name = "ApiRequestError";
5290
+ }
5291
+ };
5573
5292
  });
5574
5293
 
5575
5294
  // src/backend/api/health.ts
@@ -18018,7 +17737,7 @@ var init_items = __esm(() => {
18018
17737
 
18019
17738
  // node_modules/openai/resources/conversations/conversations.mjs
18020
17739
  var Conversations2;
18021
- var init_conversations3 = __esm(() => {
17740
+ var init_conversations2 = __esm(() => {
18022
17741
  init_items();
18023
17742
  init_items();
18024
17743
  init_path2();
@@ -19485,7 +19204,7 @@ var init_resources2 = __esm(() => {
19485
19204
  init_beta();
19486
19205
  init_completions3();
19487
19206
  init_containers();
19488
- init_conversations3();
19207
+ init_conversations2();
19489
19208
  init_embeddings2();
19490
19209
  init_evals();
19491
19210
  init_files4();
@@ -19934,7 +19653,7 @@ var init_client3 = __esm(() => {
19934
19653
  init_beta();
19935
19654
  init_chat();
19936
19655
  init_containers();
19937
- init_conversations3();
19656
+ init_conversations2();
19938
19657
  init_evals();
19939
19658
  init_fine_tuning();
19940
19659
  init_graders2();
@@ -39441,7 +39160,7 @@ var init_error5 = __esm(() => {
39441
39160
 
39442
39161
  // node_modules/@anthropic-ai/sdk/internal/constants.mjs
39443
39162
  var MODEL_NONSTREAMING_TOKENS;
39444
- var init_constants2 = __esm(() => {
39163
+ var init_constants = __esm(() => {
39445
39164
  MODEL_NONSTREAMING_TOKENS = {
39446
39165
  "claude-opus-4-20250514": 8192,
39447
39166
  "claude-opus-4-0": 8192,
@@ -40739,7 +40458,7 @@ function transformOutputFormat(params) {
40739
40458
  var DEPRECATED_MODELS, MODELS_TO_WARN_WITH_THINKING_ENABLED, Messages8;
40740
40459
  var init_messages8 = __esm(() => {
40741
40460
  init_error5();
40742
- init_constants2();
40461
+ init_constants();
40743
40462
  init_headers3();
40744
40463
  init_stainless_helper_header();
40745
40464
  init_beta_parser();
@@ -41979,7 +41698,7 @@ var init_messages9 = __esm(() => {
41979
41698
  init_parser5();
41980
41699
  init_batches3();
41981
41700
  init_batches3();
41982
- init_constants2();
41701
+ init_constants();
41983
41702
  Messages9 = class Messages9 extends APIResource3 {
41984
41703
  constructor() {
41985
41704
  super(...arguments);
@@ -114208,7 +113927,7 @@ var init_betaConversationsStartStream = __esm(() => {
114208
113927
 
114209
113928
  // node_modules/@mistralai/mistralai/esm/sdk/conversations.js
114210
113929
  var Conversations3;
114211
- var init_conversations4 = __esm(() => {
113930
+ var init_conversations3 = __esm(() => {
114212
113931
  init_betaConversationsAppend();
114213
113932
  init_betaConversationsAppendStream();
114214
113933
  init_betaConversationsDelete();
@@ -119556,7 +119275,7 @@ var init_beta3 = __esm(() => {
119556
119275
  init_sdks();
119557
119276
  init_betaagents();
119558
119277
  init_connectors();
119559
- init_conversations4();
119278
+ init_conversations3();
119560
119279
  init_libraries();
119561
119280
  init_observability();
119562
119281
  init_rag();
@@ -141070,6 +140789,8 @@ function isFresh(now = Date.now()) {
141070
140789
  }
141071
140790
  function clearAvailableModelsCache() {
141072
140791
  cache = null;
140792
+ inflight = null;
140793
+ generation++;
141073
140794
  }
141074
140795
  function getAvailableModelsCacheInfo() {
141075
140796
  const now = Date.now();
@@ -141133,13 +140854,19 @@ async function getAvailableModelHandles(options3) {
141133
140854
  if (forceRefresh && backend.capabilities.byokProviderRefresh) {
141134
140855
  await refreshByokProviders();
141135
140856
  }
141136
- inflight = fetchFromNetwork().then((entry2) => {
141137
- cache = entry2;
140857
+ const requestGeneration = generation;
140858
+ const request = fetchFromNetwork().then((entry2) => {
140859
+ if (generation === requestGeneration) {
140860
+ cache = entry2;
140861
+ }
141138
140862
  return entry2;
141139
140863
  }).finally(() => {
141140
- inflight = null;
140864
+ if (inflight === request) {
140865
+ inflight = null;
140866
+ }
141141
140867
  });
141142
- const entry = await inflight;
140868
+ inflight = request;
140869
+ const entry = await request;
141143
140870
  return {
141144
140871
  handles: entry.handles,
141145
140872
  providerTypes: entry.providerTypes,
@@ -141162,7 +140889,7 @@ async function getModelProviderType(handle) {
141162
140889
  }
141163
140890
  return cache?.providerTypes.get(handle);
141164
140891
  }
141165
- var CACHE_TTL_MS, cache = null, inflight = null;
140892
+ var CACHE_TTL_MS, cache = null, inflight = null, generation = 0;
141166
140893
  var init_available_models = __esm(() => {
141167
140894
  init_backend2();
141168
140895
  init_providers();
@@ -152980,7 +152707,7 @@ function createChannelTurnProgressBuilder(options3 = {}) {
152980
152707
  namesByToolCallId.delete(summary.id);
152981
152708
  }
152982
152709
  const toolWithAccumulatedArgs = accumulatedArgs ? { ...summary, argumentsText: accumulatedArgs } : summary;
152983
- const toolDetails = status === "error" ? errorDetails || formatToolProgressDetails(toolWithAccumulatedArgs, options3) : formatToolProgressDetails(toolWithAccumulatedArgs, options3);
152710
+ const toolDetails = formatToolProgressDetails(toolWithAccumulatedArgs, options3);
152984
152711
  const toolTitle = formatToolProgressTitle(toolWithAccumulatedArgs, status);
152985
152712
  updates.push(withRunId({
152986
152713
  kind: "tool",
@@ -152989,6 +152716,7 @@ function createChannelTurnProgressBuilder(options3 = {}) {
152989
152716
  ...summary.id ? { toolCallId: summary.id } : {},
152990
152717
  ...summary.name ? { toolName: summary.name } : {},
152991
152718
  ...toolDetails ? { toolDetails } : {},
152719
+ ...status === "error" && errorDetails ? { errorDetails } : {},
152992
152720
  ...toolTitle ? { toolTitle } : {}
152993
152721
  }, runId));
152994
152722
  }
@@ -153019,7 +152747,8 @@ function createChannelTurnProgressBuilder(options3 = {}) {
153019
152747
  namesByToolCallId.delete(tool2.id);
153020
152748
  }
153021
152749
  const toolWithAccumulatedArgs = tool2 && accumulatedArgs ? { ...tool2, argumentsText: accumulatedArgs } : tool2;
153022
- const toolDetails = toolWithAccumulatedArgs ? state === "error" ? formatToolErrorDetails(record5) || formatToolProgressDetails(toolWithAccumulatedArgs, options3) : formatToolProgressDetails(toolWithAccumulatedArgs, options3) : undefined;
152750
+ const toolDetails = toolWithAccumulatedArgs ? formatToolProgressDetails(toolWithAccumulatedArgs, options3) : undefined;
152751
+ const errorDetails = state === "error" ? formatToolErrorDetails(record5) : undefined;
153023
152752
  const toolTitle = toolWithAccumulatedArgs ? formatToolProgressTitle(toolWithAccumulatedArgs, state) : undefined;
153024
152753
  return [
153025
152754
  withRunId({
@@ -153029,6 +152758,7 @@ function createChannelTurnProgressBuilder(options3 = {}) {
153029
152758
  ...tool2?.id ? { toolCallId: tool2.id } : {},
153030
152759
  ...tool2?.name ? { toolName: tool2.name } : {},
153031
152760
  ...toolDetails ? { toolDetails } : {},
152761
+ ...errorDetails ? { errorDetails } : {},
153032
152762
  ...toolTitle ? { toolTitle } : {}
153033
152763
  }, runId)
153034
152764
  ];
@@ -154177,7 +153907,7 @@ function formatSlackToolTaskTitle(toolName, status, details) {
154177
153907
  if (details) {
154178
153908
  return details;
154179
153909
  }
154180
- return status === "complete" ? "Ran" : "Running";
153910
+ return status === "complete" || status === "error" ? "Ran" : "Running";
154181
153911
  }
154182
153912
  if (toolName === "TaskOutput") {
154183
153913
  return status === "complete" ? "Checked task output" : "Checking task output";
@@ -154272,7 +154002,7 @@ function resolveSlackToolActionDetails(entry, update2) {
154272
154002
  return;
154273
154003
  }
154274
154004
  const rememberedDetails = update2.toolCallId ? entry.toolDetailsByCallId?.get(update2.toolCallId) : undefined;
154275
- const details = update2.toolDetails ?? rememberedDetails;
154005
+ const details = (update2.state === "error" ? update2.errorDetails : undefined) ?? update2.toolDetails ?? rememberedDetails;
154276
154006
  if (!details) {
154277
154007
  return;
154278
154008
  }
@@ -154407,7 +154137,7 @@ function buildSlackPlanUpdateChunk(entry) {
154407
154137
  if (entry.status === "cancelled") {
154408
154138
  return {
154409
154139
  type: "plan_update",
154410
- title: "Cancelled"
154140
+ title: "Interrupted"
154411
154141
  };
154412
154142
  }
154413
154143
  if (entry.status === "completed") {
@@ -154547,7 +154277,8 @@ function buildSlackStreamProgressChunks(entry, update2) {
154547
154277
  const resolvedDetails = resolveSlackToolActionDetails(entry, update2);
154548
154278
  const sentDetails = entry.sentTaskDetailsById?.get(id2);
154549
154279
  const details = sentDetails && resolvedDetails && sentDetails !== resolvedDetails ? sentDetails : resolvedDetails;
154550
- const title = resolveSlackToolActionName(entry, update2, details);
154280
+ const titleDetails = update2.toolDetails ?? (update2.toolCallId ? entry.toolDetailsByCallId?.get(update2.toolCallId) : undefined);
154281
+ const title = resolveSlackToolActionName(entry, update2, titleDetails);
154551
154282
  if (!title) {
154552
154283
  return [];
154553
154284
  }
@@ -154597,7 +154328,7 @@ function resolveSlackLifecycleProgressText(outcome) {
154597
154328
  return { status: "completed", text: "Completed" };
154598
154329
  }
154599
154330
  if (outcome === "cancelled") {
154600
- return { status: "cancelled", text: "Cancelled" };
154331
+ return { status: "cancelled", text: "Interrupted" };
154601
154332
  }
154602
154333
  return { status: "error", text: "Failed" };
154603
154334
  }
@@ -154801,6 +154532,7 @@ function createSlackAdapter(config3) {
154801
154532
  const agentThreadTracker = createAgentThreadTracker();
154802
154533
  const progressCardByReplyKey = new Map;
154803
154534
  const activeProgressCardKeyByReplyKey = new Map;
154535
+ const orphanedStreamsByReplyKey = new Map;
154804
154536
  const assistantStatusReplyKeys = new Set;
154805
154537
  const assistantStatusTextByReplyKey = new Map;
154806
154538
  const progressUpdateThrottleMs = resolveSlackProgressUpdateThrottleMs();
@@ -155127,6 +154859,59 @@ function createSlackAdapter(config3) {
155127
154859
  }
155128
154860
  return args;
155129
154861
  }
154862
+ function rememberOrphanedSlackProgressStream(source2, streamTs, terminalPlanTitle) {
154863
+ const replyKey = getLifecycleReplyKey(source2);
154864
+ if (!replyKey) {
154865
+ return;
154866
+ }
154867
+ let orphans = orphanedStreamsByReplyKey.get(replyKey);
154868
+ if (!orphans) {
154869
+ if (orphanedStreamsByReplyKey.size >= SLACK_ORPHANED_STREAM_THREADS_MAX) {
154870
+ const oldestKey = orphanedStreamsByReplyKey.keys().next().value;
154871
+ if (oldestKey !== undefined) {
154872
+ orphanedStreamsByReplyKey.delete(oldestKey);
154873
+ }
154874
+ }
154875
+ orphans = new Map;
154876
+ orphanedStreamsByReplyKey.set(replyKey, orphans);
154877
+ }
154878
+ if (orphans.size >= SLACK_ORPHANED_STREAMS_PER_THREAD_MAX) {
154879
+ return;
154880
+ }
154881
+ orphans.set(streamTs, terminalPlanTitle);
154882
+ console.warn("[Slack] Progress stream stop failed; deferring close until the next stream in this thread:", streamTs);
154883
+ }
154884
+ async function sweepOrphanedSlackProgressStreams(source2, slackClient) {
154885
+ const replyKey = getLifecycleReplyKey(source2);
154886
+ if (!replyKey) {
154887
+ return;
154888
+ }
154889
+ const orphans = orphanedStreamsByReplyKey.get(replyKey);
154890
+ if (!orphans || orphans.size === 0) {
154891
+ return;
154892
+ }
154893
+ orphanedStreamsByReplyKey.delete(replyKey);
154894
+ const stopStream = slackClient.chat.stopStream;
154895
+ if (!stopStream) {
154896
+ return;
154897
+ }
154898
+ for (const [ts, terminalPlanTitle] of orphans) {
154899
+ try {
154900
+ const response = await stopStream.call(slackClient.chat, {
154901
+ channel: source2.chatId,
154902
+ ts,
154903
+ chunks: [{ type: "plan_update", title: terminalPlanTitle }]
154904
+ });
154905
+ if (response.ok === false && !isSlackMessageNotStreamingStateError(response.error)) {
154906
+ console.warn("[Slack] Failed to stop orphaned progress stream:", response.error ?? "unknown error");
154907
+ }
154908
+ } catch (error54) {
154909
+ if (!isSlackMessageNotStreamingStateError(error54)) {
154910
+ console.warn("[Slack] Failed to stop orphaned progress stream:", error54 instanceof Error ? error54.message : error54);
154911
+ }
154912
+ }
154913
+ }
154914
+ }
155130
154915
  async function startSlackProgressStream(entry, replyToMessageId, rawChunks) {
155131
154916
  if (!canStartSlackStream(entry.source)) {
155132
154917
  return false;
@@ -155140,6 +154925,7 @@ function createSlackAdapter(config3) {
155140
154925
  if (!startStream) {
155141
154926
  return false;
155142
154927
  }
154928
+ await sweepOrphanedSlackProgressStreams(entry.source, slackClient);
155143
154929
  try {
155144
154930
  const args = buildSlackStartStreamArgs(entry, replyToMessageId, rawChunks);
155145
154931
  const response = await startStream.call(slackClient.chat, args);
@@ -155546,6 +155332,8 @@ function createSlackAdapter(config3) {
155546
155332
  if (didStop) {
155547
155333
  entry.lastSentText = formatSlackProgressCardText(entry.status, entry.latestText);
155548
155334
  entry.lastSentAt = Date.now();
155335
+ } else if (!entry.streamDead && entry.streamTs) {
155336
+ rememberOrphanedSlackProgressStream(source2, entry.streamTs, entry.status === "completed" ? formatSlackCompletionPlanTitle(entry) : entry.status === "cancelled" ? "Interrupted" : "Failed");
155549
155337
  }
155550
155338
  } else {
155551
155339
  await upsertSlackProgressCard(source2, progress.status, progress.text, {
@@ -156285,7 +156073,7 @@ function createSlackAdapter(config3) {
156285
156073
  };
156286
156074
  return adapter;
156287
156075
  }
156288
- var INITIAL_SLACK_THREAD_HISTORY_LIMIT = 20, SLACK_ASSISTANT_STATUS_VERBS, IGNORED_SLACK_MESSAGE_SUBTYPES, WRAPPER_SLACK_MESSAGE_SUBTYPES, SLACK_INGRESS_DEDUPE_TTL_MS = 60000, SLACK_INGRESS_DEDUPE_MAX = 2000, SLACK_LIFECYCLE_ERROR_TEXT_MAX = 3000, SLACK_DEAD_STREAM_REWRITE_TEXT_MAX = 2900, SLACK_PROGRESS_CARD_TEXT_MAX = 300, SLACK_PROGRESS_CARD_STATE_TTL_MS, SLACK_PROGRESS_CARD_STATE_MAX = 2000, SLACK_STREAM_CHUNK_TEXT_MAX = 256, SLACK_LIFECYCLE_ERROR_TASK_ID = "task_lifecycle_error", SLACK_CHANNEL_RESPONSE_TASK_ID = "task_channel_response", SLACK_TURN_ACTIVE_TASK_ID = "task_turn_active", DEFAULT_SLACK_PROGRESS_UPDATE_THROTTLE_MS = 1000, DEFAULT_SLACK_PROGRESS_STREAM_KEEPALIVE_MS = 60000, DEFAULT_SLACK_COMPLETION_FINALIZE_GRACE_MS = 500, SLACK_AGENT_THREAD_TTL_MS, SLACK_AGENT_THREAD_MAX = 2000, APP_MENTION_RETRY_TTL_MS = 60000;
156076
+ var INITIAL_SLACK_THREAD_HISTORY_LIMIT = 20, SLACK_ASSISTANT_STATUS_VERBS, IGNORED_SLACK_MESSAGE_SUBTYPES, WRAPPER_SLACK_MESSAGE_SUBTYPES, SLACK_INGRESS_DEDUPE_TTL_MS = 60000, SLACK_INGRESS_DEDUPE_MAX = 2000, SLACK_LIFECYCLE_ERROR_TEXT_MAX = 3000, SLACK_DEAD_STREAM_REWRITE_TEXT_MAX = 2900, SLACK_PROGRESS_CARD_TEXT_MAX = 300, SLACK_PROGRESS_CARD_STATE_TTL_MS, SLACK_PROGRESS_CARD_STATE_MAX = 2000, SLACK_ORPHANED_STREAMS_PER_THREAD_MAX = 4, SLACK_ORPHANED_STREAM_THREADS_MAX = 500, SLACK_STREAM_CHUNK_TEXT_MAX = 256, SLACK_LIFECYCLE_ERROR_TASK_ID = "task_lifecycle_error", SLACK_CHANNEL_RESPONSE_TASK_ID = "task_channel_response", SLACK_TURN_ACTIVE_TASK_ID = "task_turn_active", DEFAULT_SLACK_PROGRESS_UPDATE_THROTTLE_MS = 1000, DEFAULT_SLACK_PROGRESS_STREAM_KEEPALIVE_MS = 60000, DEFAULT_SLACK_COMPLETION_FINALIZE_GRACE_MS = 500, SLACK_AGENT_THREAD_TTL_MS, SLACK_AGENT_THREAD_MAX = 2000, APP_MENTION_RETRY_TTL_MS = 60000;
156289
156077
  var init_adapter3 = __esm(async () => {
156290
156078
  init_commands();
156291
156079
  init_lifecycle_error();
@@ -159076,7 +158864,7 @@ function createWhatsAppAdapter(account) {
159076
158864
  }
159077
158865
  async function connect() {
159078
158866
  connectionGeneration += 1;
159079
- const generation = connectionGeneration;
158867
+ const generation2 = connectionGeneration;
159080
158868
  clearActiveSocket(true);
159081
158869
  await ensureRuntimeHelpers();
159082
158870
  connectedAtMs = Date.now();
@@ -159085,7 +158873,7 @@ function createWhatsAppAdapter(account) {
159085
158873
  printQr: true,
159086
158874
  messageStore,
159087
158875
  onConnectionUpdate(update2) {
159088
- if (generation !== connectionGeneration)
158876
+ if (generation2 !== connectionGeneration)
159089
158877
  return;
159090
158878
  if (update2.connection === "open") {
159091
158879
  reconnectAttempts = 0;
@@ -159113,7 +158901,7 @@ function createWhatsAppAdapter(account) {
159113
158901
  }
159114
158902
  }
159115
158903
  });
159116
- if (generation !== connectionGeneration || stopping || !running) {
158904
+ if (generation2 !== connectionGeneration || stopping || !running) {
159117
158905
  try {
159118
158906
  result.sock.ws?.close?.();
159119
158907
  } catch {}
@@ -162622,6 +162410,16 @@ var init_routing = __esm(() => {
162622
162410
  routesByKey = new Map;
162623
162411
  });
162624
162412
 
162413
+ // src/constants.ts
162414
+ var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_TITLE_SUMMARIZATION_MODEL = "letta/auto-fast", DEFAULT_AGENT_NAME = "Letta Code", INTERRUPTED_BY_USER = "Interrupted by user", TURN_DID_NOT_COMPLETE = "Turn did not complete", SYSTEM_REMINDER_TAG = "system-reminder", SYSTEM_REMINDER_OPEN, SYSTEM_REMINDER_CLOSE, SYSTEM_ALERT_TAG = "system-alert", SYSTEM_ALERT_OPEN, SYSTEM_ALERT_CLOSE, COMPACTION_SUMMARY_HEADER = "(Earlier messages in this conversation have been compacted to free up context, summarized below)", TOKEN_DISPLAY_THRESHOLD = 100, ELAPSED_DISPLAY_THRESHOLD_MS;
162415
+ var init_constants2 = __esm(() => {
162416
+ SYSTEM_REMINDER_OPEN = `<${SYSTEM_REMINDER_TAG}>`;
162417
+ SYSTEM_REMINDER_CLOSE = `</${SYSTEM_REMINDER_TAG}>`;
162418
+ SYSTEM_ALERT_OPEN = `<${SYSTEM_ALERT_TAG}>`;
162419
+ SYSTEM_ALERT_CLOSE = `</${SYSTEM_ALERT_TAG}>`;
162420
+ ELAPSED_DISPLAY_THRESHOLD_MS = 60 * 1000;
162421
+ });
162422
+
162625
162423
  // src/cli/helpers/git-context.ts
162626
162424
  import { execFileSync as execFileSync3 } from "node:child_process";
162627
162425
  function runGit(args, cwd) {
@@ -162850,7 +162648,7 @@ ${gitInfo.status}
162850
162648
  }
162851
162649
  }
162852
162650
  var init_session_context = __esm(() => {
162853
- init_constants();
162651
+ init_constants2();
162854
162652
  init_version();
162855
162653
  init_git_context();
162856
162654
  });
@@ -163090,7 +162888,7 @@ function formatChannelNotification(msg) {
163090
162888
  }
163091
162889
  var init_xml = __esm(() => {
163092
162890
  init_session_context();
163093
- init_constants();
162891
+ init_constants2();
163094
162892
  });
163095
162893
 
163096
162894
  // src/channels/registry.ts
@@ -164752,6 +164550,278 @@ var init_registry = __esm(() => {
164752
164550
  };
164753
164551
  });
164754
164552
 
164553
+ // src/backend/api/conversations.ts
164554
+ var exports_conversations = {};
164555
+ __export(exports_conversations, {
164556
+ updateConversationDescription: () => updateConversationDescription,
164557
+ summarizeConversation: () => summarizeConversation,
164558
+ forkConversation: () => forkConversation
164559
+ });
164560
+ async function forkConversation(conversationId, options3 = {}) {
164561
+ const query2 = {
164562
+ ...options3.agentId ? { agent_id: options3.agentId } : {},
164563
+ ...options3.hidden !== undefined ? { hidden: options3.hidden } : {}
164564
+ };
164565
+ return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query: query2, ...options3.headers ? { headers: options3.headers } : {} });
164566
+ }
164567
+ async function updateConversationDescription(conversationId, body) {
164568
+ return apiRequest("PATCH", `/v1/conversations/${encodeURIComponent(conversationId)}`, body);
164569
+ }
164570
+ async function summarizeConversation(conversationId, body, options3 = {}) {
164571
+ return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/summarize`, body, options3);
164572
+ }
164573
+ var init_conversations4 = __esm(() => {
164574
+ init_request();
164575
+ });
164576
+
164577
+ // src/cli/helpers/conversation-title.ts
164578
+ function getConversationTitleSettings() {
164579
+ try {
164580
+ return {
164581
+ enabled: settingsManager.getSettings().autoConversationTitles === true
164582
+ };
164583
+ } catch {
164584
+ return { enabled: false };
164585
+ }
164586
+ }
164587
+ function setConversationTitleSettings(enabled) {
164588
+ settingsManager.updateSettings({ autoConversationTitles: enabled });
164589
+ return getConversationTitleSettings();
164590
+ }
164591
+ function normalizeConversationTitle(value) {
164592
+ let normalized = value.replace(/\s+/g, " ").trim();
164593
+ if (normalized.startsWith('"') && normalized.endsWith('"') || normalized.startsWith("'") && normalized.endsWith("'")) {
164594
+ normalized = normalized.slice(1, -1).trim();
164595
+ }
164596
+ if (!normalized || normalized.startsWith("/")) {
164597
+ return null;
164598
+ }
164599
+ return normalized.slice(0, CONVERSATION_TITLE_MAX_LENGTH);
164600
+ }
164601
+ function paginatedItems(value) {
164602
+ if (Array.isArray(value))
164603
+ return value;
164604
+ return value.getPaginatedItems?.() ?? [];
164605
+ }
164606
+ function extractAssistantText(content) {
164607
+ if (typeof content === "string") {
164608
+ return content;
164609
+ }
164610
+ if (Array.isArray(content)) {
164611
+ let collected = "";
164612
+ for (const part of content) {
164613
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
164614
+ collected += part.text;
164615
+ }
164616
+ }
164617
+ return collected;
164618
+ }
164619
+ return "";
164620
+ }
164621
+ function stripSystemReminders(content) {
164622
+ return content.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
164623
+ }
164624
+ function extractUserText(content) {
164625
+ if (typeof content === "string") {
164626
+ return stripSystemReminders(content);
164627
+ }
164628
+ if (Array.isArray(content)) {
164629
+ const parts = [];
164630
+ for (const part of content) {
164631
+ if (!part || typeof part !== "object")
164632
+ continue;
164633
+ const record5 = part;
164634
+ if (typeof record5.text === "string") {
164635
+ parts.push(record5.text);
164636
+ } else if (record5.type === "image") {
164637
+ parts.push("[image]");
164638
+ }
164639
+ }
164640
+ return stripSystemReminders(parts.join(`
164641
+ `));
164642
+ }
164643
+ return "";
164644
+ }
164645
+ function messageToTitleMessage(message) {
164646
+ if (message.message_type === "user_message") {
164647
+ const content = extractUserText(message.content).trim();
164648
+ return content ? { role: "user", content } : null;
164649
+ }
164650
+ if (message.message_type === "assistant_message") {
164651
+ const content = extractAssistantText(message.content).trim();
164652
+ return content ? { role: "assistant", content } : null;
164653
+ }
164654
+ return null;
164655
+ }
164656
+ function buildConversationTitleMessages(messages) {
164657
+ const titleMessages = [];
164658
+ for (const message of messages) {
164659
+ const titleMessage = messageToTitleMessage(message);
164660
+ if (titleMessage) {
164661
+ titleMessages.push(titleMessage);
164662
+ }
164663
+ }
164664
+ return titleMessages;
164665
+ }
164666
+ async function listConversationTitleMessages(backend, conversationId) {
164667
+ const page = await backend.listConversationMessages(conversationId, {
164668
+ limit: CONVERSATION_TITLE_MESSAGE_LIMIT,
164669
+ order: "desc",
164670
+ include_return_message_types: ["user_message", "assistant_message"]
164671
+ });
164672
+ return buildConversationTitleMessages(paginatedItems(page).reverse());
164673
+ }
164674
+ async function generateConversationTitleFromSummary(conversationId, messages, model = DEFAULT_TITLE_SUMMARIZATION_MODEL) {
164675
+ if (messages.length === 0) {
164676
+ return null;
164677
+ }
164678
+ const abortController = new AbortController;
164679
+ const timeoutId = setTimeout(() => abortController.abort(), CONVERSATION_TITLE_TIMEOUT_MS);
164680
+ try {
164681
+ const response = await summarizeConversation(conversationId, {
164682
+ prompt: CONVERSATION_TITLE_SYSTEM_PROMPT,
164683
+ messages,
164684
+ model
164685
+ }, {
164686
+ signal: abortController.signal
164687
+ });
164688
+ return normalizeConversationTitle(response.summary);
164689
+ } catch (err) {
164690
+ if (isDebugEnabled()) {
164691
+ console.error("[DEBUG] generateConversationTitleFromSummary failed:", err);
164692
+ }
164693
+ return null;
164694
+ } finally {
164695
+ clearTimeout(timeoutId);
164696
+ }
164697
+ }
164698
+ var CONVERSATION_TITLE_MAX_LENGTH = 100, CONVERSATION_TITLE_TIMEOUT_MS = 30000, CONVERSATION_TITLE_SYSTEM_PROMPT = `You are a conversation title generator.
164699
+
164700
+ Output ONLY a short, descriptive title for the conversation above.
164701
+ Rules:
164702
+ - 2 to 7 words
164703
+ - describe the actual topic, not the mood
164704
+ - no quotes, markdown, prefixes, or trailing punctuation
164705
+ - never call any tools — reply with plain text only
164706
+ - avoid generic titles like "New conversation" or "Help request"`, CONVERSATION_TITLE_MESSAGE_LIMIT = 1e4;
164707
+ var init_conversation_title = __esm(() => {
164708
+ init_conversations4();
164709
+ init_constants2();
164710
+ init_settings_manager();
164711
+ init_debug();
164712
+ });
164713
+
164714
+ // src/experiments/manager.ts
164715
+ function isEnabledToggle(value) {
164716
+ if (!value) {
164717
+ return false;
164718
+ }
164719
+ return ENABLED_TOGGLE_VALUES.has(value.trim().toLowerCase());
164720
+ }
164721
+ function getExperimentDefinition(id2) {
164722
+ const definition = EXPERIMENT_DEFINITIONS.find((entry) => entry.id === id2);
164723
+ if (!definition) {
164724
+ throw new Error(`Unknown experiment: ${id2}`);
164725
+ }
164726
+ return definition;
164727
+ }
164728
+
164729
+ class ExperimentManager {
164730
+ getStoredOverrides() {
164731
+ try {
164732
+ return settingsManager.getSettings().experiments ?? {};
164733
+ } catch {
164734
+ return {};
164735
+ }
164736
+ }
164737
+ list() {
164738
+ return EXPERIMENT_DEFINITIONS.map((definition) => this.getSnapshot(definition.id));
164739
+ }
164740
+ getSnapshot(id2) {
164741
+ const definition = getExperimentDefinition(id2);
164742
+ if (id2 === "conversation_titles") {
164743
+ return {
164744
+ ...definition,
164745
+ enabled: getConversationTitleSettings().enabled,
164746
+ source: "default",
164747
+ override: null
164748
+ };
164749
+ }
164750
+ const override = this.getStoredOverrides()[id2];
164751
+ if (typeof override === "boolean") {
164752
+ return {
164753
+ ...definition,
164754
+ enabled: override,
164755
+ source: "override",
164756
+ override
164757
+ };
164758
+ }
164759
+ const envEnabled = definition.envVar ? isEnabledToggle(process.env[definition.envVar]) : false;
164760
+ return {
164761
+ ...definition,
164762
+ enabled: envEnabled,
164763
+ source: envEnabled ? "env" : "default",
164764
+ override: null
164765
+ };
164766
+ }
164767
+ isEnabled(id2) {
164768
+ return this.getSnapshot(id2).enabled;
164769
+ }
164770
+ set(id2, enabled) {
164771
+ if (id2 === "conversation_titles") {
164772
+ setConversationTitleSettings(enabled);
164773
+ return this.getSnapshot(id2);
164774
+ }
164775
+ const settings3 = settingsManager.getSettings();
164776
+ settingsManager.updateSettings({
164777
+ experiments: {
164778
+ ...settings3.experiments ?? {},
164779
+ [id2]: enabled
164780
+ }
164781
+ });
164782
+ return this.getSnapshot(id2);
164783
+ }
164784
+ toggle(id2) {
164785
+ const snapshot = this.getSnapshot(id2);
164786
+ return this.set(id2, !snapshot.enabled);
164787
+ }
164788
+ }
164789
+ var ENABLED_TOGGLE_VALUES, EXPERIMENT_DEFINITIONS, experimentManager;
164790
+ var init_manager = __esm(() => {
164791
+ init_conversation_title();
164792
+ init_settings_manager();
164793
+ ENABLED_TOGGLE_VALUES = new Set(["1", "true", "yes"]);
164794
+ EXPERIMENT_DEFINITIONS = [
164795
+ {
164796
+ id: "artifacts",
164797
+ label: "artifacts",
164798
+ description: "Expose Letta Code Desktop artifact creation tools and artifact UI surfaces.",
164799
+ envVar: "LETTA_ARTIFACTS"
164800
+ },
164801
+ {
164802
+ id: "conversation_titles",
164803
+ label: "conversation titles",
164804
+ description: "Generate AI conversation titles automatically when possible."
164805
+ },
164806
+ {
164807
+ id: "desktop_conversation_bootstrap",
164808
+ label: "conversation bootstrap",
164809
+ description: "Inject lightweight prior-conversation context into the first turn of brand-new Letta Code conversations."
164810
+ },
164811
+ {
164812
+ id: "diffs",
164813
+ label: "diffs",
164814
+ description: "Open browser-based worktree diff previews powered by Diffs from Pierre."
164815
+ },
164816
+ {
164817
+ id: "tui_cron",
164818
+ label: "TUI cron scheduler",
164819
+ description: "Fire scheduled tasks from the CLI when the desktop app isn't running."
164820
+ }
164821
+ ];
164822
+ experimentManager = new ExperimentManager;
164823
+ });
164824
+
164755
164825
  // src/agent/subagent-state.ts
164756
164826
  function updateSnapshot() {
164757
164827
  const agents = Array.from(store2.agents.values());
@@ -165383,7 +165453,7 @@ async function executeAutoAllowedTools(autoAllowed, onChunk, options3) {
165383
165453
  }
165384
165454
  var PARALLEL_SAFE_TOOLS, FILE_PATH_TOOLS, GLOBAL_LOCK_TOOLS;
165385
165455
  var init_approval_execution = __esm(async () => {
165386
- init_constants();
165456
+ init_constants2();
165387
165457
  init_runtime_context();
165388
165458
  await init_manager4();
165389
165459
  PARALLEL_SAFE_TOOLS = new Set([
@@ -172359,7 +172429,7 @@ ${errorMessage}`;
172359
172429
  }
172360
172430
  var cachedWorkingLauncher = null;
172361
172431
  var init_bash = __esm(() => {
172362
- init_constants();
172432
+ init_constants2();
172363
172433
  init_runtime_context();
172364
172434
  init_worktree_ownership();
172365
172435
  init_process_manager();
@@ -180355,7 +180425,7 @@ function normalizeOutgoingApprovalMessages(messages, options3 = {}) {
180355
180425
  }
180356
180426
  var APPROVAL_COMMENT_PREFIX = "The user approved the tool execution with the following comment:";
180357
180427
  var init_approval_result_normalization = __esm(() => {
180358
- init_constants();
180428
+ init_constants2();
180359
180429
  });
180360
180430
 
180361
180431
  // src/agent/skills.ts
@@ -181249,7 +181319,7 @@ async function runModCommandWithTimeout(command, context2) {
181249
181319
  }
181250
181320
  var MOD_COMMAND_TIMEOUT_MS = 30000;
181251
181321
  var init_command_runtime = __esm(() => {
181252
- init_constants();
181322
+ init_constants2();
181253
181323
  });
181254
181324
 
181255
181325
  // src/mods/capabilities.ts
@@ -351268,14 +351338,14 @@ function resolveLocalModSources(options3 = {}) {
351268
351338
  }
351269
351339
  return sources;
351270
351340
  }
351271
- function createEmptyModRegistry(sources, generation, capabilities) {
351341
+ function createEmptyModRegistry(sources, generation2, capabilities) {
351272
351342
  return {
351273
351343
  capabilities: cloneModCapabilities(capabilities),
351274
351344
  commands: {},
351275
351345
  diagnostics: [],
351276
351346
  disposers: [],
351277
351347
  events: {},
351278
- generation,
351348
+ generation: generation2,
351279
351349
  loadedPaths: [],
351280
351350
  ownerAbortControllers: {},
351281
351351
  owners: {},
@@ -351287,12 +351357,12 @@ function createEmptyModRegistry(sources, generation, capabilities) {
351287
351357
  }
351288
351358
  };
351289
351359
  }
351290
- function createModOwner(modPath, source2, generation) {
351360
+ function createModOwner(modPath, source2, generation2) {
351291
351361
  return {
351292
351362
  id: `${source2.scope}:${modPath}`,
351293
351363
  path: modPath,
351294
351364
  scope: source2.scope,
351295
- generation
351365
+ generation: generation2
351296
351366
  };
351297
351367
  }
351298
351368
  function isOwnerLive(registry2, owner) {
@@ -352066,13 +352136,13 @@ async function loadLocalMods(options3) {
352066
352136
  const onChange = options3.onChange ?? (() => {});
352067
352137
  const sources = resolveLocalModSources(options3);
352068
352138
  const capabilities = resolveModCapabilities(options3.capabilities);
352069
- const generation = options3.generation ?? 1;
352139
+ const generation2 = options3.generation ?? 1;
352070
352140
  const builtinCommandIds = new Set([...options3.builtinCommandIds ?? []]);
352071
352141
  const reservedToolNames = new Set([...options3.reservedToolNames ?? []]);
352072
- const registry2 = createEmptyModRegistry(sources, generation, capabilities);
352142
+ const registry2 = createEmptyModRegistry(sources, generation2, capabilities);
352073
352143
  for (const source2 of sources) {
352074
352144
  for (const diagnostic of source2.diagnostics ?? []) {
352075
- const owner = createModOwner(diagnostic.path, source2, generation);
352145
+ const owner = createModOwner(diagnostic.path, source2, generation2);
352076
352146
  recordModDiagnostic(registry2, {
352077
352147
  error: diagnostic.error,
352078
352148
  owner,
@@ -352080,7 +352150,7 @@ async function loadLocalMods(options3) {
352080
352150
  }, options3.onDiagnostic);
352081
352151
  }
352082
352152
  for (const modPath of source2.files) {
352083
- const owner = createModOwner(modPath, source2, generation);
352153
+ const owner = createModOwner(modPath, source2, generation2);
352084
352154
  const abortController = new AbortController;
352085
352155
  let failurePhase = "import";
352086
352156
  registry2.ownerAbortControllers[owner.id] = abortController;
@@ -352253,10 +352323,10 @@ function disposeLocalMods(registry2) {
352253
352323
  }
352254
352324
  function createModEngine(options3) {
352255
352325
  const { getBackend: getBackend2, onDiagnostic, ...modOptions } = options3;
352256
- let generation = 0;
352326
+ let generation2 = 0;
352257
352327
  let disposed = false;
352258
352328
  const capabilities = resolveModCapabilities(modOptions.capabilities);
352259
- let activeRegistry = createEmptyModRegistry(resolveLocalModSources(modOptions), generation, capabilities);
352329
+ let activeRegistry = createEmptyModRegistry(resolveLocalModSources(modOptions), generation2, capabilities);
352260
352330
  let snapshot = snapshotRegistryForReaders(activeRegistry);
352261
352331
  const listeners2 = new Set;
352262
352332
  const publish = () => {
@@ -352269,8 +352339,8 @@ function createModEngine(options3) {
352269
352339
  if (disposed)
352270
352340
  return;
352271
352341
  disposeLocalMods(activeRegistry);
352272
- generation += 1;
352273
- const loadGeneration = generation;
352342
+ generation2 += 1;
352343
+ const loadGeneration = generation2;
352274
352344
  activeRegistry = createEmptyModRegistry(resolveLocalModSources(modOptions), loadGeneration, capabilities);
352275
352345
  publish();
352276
352346
  let loadingRegistry = null;
@@ -352278,7 +352348,7 @@ function createModEngine(options3) {
352278
352348
  ...modOptions,
352279
352349
  generation: loadGeneration,
352280
352350
  onChange: () => {
352281
- if (!disposed && loadingRegistry && loadGeneration === generation) {
352351
+ if (!disposed && loadingRegistry && loadGeneration === generation2) {
352282
352352
  activeRegistry = loadingRegistry;
352283
352353
  publish();
352284
352354
  }
@@ -352286,7 +352356,7 @@ function createModEngine(options3) {
352286
352356
  onDiagnostic: (diagnostic) => {
352287
352357
  if (disposed)
352288
352358
  return;
352289
- if (loadingRegistry && loadGeneration === generation) {
352359
+ if (loadingRegistry && loadGeneration === generation2) {
352290
352360
  activeRegistry = loadingRegistry;
352291
352361
  publish();
352292
352362
  onDiagnostic?.(diagnostic);
@@ -352298,7 +352368,7 @@ function createModEngine(options3) {
352298
352368
  }
352299
352369
  });
352300
352370
  loadingRegistry = nextRegistry;
352301
- if (disposed || loadGeneration !== generation) {
352371
+ if (disposed || loadGeneration !== generation2) {
352302
352372
  disposeLocalMods(nextRegistry);
352303
352373
  return;
352304
352374
  }
@@ -352310,9 +352380,9 @@ function createModEngine(options3) {
352310
352380
  if (disposed)
352311
352381
  return;
352312
352382
  disposed = true;
352313
- generation += 1;
352383
+ generation2 += 1;
352314
352384
  disposeLocalMods(activeRegistry);
352315
- activeRegistry = createEmptyModRegistry(resolveLocalModSources(modOptions), generation, capabilities);
352385
+ activeRegistry = createEmptyModRegistry(resolveLocalModSources(modOptions), generation2, capabilities);
352316
352386
  publish();
352317
352387
  listeners2.clear();
352318
352388
  },
@@ -353481,7 +353551,7 @@ var init_protocol_outbound = __esm(async () => {
353481
353551
  init_git_context();
353482
353552
  init_memory_reminder();
353483
353553
  init_system_prompt_warning();
353484
- init_constants();
353554
+ init_constants2();
353485
353555
  init_manager();
353486
353556
  init_mode();
353487
353557
  init_settings_manager();
@@ -359160,7 +359230,7 @@ ${SYSTEM_REMINDER_CLOSE}`
359160
359230
  }
359161
359231
  var IMAGE_EXTENSIONS2;
359162
359232
  var init_read = __esm(async () => {
359163
- init_constants();
359233
+ init_constants2();
359164
359234
  init_runtime_context();
359165
359235
  init_debug();
359166
359236
  init_file_path();
@@ -368888,7 +368958,7 @@ var init_manager3 = __esm(() => {
368888
368958
  init_metadata();
368889
368959
  init_paths();
368890
368960
  init_app_urls();
368891
- init_constants();
368961
+ init_constants2();
368892
368962
  init_cli_permissions_instance();
368893
368963
  init_memory_paths();
368894
368964
  init_session2();
@@ -369021,7 +369091,7 @@ function appendTaskNotificationEventsToBuffer(summaries, buffer, generateId, flu
369021
369091
  return true;
369022
369092
  }
369023
369093
  var init_task_notifications = __esm(() => {
369024
- init_constants();
369094
+ init_constants2();
369025
369095
  });
369026
369096
 
369027
369097
  // src/tools/impl/task.ts
@@ -376561,7 +376631,7 @@ var init_manager4 = __esm(async () => {
376561
376631
  init_backend2();
376562
376632
  init_message_tool();
376563
376633
  init_registry();
376564
- init_constants();
376634
+ init_constants2();
376565
376635
  init_manager();
376566
376636
  init_hooks2();
376567
376637
  init_context2();
@@ -381629,7 +381699,7 @@ class LocalStore {
381629
381699
  }
381630
381700
  var DEFAULT_LOCAL_AGENT_NAME = "Letta Code", DEFAULT_LOCAL_MODEL = "local/default", LEGACY_LOCAL_CONTEXT_WINDOW_LIMIT = 128000, DEFAULT_LOCAL_CONVERSATION_ID_PREFIX = "local-conv-", DEFAULT_LOCAL_STORED_MESSAGE_ID_PREFIX = "letta-msg-", DEFAULT_LOCAL_UI_MESSAGE_ID_PREFIX = "ui-msg-", LocalBackendNotFoundError, LOCAL_TRANSCRIPT_LEGACY_SCHEMA_VERSION = 1, LOCAL_TRANSCRIPT_SCHEMA_VERSION = 2, LOCAL_TRANSCRIPT_LEGACY_MESSAGE_FORMAT = "pi-ai-message-jsonl", LOCAL_TRANSCRIPT_MESSAGE_FORMAT = "pi-session-entry-jsonl", LOCAL_TRANSCRIPT_PROVIDER_STACK = "pi-ai", LocalTranscriptMigrationRequiredError, LocalTranscriptRepairRequiredError;
381631
381701
  var init_local_store = __esm(() => {
381632
- init_constants();
381702
+ init_constants2();
381633
381703
  init_local_stream_chunks();
381634
381704
  LocalBackendNotFoundError = class LocalBackendNotFoundError extends Error {
381635
381705
  status = 404;
@@ -383475,7 +383545,7 @@ var FAKE_HEADLESS_MODEL = "dev/fake-headless";
383475
383545
  var init_fake_headless_backend = __esm(() => {
383476
383546
  init_local_store();
383477
383547
  init_local_stream_chunks();
383478
- init_constants();
383548
+ init_constants2();
383479
383549
  init_local_provider_errors();
383480
383550
  });
383481
383551
 
@@ -386773,7 +386843,7 @@ class APIBackend {
386773
386843
  if (this.forkConversationOverride) {
386774
386844
  return this.forkConversationOverride(conversationId, options3);
386775
386845
  }
386776
- const { forkConversation: forkConversation2 } = await Promise.resolve().then(() => (init_conversations2(), exports_conversations));
386846
+ const { forkConversation: forkConversation2 } = await Promise.resolve().then(() => (init_conversations4(), exports_conversations));
386777
386847
  return forkConversation2(conversationId, options3);
386778
386848
  }
386779
386849
  }
@@ -425224,7 +425294,7 @@ var init_WelcomeScreen = __esm(async () => {
425224
425294
  // src/agent/create-agent-request.ts
425225
425295
  var LETTA_CODE_AGENT_TYPE = "letta_v1_agent", DEFAULT_CREATED_AGENT_BASE_TOOLS;
425226
425296
  var init_create_agent_request = __esm(() => {
425227
- init_constants();
425297
+ init_constants2();
425228
425298
  init_memory5();
425229
425299
  init_model_catalog();
425230
425300
  init_personality_presets();
@@ -425421,7 +425491,7 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
425421
425491
  var init_create6 = __esm(() => {
425422
425492
  init_backend2();
425423
425493
  init_request();
425424
- init_constants();
425494
+ init_constants2();
425425
425495
  init_settings_manager();
425426
425496
  init_available_models();
425427
425497
  init_create_agent_request();
@@ -427979,7 +428049,7 @@ var init_reflection_launcher = __esm(() => {
427979
428049
  init_memory_reminder();
427980
428050
  init_memory_subagent_completion();
427981
428051
  init_reflection_transcript();
427982
- init_constants();
428052
+ init_constants2();
427983
428053
  init_telemetry();
427984
428054
  init_reflection_threshold_feedback();
427985
428055
  init_debug();
@@ -430502,8 +430572,8 @@ Rules:
430502
430572
  - ignore setup noise like tool chatter, system reminders, approvals, and boilerplate unless the conversation is explicitly about them`;
430503
430573
  var init_conversation_description = __esm(() => {
430504
430574
  init_backend2();
430505
- init_conversations2();
430506
- init_constants();
430575
+ init_conversations4();
430576
+ init_constants2();
430507
430577
  init_manager();
430508
430578
  init_debug();
430509
430579
  });
@@ -430932,7 +431002,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
430932
431002
  }
430933
431003
  var init_init_command = __esm(() => {
430934
431004
  init_subagent_state();
430935
- init_constants();
431005
+ init_constants2();
430936
431006
  init_git_context();
430937
431007
  });
430938
431008
 
@@ -432033,7 +432103,7 @@ function isListModelsCommand(value) {
432033
432103
  if (!value || typeof value !== "object")
432034
432104
  return false;
432035
432105
  const c = value;
432036
- return c.type === "list_models" && typeof c.request_id === "string";
432106
+ return c.type === "list_models" && typeof c.request_id === "string" && (c.force === undefined || typeof c.force === "boolean");
432037
432107
  }
432038
432108
  function isListConnectProvidersCommand(value) {
432039
432109
  if (!value || typeof value !== "object")
@@ -432500,7 +432570,6 @@ var init_protocol_inbound = __esm(async () => {
432500
432570
  EXPERIMENT_IDS = new Set([
432501
432571
  "conversation_titles",
432502
432572
  "desktop_conversation_bootstrap",
432503
- "node",
432504
432573
  "tui_cron"
432505
432574
  ]);
432506
432575
  CHANNEL_ACCOUNT_CREATE_FIELDS = new Set([
@@ -434016,7 +434085,7 @@ function setToolCallsRunning(b3, toolCallIds) {
434016
434085
  }
434017
434086
  var MAX_TAIL_LINES = 5, MAX_BUFFER_SIZE = 1e5, CANCEL_REASON_TEXT;
434018
434087
  var init_accumulator = __esm(async () => {
434019
- init_constants();
434088
+ init_constants2();
434020
434089
  init_hooks2();
434021
434090
  init_debug();
434022
434091
  await init_tool_name_mapping();
@@ -434963,7 +435032,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
434963
435032
  var init_agent_info = __esm(() => {
434964
435033
  init_memory_filesystem2();
434965
435034
  init_paths();
434966
- init_constants();
435035
+ init_constants2();
434967
435036
  init_settings_manager();
434968
435037
  });
434969
435038
 
@@ -435089,7 +435158,7 @@ var BOOTSTRAP_RECENT_LIMIT = 5, BOOTSTRAP_RELEVANT_LIMIT = 5, BOOTSTRAP_RECENT_F
435089
435158
  var init_conversation_bootstrap = __esm(() => {
435090
435159
  init_backend2();
435091
435160
  init_conversation_search();
435092
- init_constants();
435161
+ init_constants2();
435093
435162
  BOOTSTRAP_RECENT_FETCH_LIMIT = BOOTSTRAP_RECENT_LIMIT + BOOTSTRAP_RELEVANT_LIMIT;
435094
435163
  });
435095
435164
 
@@ -435420,7 +435489,7 @@ var init_engine3 = __esm(() => {
435420
435489
  init_agent_info();
435421
435490
  init_conversation_bootstrap();
435422
435491
  init_session_context();
435423
- init_constants();
435492
+ init_constants2();
435424
435493
  init_manager();
435425
435494
  init_mode();
435426
435495
  init_settings_manager();
@@ -435524,7 +435593,7 @@ async function runPostTurnMemorySync(params) {
435524
435593
  }
435525
435594
  var init_memory_git_sync = __esm(() => {
435526
435595
  init_memory_git();
435527
- init_constants();
435596
+ init_constants2();
435528
435597
  init_debug();
435529
435598
  });
435530
435599
 
@@ -436541,7 +436610,7 @@ function stashRecoveredApprovalInterrupts(runtime, recovered) {
436541
436610
  var INTERRUPT_TOOL_RETURN_MAX_CHARS, STREAMING_TOOL_OUTPUT_MAX_CHARS, STREAMING_TOOL_OUTPUT_EMIT_INTERVAL_MS = 100;
436542
436611
  var init_interrupts = __esm(async () => {
436543
436612
  init_approval_result_normalization();
436544
- init_constants();
436613
+ init_constants2();
436545
436614
  init_truncation();
436546
436615
  init_debug();
436547
436616
  init_runtime6();
@@ -443350,7 +443419,7 @@ var init_commands2 = __esm(async () => {
443350
443419
  init_memory_reminder();
443351
443420
  init_skill_name_frontmatter_repair();
443352
443421
  init_command_runtime();
443353
- init_constants();
443422
+ init_constants2();
443354
443423
  init_hooks2();
443355
443424
  init_settings_manager();
443356
443425
  init_error_reporting();
@@ -444501,10 +444570,10 @@ function buildListModelsEntries() {
444501
444570
  ...model.updateArgs && typeof model.updateArgs === "object" ? { updateArgs: model.updateArgs } : {}
444502
444571
  }));
444503
444572
  }
444504
- async function buildListModelsResponse(requestId) {
444573
+ async function buildListModelsResponse(requestId, options3 = {}) {
444505
444574
  const entries = buildListModelsEntries();
444506
444575
  const [handlesResult, providersResult] = await Promise.allSettled([
444507
- getAvailableModelHandles(),
444576
+ getAvailableModelHandles(options3.forceRefresh === true ? { forceRefresh: true } : undefined),
444508
444577
  listProviders2()
444509
444578
  ]);
444510
444579
  const availableHandles = handlesResult.status === "fulfilled" ? [...handlesResult.value.handles] : null;
@@ -444530,7 +444599,9 @@ function handleModelToolsetCommand(parsed, context3) {
444530
444599
  if (isListModelsCommand(parsed)) {
444531
444600
  runDetachedListenerTask("list_models", async () => {
444532
444601
  try {
444533
- const response = await buildListModelsResponse(parsed.request_id);
444602
+ const response = await buildListModelsResponse(parsed.request_id, {
444603
+ forceRefresh: parsed.force === true
444604
+ });
444534
444605
  safeSocketSend(socket, response, "listener_list_models_send_failed", "listener_list_models");
444535
444606
  } catch (error54) {
444536
444607
  safeSocketSend(socket, {
@@ -444911,7 +444982,7 @@ async function handleCwdChange(msg, socket, runtime) {
444911
444982
  }
444912
444983
  var init_control_inputs = __esm(async () => {
444913
444984
  init_backend2();
444914
- init_constants();
444985
+ init_constants2();
444915
444986
  init_mode();
444916
444987
  init_error_reporting();
444917
444988
  init_debug();
@@ -454874,7 +454945,7 @@ function PinDialog({ currentName, onSubmit, onCancel }) {
454874
454945
  }
454875
454946
  var import_react37, jsx_dev_runtime16;
454876
454947
  var init_PinDialog = __esm(async () => {
454877
- init_constants();
454948
+ init_constants2();
454878
454949
  init_colors();
454879
454950
  await __promiseAll([
454880
454951
  init_build4(),
@@ -455920,7 +455991,7 @@ var init_AgentSelector = __esm(async () => {
455920
455991
  init_backend();
455921
455992
  init_local_agent_listing();
455922
455993
  init_use_terminal_width();
455923
- init_constants();
455994
+ init_constants2();
455924
455995
  init_settings_manager();
455925
455996
  init_colors();
455926
455997
  await __promiseAll([
@@ -461854,7 +461925,7 @@ var init_headless = __esm(async () => {
461854
461925
  init_reflection_launcher();
461855
461926
  init_reflection_transcript();
461856
461927
  init_local_backend_mod_events();
461857
- init_constants();
461928
+ init_constants2();
461858
461929
  init_diff_preview();
461859
461930
  init_format_denial();
461860
461931
  init_startup();
@@ -462101,7 +462172,7 @@ async function reconcileExistingAgentState(client, agent2) {
462101
462172
  }
462102
462173
  var DEFAULT_ATTACHED_BASE_TOOLS;
462103
462174
  var init_reconcile_existing_agent_state = __esm(() => {
462104
- init_constants();
462175
+ init_constants2();
462105
462176
  DEFAULT_ATTACHED_BASE_TOOLS = [
462106
462177
  "web_search",
462107
462178
  "fetch_webpage"
@@ -463092,7 +463163,7 @@ function backfillBuffers(buffers, history) {
463092
463163
  }
463093
463164
  var CLIP_CHAR_LIMIT_TEXT = 500;
463094
463165
  var init_backfill = __esm(() => {
463095
- init_constants();
463166
+ init_constants2();
463096
463167
  init_task_notifications();
463097
463168
  });
463098
463169
 
@@ -468471,7 +468542,7 @@ var import_react60, jsx_dev_runtime33, BashCommandMessage;
468471
468542
  var init_BashCommandMessage = __esm(async () => {
468472
468543
  init_glyphs();
468473
468544
  init_use_terminal_width();
468474
- init_constants();
468545
+ init_constants2();
468475
468546
  init_colors();
468476
468547
  await __promiseAll([
468477
468548
  init_build4(),
@@ -469753,7 +469824,7 @@ var init_ConversationSelector = __esm(async () => {
469753
469824
  init_backend2();
469754
469825
  init_glyphs();
469755
469826
  init_use_terminal_width();
469756
- init_constants();
469827
+ init_constants2();
469757
469828
  init_colors();
469758
469829
  await __promiseAll([
469759
469830
  init_build4(),
@@ -469894,7 +469965,7 @@ var import_react69, jsx_dev_runtime42, EventMessage;
469894
469965
  var init_EventMessage = __esm(async () => {
469895
469966
  init_glyphs();
469896
469967
  init_use_terminal_width();
469897
- init_constants();
469968
+ init_constants2();
469898
469969
  init_colors();
469899
469970
  await __promiseAll([
469900
469971
  init_build4(),
@@ -473410,7 +473481,7 @@ var init_AgentInfoBar = __esm(async () => {
473410
473481
  init_string_width();
473411
473482
  init_app_urls();
473412
473483
  init_use_terminal_width();
473413
- init_constants();
473484
+ init_constants2();
473414
473485
  init_settings_manager();
473415
473486
  init_version();
473416
473487
  init_colors();
@@ -476390,7 +476461,7 @@ var init_InputRich = __esm(async () => {
476390
476461
  init_thinking_messages();
476391
476462
  init_use_shimmer_animation();
476392
476463
  init_use_token_smoothing();
476393
- init_constants();
476464
+ init_constants2();
476394
476465
  init_mode();
476395
476466
  init_openai_codex_provider();
476396
476467
  init_settings_manager();
@@ -488088,7 +488159,7 @@ var import_react104, jsx_dev_runtime82, LIVE_SHELL_ARGS_MAX_LINES = 2, ToolCallM
488088
488159
  var init_ToolCallMessageRich = __esm(async () => {
488089
488160
  init_subagent_state();
488090
488161
  init_glyphs();
488091
- init_constants();
488162
+ init_constants2();
488092
488163
  init_store();
488093
488164
  init_use_terminal_width();
488094
488165
  init_colors();
@@ -489274,7 +489345,7 @@ var import_react106, jsx_dev_runtime84, UserMessage;
489274
489345
  var init_UserMessageRich = __esm(async () => {
489275
489346
  init_glyphs();
489276
489347
  init_use_terminal_width();
489277
- init_constants();
489348
+ init_constants2();
489278
489349
  init_task_notifications();
489279
489350
  init_colors();
489280
489351
  await __promiseAll([
@@ -507630,7 +507701,7 @@ ${expanded.command}` : expanded.command;
507630
507701
  }
507631
507702
  var import_react113;
507632
507703
  var init_use_bash_handlers = __esm(async () => {
507633
- init_constants();
507704
+ init_constants2();
507634
507705
  init_ids();
507635
507706
  await init_accumulator();
507636
507707
  import_react113 = __toESM(require_react(), 1);
@@ -508448,7 +508519,7 @@ var init_use_configuration_handlers = __esm(async () => {
508448
508519
  init_client2();
508449
508520
  init_error_formatter();
508450
508521
  init_memory_reminder();
508451
- init_constants();
508522
+ init_constants2();
508452
508523
  init_manager();
508453
508524
  init_openai_codex_provider();
508454
508525
  init_settings_manager();
@@ -508564,7 +508635,7 @@ function stripSystemReminders2(text2) {
508564
508635
  return text2.replace(new RegExp(`${SYSTEM_REMINDER_OPEN}[\\s\\S]*?${SYSTEM_REMINDER_CLOSE}`, "g"), "").replace(new RegExp(`${SYSTEM_ALERT_OPEN}[\\s\\S]*?${SYSTEM_ALERT_CLOSE}`, "g"), "").trim();
508565
508636
  }
508566
508637
  var init_system_reminders = __esm(() => {
508567
- init_constants();
508638
+ init_constants2();
508568
508639
  });
508569
508640
 
508570
508641
  // src/cli/app/use-conversation-loop.ts
@@ -510131,7 +510202,7 @@ var init_use_conversation_loop = __esm(async () => {
510131
510202
  init_queued_message_parts();
510132
510203
  init_reflection_transcript();
510133
510204
  init_thinking_messages();
510134
- init_constants();
510205
+ init_constants2();
510135
510206
  init_hooks2();
510136
510207
  init_format_denial();
510137
510208
  init_mode();
@@ -511054,7 +511125,7 @@ var init_use_interrupt_handler = __esm(async () => {
511054
511125
  init_backend2();
511055
511126
  init_error_formatter();
511056
511127
  init_reflection_launcher();
511057
- init_constants();
511128
+ init_constants2();
511058
511129
  init_constants7();
511059
511130
  await init_accumulator();
511060
511131
  import_react118 = __toESM(require_react(), 1);
@@ -515723,7 +515794,7 @@ function pushMessageHistory(parts, ctx) {
515723
515794
  }
515724
515795
  var MAX_HISTORY_MESSAGES = 8, MAX_MESSAGE_CHARS = 500;
515725
515796
  var init_conversation_switch_alert = __esm(() => {
515726
- init_constants();
515797
+ init_constants2();
515727
515798
  });
515728
515799
 
515729
515800
  // src/cli/app/use-submit-handler.ts
@@ -518011,7 +518082,7 @@ var init_use_submit_handler = __esm(async () => {
518011
518082
  init_system_prompt_warning();
518012
518083
  init_thinking_messages();
518013
518084
  init_command_runtime();
518014
- init_constants();
518085
+ init_constants2();
518015
518086
  init_manager();
518016
518087
  init_hooks2();
518017
518088
  init_conversation_handle();
@@ -522287,7 +522358,7 @@ async function createAgent2(nameOrOptions = DEFAULT_AGENT_NAME, model, embedding
522287
522358
  var init_create9 = __esm(() => {
522288
522359
  init_backend2();
522289
522360
  init_request();
522290
- init_constants();
522361
+ init_constants2();
522291
522362
  init_settings_manager();
522292
522363
  init_available_models();
522293
522364
  init_create_agent_request();
@@ -525087,7 +525158,7 @@ function extractBackendFlag(args) {
525087
525158
  init_backend2();
525088
525159
  init_glyphs();
525089
525160
  init_use_terminal_width();
525090
- init_constants();
525161
+ init_constants2();
525091
525162
  init_colors();
525092
525163
  await __promiseAll([
525093
525164
  init_build4(),
@@ -529911,7 +529982,10 @@ var AGENTS_MD_GUIDANCE = [
529911
529982
  "plain Markdown with any headings. Do NOT duplicate human-README content",
529912
529983
  "(project pitch, quickstart, contribution guide). Prefer editing/merging",
529913
529984
  "existing sections over appending; remove guidance that new evidence",
529914
- "contradicts."
529985
+ "contradicts. Keep it concise and scannable — favor short bullets over prose",
529986
+ "so a coding agent can skim it quickly. Write timelessly: describe how the",
529987
+ "repo works, not how it recently changed, and avoid time-relative wording",
529988
+ "(currently, for now, no longer) that goes stale."
529915
529989
  ].join(`
529916
529990
  `);
529917
529991
  var GENERIC_GUIDANCE = [
@@ -529927,11 +530001,19 @@ function buildTargetInstruction(target2) {
529927
530001
  `In addition to updating memory, maintain the file at $MEMORY_DIR/${relPath}.`,
529928
530002
  guidance,
529929
530003
  "",
529930
- `Read the existing $MEMORY_DIR/${relPath} (create it if it does not exist)`,
529931
- "and revise it in place: apply only the changes the new experience",
529932
- "warrants, using your judgment. Often no change is needed — if so, leave it",
529933
- "as-is. Keep the YAML frontmatter block (--- ... ---) at the top intact;",
529934
- "edit only the body below it. Commit when done."
530004
+ `If $MEMORY_DIR/${relPath} already exists, revise it in place: apply only`,
530005
+ "the changes the new experience warrants, using your judgment. Often no",
530006
+ "change is needed — if so, leave it as-is. Keep the YAML frontmatter block",
530007
+ "(--- ... ---) at the top intact and edit only the body below it.",
530008
+ "",
530009
+ "If it does not exist, create it ONLY when the new experience yields",
530010
+ "durable, forward-looking guidance worth recording, and begin the file with",
530011
+ "a YAML frontmatter block (a --- ... --- header with a short `description:`).",
530012
+ "If there is nothing substantive to record yet, do NOT create the file —",
530013
+ "leave it absent rather than writing a placeholder that says nothing was",
530014
+ "learned. The file should first appear on a run that produces real guidance.",
530015
+ "",
530016
+ "Commit when done."
529935
530017
  ].join(`
529936
530018
  `);
529937
530019
  }
@@ -535886,7 +535968,7 @@ init_subagents();
535886
535968
  init_backend2();
535887
535969
  init_message_tool();
535888
535970
  init_registry();
535889
- init_constants();
535971
+ init_constants2();
535890
535972
  init_manager();
535891
535973
  init_hooks2();
535892
535974
  init_context2();
@@ -538086,4 +538168,4 @@ Error during initialization: ${message}`);
538086
538168
  }
538087
538169
  main2();
538088
538170
 
538089
- //# debugId=3BA6DDB7D3111D5C64756E2164756E21
538171
+ //# debugId=BDC82BB3FBA1F3D964756E2164756E21