@letta-ai/letta-code 0.20.0 → 0.21.0

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.
Files changed (2) hide show
  1. package/letta.js +103 -59
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -3269,7 +3269,7 @@ var package_default;
3269
3269
  var init_package = __esm(() => {
3270
3270
  package_default = {
3271
3271
  name: "@letta-ai/letta-code",
3272
- version: "0.20.0",
3272
+ version: "0.21.0",
3273
3273
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3274
3274
  type: "module",
3275
3275
  bin: {
@@ -53419,6 +53419,7 @@ function getShellEnv() {
53419
53419
  }
53420
53420
  if (convId) {
53421
53421
  env3.LETTA_CONVERSATION_ID = convId;
53422
+ env3.CONVERSATION_ID = convId;
53422
53423
  }
53423
53424
  if (!env3.LETTA_API_KEY || !env3.LETTA_BASE_URL) {
53424
53425
  try {
@@ -69631,12 +69632,18 @@ async function executeTool(name, args, options) {
69631
69632
  }
69632
69633
  if (stdout) {
69633
69634
  for (let i = 0;i < stdout.length; i++) {
69634
- stdout[i] = scrubSecretsFromString(stdout[i]);
69635
+ const line = stdout[i];
69636
+ if (line !== undefined) {
69637
+ stdout[i] = scrubSecretsFromString(line);
69638
+ }
69635
69639
  }
69636
69640
  }
69637
69641
  if (stderr) {
69638
69642
  for (let i = 0;i < stderr.length; i++) {
69639
- stderr[i] = scrubSecretsFromString(stderr[i]);
69643
+ const line = stderr[i];
69644
+ if (line !== undefined) {
69645
+ stderr[i] = scrubSecretsFromString(line);
69646
+ }
69640
69647
  }
69641
69648
  }
69642
69649
  }
@@ -71886,7 +71893,7 @@ function emitSlashCommandEnd(socket, runtime, scope, fields) {
71886
71893
  };
71887
71894
  emitCanonicalMessageDelta(socket, runtime, endDelta, scope);
71888
71895
  }
71889
- async function handleClearCommand(socket, conversationRuntime, opts) {
71896
+ async function handleClearCommand(_socket, conversationRuntime, opts) {
71890
71897
  const client = await getClient2();
71891
71898
  const agentId = conversationRuntime.agentId;
71892
71899
  if (!agentId) {
@@ -77977,7 +77984,7 @@ function getRelativeTime(dateStr) {
77977
77984
  }
77978
77985
  function buildAgentInfo(options) {
77979
77986
  try {
77980
- const { agentInfo, serverUrl } = options;
77987
+ const { agentInfo, serverUrl, conversationId } = options;
77981
77988
  let actualServerUrl = LETTA_CLOUD_API_URL;
77982
77989
  try {
77983
77990
  const settings = settingsManager.getSettings();
@@ -78003,8 +78010,10 @@ function buildAgentInfo(options) {
78003
78010
  })();
78004
78011
  const memoryDirLine = showMemoryDir ? `
78005
78012
  - **Memory directory (also stored in \`MEMORY_DIR\` env var)**: \`${getMemoryFilesystemRoot(agentInfo.id)}\`` : "";
78013
+ const convLine = conversationId ? `
78014
+ - **Conversation ID (also stored in \`CONVERSATION_ID\` env var)**: ${conversationId}` : "";
78006
78015
  return `${SYSTEM_REMINDER_OPEN} This is an automated message providing information about you.
78007
- - **Agent ID (also stored in \`AGENT_ID\` env var)**: ${agentInfo.id}${memoryDirLine}
78016
+ - **Agent ID (also stored in \`AGENT_ID\` env var)**: ${agentInfo.id}${convLine}${memoryDirLine}
78008
78017
  - **Agent name**: ${agentInfo.name || "(unnamed)"} (the user can change this with /rename)
78009
78018
  - **Agent description**: ${agentInfo.description || "(no description)"} (the user can change this with /description)
78010
78019
  - **Last message**: ${lastRunInfo}
@@ -78449,7 +78458,8 @@ async function buildAgentInfoReminder(context3) {
78449
78458
  description: context3.agent.description,
78450
78459
  lastRunAt: context3.agent.lastRunAt
78451
78460
  },
78452
- serverUrl: context3.agent.serverUrl
78461
+ serverUrl: context3.agent.serverUrl,
78462
+ conversationId: context3.agent.conversationId
78453
78463
  });
78454
78464
  context3.state.hasSentAgentInfo = true;
78455
78465
  return reminder || null;
@@ -78728,7 +78738,8 @@ function buildListenReminderContext(params) {
78728
78738
  id: params.agentId,
78729
78739
  name: null,
78730
78740
  description: null,
78731
- lastRunAt: null
78741
+ lastRunAt: null,
78742
+ conversationId: params.conversationId
78732
78743
  },
78733
78744
  state: params.state,
78734
78745
  sessionContextReminderEnabled: true,
@@ -79265,6 +79276,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
79265
79276
  try {
79266
79277
  const { parts: reminderParts } = await buildSharedReminderParts(buildListenReminderContext({
79267
79278
  agentId: agentId || "",
79279
+ conversationId,
79268
79280
  state: runtime.reminderState,
79269
79281
  resolvePlanModeReminder: getPlanModeReminder,
79270
79282
  workingDirectory: turnWorkingDirectory
@@ -84587,7 +84599,8 @@ ${SYSTEM_REMINDER_CLOSE}
84587
84599
  id: agent.id,
84588
84600
  name: agent.name,
84589
84601
  description: agent.description,
84590
- lastRunAt: lastRunAt ?? null
84602
+ lastRunAt: lastRunAt ?? null,
84603
+ conversationId
84591
84604
  },
84592
84605
  state: sharedReminderState,
84593
84606
  sessionContextReminderEnabled: systemInfoReminderEnabled,
@@ -85867,7 +85880,8 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
85867
85880
  id: agent.id,
85868
85881
  name: agent.name,
85869
85882
  description: agent.description,
85870
- lastRunAt: lastRunAt ?? null
85883
+ lastRunAt: lastRunAt ?? null,
85884
+ conversationId
85871
85885
  },
85872
85886
  state: sharedReminderState,
85873
85887
  sessionContextReminderEnabled: systemInfoReminderEnabled,
@@ -119902,6 +119916,24 @@ async function warmMessageSearchCache(client) {
119902
119916
  body
119903
119917
  });
119904
119918
  }
119919
+ function isSearchRangeAvailable(range2, options) {
119920
+ if (range2 === "agent")
119921
+ return Boolean(options.agentId);
119922
+ if (range2 === "conv")
119923
+ return Boolean(options.conversationId);
119924
+ return true;
119925
+ }
119926
+ function buildSearchTargetPlan(mode, range2, options) {
119927
+ const availableRanges = SEARCH_RANGES.filter((candidateRange) => isSearchRangeAvailable(candidateRange, options));
119928
+ const prefetch = [
119929
+ ...SEARCH_MODES.filter((candidateMode) => candidateMode !== mode).map((candidateMode) => ({ mode: candidateMode, range: range2 })),
119930
+ ...availableRanges.filter((candidateRange) => candidateRange !== range2).map((candidateRange) => ({ mode, range: candidateRange }))
119931
+ ];
119932
+ return {
119933
+ primary: { mode, range: range2 },
119934
+ prefetch
119935
+ };
119936
+ }
119905
119937
  function formatLocalTime(dateStr) {
119906
119938
  if (!dateStr)
119907
119939
  return "";
@@ -120001,11 +120033,14 @@ function MessageSearch({
120001
120033
  const [selectedIndex, setSelectedIndex] = import_react79.useState(0);
120002
120034
  const [expandedMessage, setExpandedMessage] = import_react79.useState(null);
120003
120035
  const clientRef = import_react79.useRef(null);
120036
+ const searchRequestIdRef = import_react79.useRef(0);
120004
120037
  const resultsCache = import_react79.useRef(new Map);
120038
+ const pendingResultsCache = import_react79.useRef(new Map);
120005
120039
  import_react79.useEffect(() => {
120006
120040
  const warmCache = async () => {
120007
120041
  try {
120008
120042
  const client = await getClient2();
120043
+ clientRef.current = client;
120009
120044
  await warmMessageSearchCache(client);
120010
120045
  } catch {}
120011
120046
  };
@@ -120029,73 +120064,81 @@ function MessageSearch({
120029
120064
  const searchResults = await client.post("/v1/messages/search", { body });
120030
120065
  return searchResults;
120031
120066
  }, [agentId, conversationId]);
120067
+ const fetchAndCacheSearchResults = import_react79.useCallback(async (client, query, mode, range2) => {
120068
+ const cacheKey = getCacheKey(query, mode, range2);
120069
+ const cached = resultsCache.current.get(cacheKey);
120070
+ if (cached) {
120071
+ return cached;
120072
+ }
120073
+ const pending = pendingResultsCache.current.get(cacheKey);
120074
+ if (pending) {
120075
+ return pending;
120076
+ }
120077
+ if (!isSearchRangeAvailable(range2, { agentId, conversationId })) {
120078
+ const emptyResults = [];
120079
+ resultsCache.current.set(cacheKey, emptyResults);
120080
+ return emptyResults;
120081
+ }
120082
+ const request = fetchSearchResults(client, query, mode, range2).then((searchResults) => {
120083
+ resultsCache.current.set(cacheKey, searchResults);
120084
+ return searchResults;
120085
+ }).finally(() => {
120086
+ pendingResultsCache.current.delete(cacheKey);
120087
+ });
120088
+ pendingResultsCache.current.set(cacheKey, request);
120089
+ return request;
120090
+ }, [agentId, conversationId, fetchSearchResults, getCacheKey]);
120091
+ const prefetchSearchResults = import_react79.useCallback((query, mode, range2) => {
120092
+ const { prefetch } = buildSearchTargetPlan(mode, range2, {
120093
+ agentId,
120094
+ conversationId
120095
+ });
120096
+ if (prefetch.length === 0) {
120097
+ return;
120098
+ }
120099
+ (async () => {
120100
+ try {
120101
+ const client = clientRef.current || await getClient2();
120102
+ clientRef.current = client;
120103
+ await Promise.all(prefetch.map(({ mode: prefetchMode, range: prefetchRange }) => fetchAndCacheSearchResults(client, query, prefetchMode, prefetchRange).catch(() => [])));
120104
+ } catch {}
120105
+ })();
120106
+ }, [agentId, conversationId, fetchAndCacheSearchResults]);
120032
120107
  const executeSearch = import_react79.useCallback(async (query, mode, range2) => {
120033
120108
  if (!query.trim())
120034
120109
  return;
120035
120110
  const cacheKey = getCacheKey(query, mode, range2);
120111
+ const requestId = ++searchRequestIdRef.current;
120036
120112
  const cached = resultsCache.current.get(cacheKey);
120113
+ setError(null);
120037
120114
  if (cached) {
120115
+ setLoading(false);
120038
120116
  setResults(cached);
120039
120117
  setSelectedIndex(0);
120118
+ prefetchSearchResults(query, mode, range2);
120040
120119
  return;
120041
120120
  }
120042
120121
  setLoading(true);
120043
- setError(null);
120044
120122
  try {
120045
120123
  const client = clientRef.current || await getClient2();
120046
120124
  clientRef.current = client;
120047
- const getOrFetch = (m, r2) => {
120048
- const key = getCacheKey(query, m, r2);
120049
- return resultsCache.current.get(key) ?? fetchSearchResults(client, query, m, r2);
120050
- };
120051
- const [
120052
- hybridAll,
120053
- vectorAll,
120054
- ftsAll,
120055
- hybridAgent,
120056
- vectorAgent,
120057
- ftsAgent,
120058
- hybridConv,
120059
- vectorConv,
120060
- ftsConv
120061
- ] = await Promise.all([
120062
- getOrFetch("hybrid", "all"),
120063
- getOrFetch("vector", "all"),
120064
- getOrFetch("fts", "all"),
120065
- agentId ? getOrFetch("hybrid", "agent") : Promise.resolve([]),
120066
- agentId ? getOrFetch("vector", "agent") : Promise.resolve([]),
120067
- agentId ? getOrFetch("fts", "agent") : Promise.resolve([]),
120068
- conversationId ? getOrFetch("hybrid", "conv") : Promise.resolve([]),
120069
- conversationId ? getOrFetch("vector", "conv") : Promise.resolve([]),
120070
- conversationId ? getOrFetch("fts", "conv") : Promise.resolve([])
120071
- ]);
120072
- resultsCache.current.set(getCacheKey(query, "hybrid", "all"), hybridAll);
120073
- resultsCache.current.set(getCacheKey(query, "vector", "all"), vectorAll);
120074
- resultsCache.current.set(getCacheKey(query, "fts", "all"), ftsAll);
120075
- if (agentId) {
120076
- resultsCache.current.set(getCacheKey(query, "hybrid", "agent"), hybridAgent);
120077
- resultsCache.current.set(getCacheKey(query, "vector", "agent"), vectorAgent);
120078
- resultsCache.current.set(getCacheKey(query, "fts", "agent"), ftsAgent);
120079
- }
120080
- if (conversationId) {
120081
- resultsCache.current.set(getCacheKey(query, "hybrid", "conv"), hybridConv);
120082
- resultsCache.current.set(getCacheKey(query, "vector", "conv"), vectorConv);
120083
- resultsCache.current.set(getCacheKey(query, "fts", "conv"), ftsConv);
120084
- }
120085
- const resultMap = {
120086
- hybrid: { all: hybridAll, agent: hybridAgent, conv: hybridConv },
120087
- vector: { all: vectorAll, agent: vectorAgent, conv: vectorConv },
120088
- fts: { all: ftsAll, agent: ftsAgent, conv: ftsConv }
120089
- };
120090
- setResults(resultMap[mode][range2]);
120125
+ const primaryResults = await fetchAndCacheSearchResults(client, query, mode, range2);
120126
+ if (searchRequestIdRef.current !== requestId) {
120127
+ return;
120128
+ }
120129
+ setResults(primaryResults);
120091
120130
  setSelectedIndex(0);
120131
+ setLoading(false);
120132
+ prefetchSearchResults(query, mode, range2);
120092
120133
  } catch (err) {
120134
+ if (searchRequestIdRef.current !== requestId) {
120135
+ return;
120136
+ }
120093
120137
  setError(err instanceof Error ? err.message : String(err));
120094
120138
  setResults([]);
120095
- } finally {
120096
120139
  setLoading(false);
120097
120140
  }
120098
- }, [fetchSearchResults, getCacheKey, agentId, conversationId]);
120141
+ }, [fetchAndCacheSearchResults, getCacheKey, prefetchSearchResults]);
120099
120142
  const submitSearch = import_react79.useCallback(() => {
120100
120143
  if (searchInput.trim() && searchInput !== activeQuery) {
120101
120144
  setActiveQuery(searchInput);
@@ -135053,7 +135096,8 @@ ${SYSTEM_REMINDER_CLOSE}
135053
135096
  id: agentId,
135054
135097
  name: agentName,
135055
135098
  description: agentDescription,
135056
- lastRunAt: agentLastRunAt
135099
+ lastRunAt: agentLastRunAt,
135100
+ conversationId
135057
135101
  },
135058
135102
  state: sharedReminderStateRef.current,
135059
135103
  sessionContextReminderEnabled,
@@ -147488,4 +147532,4 @@ Error during initialization: ${message}`);
147488
147532
  }
147489
147533
  main();
147490
147534
 
147491
- //# debugId=F7D039CC4FAF744E64756E2164756E21
147535
+ //# debugId=194DEEED08EA813D64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {