@letta-ai/letta-code 0.32.1 → 0.32.3

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 (74) hide show
  1. package/README.md +6 -0
  2. package/dist/agent-presets.js +25 -1
  3. package/dist/agent-presets.js.map +2 -2
  4. package/dist/channels-public.js +32 -2
  5. package/dist/channels-public.js.map +3 -3
  6. package/dist/channels-slack.js +100 -4
  7. package/dist/channels-slack.js.map +7 -6
  8. package/dist/gateway-core.js +125 -32
  9. package/dist/gateway-core.js.map +8 -7
  10. package/dist/mcp-client.js +2 -2
  11. package/dist/mcp-client.js.map +1 -1
  12. package/dist/memory-constraints.js +77 -1
  13. package/dist/memory-constraints.js.map +5 -4
  14. package/dist/types/agent/memory-git-hooks.d.ts +1 -1
  15. package/dist/types/agent/memory-git-hooks.d.ts.map +1 -1
  16. package/dist/types/agent/skills.d.ts.map +1 -1
  17. package/dist/types/agent/subagents/manager.d.ts.map +1 -1
  18. package/dist/types/backend/backend.d.ts +0 -1
  19. package/dist/types/backend/backend.d.ts.map +1 -1
  20. package/dist/types/backend/dev/fake-headless-backend.d.ts.map +1 -1
  21. package/dist/types/channels/gateway-core.d.ts +2 -0
  22. package/dist/types/channels/gateway-core.d.ts.map +1 -1
  23. package/dist/types/channels/gateway-sources.d.ts +6 -0
  24. package/dist/types/channels/gateway-sources.d.ts.map +1 -0
  25. package/dist/types/channels/message-channel-bindings.d.ts +39 -0
  26. package/dist/types/channels/message-channel-bindings.d.ts.map +1 -0
  27. package/dist/types/channels/message-channel-executor.d.ts +4 -0
  28. package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
  29. package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
  30. package/dist/types/channels/message-channel-types.d.ts +3 -1
  31. package/dist/types/channels/message-channel-types.d.ts.map +1 -1
  32. package/dist/types/channels/plugin-types.d.ts +9 -1
  33. package/dist/types/channels/plugin-types.d.ts.map +1 -1
  34. package/dist/types/channels/progress-builder.d.ts +1 -1
  35. package/dist/types/channels/progress-builder.d.ts.map +1 -1
  36. package/dist/types/channels/progress-types.d.ts +28 -0
  37. package/dist/types/channels/progress-types.d.ts.map +1 -0
  38. package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
  39. package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
  40. package/dist/types/channels/slack/progress.d.ts.map +1 -1
  41. package/dist/types/channels/slack/status-controller.d.ts +2 -1
  42. package/dist/types/channels/slack/status-controller.d.ts.map +1 -1
  43. package/dist/types/channels/types.d.ts +6 -23
  44. package/dist/types/channels/types.d.ts.map +1 -1
  45. package/dist/types/cli/helpers/app-urls.d.ts +0 -4
  46. package/dist/types/cli/helpers/app-urls.d.ts.map +1 -1
  47. package/dist/types/cli/helpers/error-formatter.d.ts.map +1 -1
  48. package/dist/types/gateway-core.d.ts +1 -0
  49. package/dist/types/gateway-core.d.ts.map +1 -1
  50. package/dist/types/memory-constraints.d.ts +1 -0
  51. package/dist/types/memory-constraints.d.ts.map +1 -1
  52. package/dist/types/memory-frontmatter.d.ts +18 -0
  53. package/dist/types/memory-frontmatter.d.ts.map +1 -0
  54. package/dist/types/tools/letta-toolset.d.ts +10 -0
  55. package/dist/types/tools/letta-toolset.d.ts.map +1 -0
  56. package/dist/types/tools/toolset-options.d.ts +4 -0
  57. package/dist/types/tools/toolset-options.d.ts.map +1 -0
  58. package/dist/types/tools/toolset-types.d.ts +1 -2
  59. package/dist/types/tools/toolset-types.d.ts.map +1 -1
  60. package/dist/types/tools/toolset.d.ts.map +1 -1
  61. package/dist/types/types/protocol_v2.d.ts +3 -2
  62. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  63. package/dist/types/types/toolset-protocol.d.ts +10 -0
  64. package/dist/types/types/toolset-protocol.d.ts.map +1 -0
  65. package/dist/types/websocket/listener/device-toolset-status.d.ts +6 -0
  66. package/dist/types/websocket/listener/device-toolset-status.d.ts.map +1 -0
  67. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  68. package/letta.js +968 -1482
  69. package/package.json +2 -1
  70. package/scripts/source-file-size-baseline.json +6 -6
  71. package/skills/image-generation/SKILL.md +5 -4
  72. package/skills/self-configuration/SKILL.md +1 -1
  73. package/skills/working-across-computers/SKILL.md +88 -0
  74. package/skills/teleporting-between-environments/SKILL.md +0 -114
@@ -501,6 +501,36 @@ function getInteractiveApprovalKind(toolName) {
501
501
  }
502
502
  }
503
503
 
504
+ // src/channels/gateway-sources.ts
505
+ function sourceRouteKey(source) {
506
+ return [
507
+ source.channel,
508
+ source.accountId ?? "",
509
+ source.chatId,
510
+ source.threadId ?? ""
511
+ ].join(":");
512
+ }
513
+ function sourceLifecycleKey(source) {
514
+ return [
515
+ sourceRouteKey(source),
516
+ source.messageId ?? "",
517
+ source.agentId,
518
+ source.conversationId
519
+ ].join(":");
520
+ }
521
+ function uniqueSourcesBy(sources, getKey) {
522
+ const byKey = new Map;
523
+ for (const source of sources)
524
+ byKey.set(getKey(source), source);
525
+ return [...byKey.values()];
526
+ }
527
+ function uniqueRoutedSources(sources) {
528
+ return uniqueSourcesBy(sources, sourceRouteKey);
529
+ }
530
+ function uniqueLifecycleSources(sources) {
531
+ return uniqueSourcesBy(sources, sourceLifecycleKey);
532
+ }
533
+
504
534
  // src/channels/message-channel-idempotency.ts
505
535
  class MessageChannelDuplicateActionError extends Error {
506
536
  constructor(state) {
@@ -1009,6 +1039,34 @@ function toolNameForMessage(summary) {
1009
1039
  function createChannelTurnProgressBuilder(options = {}) {
1010
1040
  const argumentsByToolCallId = new Map;
1011
1041
  const namesByToolCallId = new Map;
1042
+ const batchesByStep = new Map;
1043
+ const batchesByToolCallId = new Map;
1044
+ function addToolBatchTitles(delta, updates) {
1045
+ const record = asRecord(delta);
1046
+ if (!record)
1047
+ return updates;
1048
+ const messageType = getMessageType(record);
1049
+ const isToolRequest = messageType === "tool_call_message" || messageType === "approval_request_message";
1050
+ const stepKey = isToolRequest ? firstNonEmptyString(record.step_id, record.id) : undefined;
1051
+ let requestBatch = stepKey ? batchesByStep.get(stepKey) : undefined;
1052
+ if (stepKey && !requestBatch) {
1053
+ requestBatch = { title: null };
1054
+ batchesByStep.set(stepKey, requestBatch);
1055
+ }
1056
+ return updates.map((update) => {
1057
+ if (update.kind !== "tool")
1058
+ return update;
1059
+ const batch = (update.toolCallId ? batchesByToolCallId.get(update.toolCallId) : undefined) ?? requestBatch;
1060
+ if (!batch)
1061
+ return update;
1062
+ if (update.toolCallId)
1063
+ batchesByToolCallId.set(update.toolCallId, batch);
1064
+ if (batch.title === null && update.state === "started") {
1065
+ batch.title = firstNonEmptyString(update.toolTitle, update.toolDetails) ?? null;
1066
+ }
1067
+ return { ...update, toolBatchTitle: batch.title };
1068
+ });
1069
+ }
1012
1070
  function extractToolCallSummary(value) {
1013
1071
  const record = asRecord(value);
1014
1072
  if (!record) {
@@ -1325,7 +1383,9 @@ function createChannelTurnProgressBuilder(options = {}) {
1325
1383
  return [];
1326
1384
  }
1327
1385
  }
1328
- return { buildUpdates };
1386
+ return {
1387
+ buildUpdates: (delta) => addToolBatchTitles(delta, buildUpdates(delta))
1388
+ };
1329
1389
  }
1330
1390
 
1331
1391
  // src/channels/gateway-core.ts
@@ -1336,34 +1396,6 @@ function runtimeKey(runtime) {
1336
1396
  function hasAgentRuntime(value) {
1337
1397
  return !!value.runtime?.agent_id;
1338
1398
  }
1339
- function sourceRouteKey(source) {
1340
- return [
1341
- source.channel,
1342
- source.accountId ?? "",
1343
- source.chatId,
1344
- source.threadId ?? ""
1345
- ].join(":");
1346
- }
1347
- function sourceLifecycleKey(source) {
1348
- return [
1349
- sourceRouteKey(source),
1350
- source.messageId ?? "",
1351
- source.agentId,
1352
- source.conversationId
1353
- ].join(":");
1354
- }
1355
- function uniqueSourcesBy(sources, getKey) {
1356
- const byKey = new Map;
1357
- for (const source of sources)
1358
- byKey.set(getKey(source), source);
1359
- return [...byKey.values()];
1360
- }
1361
- function uniqueRoutedSources(sources) {
1362
- return uniqueSourcesBy(sources, sourceRouteKey);
1363
- }
1364
- function uniqueLifecycleSources(sources) {
1365
- return uniqueSourcesBy(sources, sourceLifecycleKey);
1366
- }
1367
1399
  function channelTagsForSources(sources) {
1368
1400
  return [...new Set(sources.map((source) => `channel:${source.channel}`))];
1369
1401
  }
@@ -1422,6 +1454,7 @@ class ChannelGateway {
1422
1454
  state.acceptedClientMessageIds.add(delivery.clientMessageId);
1423
1455
  return true;
1424
1456
  }
1457
+ const workAtSubmit = state.active || state.pendingSourcesByClientMessageId.size > 0;
1425
1458
  state.pendingSourcesByClientMessageId.set(delivery.clientMessageId, {
1426
1459
  sources: uniqueLifecycleSources(delivery.sources),
1427
1460
  disposition: "submitting"
@@ -1450,6 +1483,8 @@ class ChannelGateway {
1450
1483
  });
1451
1484
  if (!response.accepted) {
1452
1485
  state.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
1486
+ if (workAtSubmit && !state.active)
1487
+ this.finishRejectedDelivery(state, delivery);
1453
1488
  return false;
1454
1489
  }
1455
1490
  this.rememberAcceptedClientMessageId(state, delivery.clientMessageId);
@@ -1469,9 +1504,28 @@ class ChannelGateway {
1469
1504
  return true;
1470
1505
  } catch (error) {
1471
1506
  state.pendingSourcesByClientMessageId.delete(delivery.clientMessageId);
1507
+ if (workAtSubmit && !state.active)
1508
+ this.finishRejectedDelivery(state, delivery);
1472
1509
  throw error;
1473
1510
  }
1474
1511
  }
1512
+ remainingSources(state) {
1513
+ return uniqueLifecycleSources([
1514
+ ...state.active?.lifecycleSources ?? [],
1515
+ ...Array.from(state.pendingSourcesByClientMessageId.values()).flatMap((pending) => pending.sources)
1516
+ ]);
1517
+ }
1518
+ finishRejectedDelivery(state, delivery) {
1519
+ const remainingSources = this.remainingSources(state);
1520
+ this.enqueueHook(state, () => this.hooks.onLifecycle({
1521
+ type: "finished",
1522
+ batchId: `channel-${delivery.clientMessageId}`,
1523
+ sources: delivery.sources,
1524
+ stopReason: "cancelled",
1525
+ outcome: "cancelled",
1526
+ remainingSources
1527
+ }));
1528
+ }
1475
1529
  adoptQueuedDelivery(delivery) {
1476
1530
  const state = this.getState(delivery.runtime);
1477
1531
  const sources = uniqueLifecycleSources(delivery.sources);
@@ -1854,12 +1908,14 @@ class ChannelGateway {
1854
1908
  this.activateSources(state, firstDequeued.clientMessageId, dequeued.flatMap((entry) => entry.sources));
1855
1909
  }
1856
1910
  for (const entry of cancelled) {
1911
+ const remainingSources = this.remainingSources(state);
1857
1912
  this.enqueueHook(state, () => this.hooks.onLifecycle({
1858
1913
  type: "finished",
1859
1914
  batchId: `channel-${entry.clientMessageId}`,
1860
1915
  sources: entry.sources,
1861
1916
  outcome: "cancelled",
1862
- stopReason: "cancelled"
1917
+ stopReason: "cancelled",
1918
+ ...remainingSources.length ? { remainingSources } : {}
1863
1919
  }));
1864
1920
  }
1865
1921
  }
@@ -1936,12 +1992,14 @@ class ChannelGateway {
1936
1992
  return;
1937
1993
  state.active = null;
1938
1994
  active.richDraft?.dispose();
1995
+ const remainingSources = lifecycleOutcome(terminal.stopReason) === "completed" ? this.remainingSources(state) : [];
1939
1996
  this.enqueueHook(state, () => this.hooks.onLifecycle({
1940
1997
  type: "finished",
1941
1998
  batchId: active.batchId,
1942
1999
  sources: active.lifecycleSources,
1943
2000
  outcome: lifecycleOutcome(terminal.stopReason),
1944
2001
  stopReason: terminal.stopReason,
2002
+ ...remainingSources.length ? { remainingSources } : {},
1945
2003
  ...terminal.runId ?? active.runId ? { runId: terminal.runId ?? active.runId } : {},
1946
2004
  ...terminal.error ? { error: terminal.error } : {}
1947
2005
  }));
@@ -2692,6 +2750,38 @@ async function executeMessageChannel(input, options) {
2692
2750
  const normalized = normalizeMessageChannelInput(input, options.resolver);
2693
2751
  if (typeof normalized === "string")
2694
2752
  return normalized;
2753
+ if (normalized.action === "get-binding" || normalized.action === "update-binding") {
2754
+ if (normalized.channel !== "slack" || !options.bindings) {
2755
+ return "Error: Binding operations are not supported by this channel host.";
2756
+ }
2757
+ if (!normalized.chatId || normalized.target) {
2758
+ return "Error: Binding operations require chat_id; target is for outbound sends.";
2759
+ }
2760
+ if (input.threadId !== null && (typeof input.threadId !== "string" || !/^\d+\.\d+$/.test(input.threadId))) {
2761
+ return "Error: Binding operations require an exact threadId timestamp, or explicit null for an unthreaded DM.";
2762
+ }
2763
+ const selection = {
2764
+ channel: normalized.channel,
2765
+ accountId: normalized.accountId,
2766
+ chatId: normalized.chatId,
2767
+ threadId: input.threadId
2768
+ };
2769
+ try {
2770
+ if (normalized.action === "get-binding") {
2771
+ return JSON.stringify(await options.bindings.get(selection, options.scope));
2772
+ }
2773
+ const conversationId = firstNonEmptyString2(input.conversationId);
2774
+ const expectedConversationId = firstNonEmptyString2(input.expectedConversationId);
2775
+ if (!conversationId || !expectedConversationId) {
2776
+ return "Error: update-binding requires conversationId and expectedConversationId.";
2777
+ }
2778
+ const result = await options.bindings.update({ ...selection, conversationId, expectedConversationId }, options.scope);
2779
+ const prefix = result.status === "conflict" || result.status === "not-found" ? "Error: " : "";
2780
+ return `${prefix}${JSON.stringify(result)}`;
2781
+ } catch (error) {
2782
+ return `Error: Binding operation failed: ${error instanceof Error ? error.message : "unknown error"}`;
2783
+ }
2784
+ }
2695
2785
  if (normalized.channel === "slack" && normalized.action === "download-file" && normalized.target) {
2696
2786
  return "Error: Slack download-file requires chat_id from a routed channel context; target is not supported.";
2697
2787
  }
@@ -2706,6 +2796,7 @@ async function executeMessageChannel(input, options) {
2706
2796
  channel: normalized.channel,
2707
2797
  chatId: normalized.chatId,
2708
2798
  accountId,
2799
+ ...normalized.threadId !== null ? { threadId: normalized.threadId } : {},
2709
2800
  scope: options.scope
2710
2801
  });
2711
2802
  if (typeof context2 === "string")
@@ -2959,7 +3050,9 @@ Replies to routed Telegram topics stay in the current topic automatically.` : ""
2959
3050
  hasAction("react") ? 'action="react" with emoji + messageId' : "",
2960
3051
  hasAction("list-custom-emojis") ? 'action="list-custom-emojis" to discover the workspace custom emoji names available for reactions' : "",
2961
3052
  hasAction("upload-file") ? 'action="upload-file" with media' : "",
2962
- hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : ""
3053
+ hasAction("download-file") ? 'action="download-file" with attachmentId + messageId' : "",
3054
+ hasAction("get-binding") ? 'action="get-binding" with chat_id and an explicit threadId (null for an unthreaded DM) to inspect the persisted incoming-message destination without sending' : "",
3055
+ hasAction("update-binding") ? 'action="update-binding" with the same exact thread, conversationId, and expectedConversationId to reassign an existing binding within this agent. It does not send a message, copy history, move queued inputs, change computers, or alter pause/detach settings. Outbound sends never take over an existing binding' : ""
2963
3056
  ].filter(Boolean) : [];
2964
3057
  const slackCapabilityGuidance = slackCapabilities.length > 0 ? `
2965
3058
 
@@ -3010,4 +3103,4 @@ export {
3010
3103
  ChannelControlRequestCoordinator
3011
3104
  };
3012
3105
 
3013
- //# debugId=C71F91C15DBDCC8264756E2164756E21
3106
+ //# debugId=4672AE632A7F690464756E2164756E21