@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.
- package/README.md +6 -0
- package/dist/agent-presets.js +25 -1
- package/dist/agent-presets.js.map +2 -2
- package/dist/channels-public.js +32 -2
- package/dist/channels-public.js.map +3 -3
- package/dist/channels-slack.js +100 -4
- package/dist/channels-slack.js.map +7 -6
- package/dist/gateway-core.js +125 -32
- package/dist/gateway-core.js.map +8 -7
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/memory-constraints.js +77 -1
- package/dist/memory-constraints.js.map +5 -4
- package/dist/types/agent/memory-git-hooks.d.ts +1 -1
- package/dist/types/agent/memory-git-hooks.d.ts.map +1 -1
- package/dist/types/agent/skills.d.ts.map +1 -1
- package/dist/types/agent/subagents/manager.d.ts.map +1 -1
- package/dist/types/backend/backend.d.ts +0 -1
- package/dist/types/backend/backend.d.ts.map +1 -1
- package/dist/types/backend/dev/fake-headless-backend.d.ts.map +1 -1
- package/dist/types/channels/gateway-core.d.ts +2 -0
- package/dist/types/channels/gateway-core.d.ts.map +1 -1
- package/dist/types/channels/gateway-sources.d.ts +6 -0
- package/dist/types/channels/gateway-sources.d.ts.map +1 -0
- package/dist/types/channels/message-channel-bindings.d.ts +39 -0
- package/dist/types/channels/message-channel-bindings.d.ts.map +1 -0
- package/dist/types/channels/message-channel-executor.d.ts +4 -0
- package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
- package/dist/types/channels/message-channel-tool-definition.d.ts.map +1 -1
- package/dist/types/channels/message-channel-types.d.ts +3 -1
- package/dist/types/channels/message-channel-types.d.ts.map +1 -1
- package/dist/types/channels/plugin-types.d.ts +9 -1
- package/dist/types/channels/plugin-types.d.ts.map +1 -1
- package/dist/types/channels/progress-builder.d.ts +1 -1
- package/dist/types/channels/progress-builder.d.ts.map +1 -1
- package/dist/types/channels/progress-types.d.ts +28 -0
- package/dist/types/channels/progress-types.d.ts.map +1 -0
- package/dist/types/channels/slack/message-action-contract.d.ts +2 -0
- package/dist/types/channels/slack/message-action-contract.d.ts.map +1 -1
- package/dist/types/channels/slack/progress.d.ts.map +1 -1
- package/dist/types/channels/slack/status-controller.d.ts +2 -1
- package/dist/types/channels/slack/status-controller.d.ts.map +1 -1
- package/dist/types/channels/types.d.ts +6 -23
- package/dist/types/channels/types.d.ts.map +1 -1
- package/dist/types/cli/helpers/app-urls.d.ts +0 -4
- package/dist/types/cli/helpers/app-urls.d.ts.map +1 -1
- package/dist/types/cli/helpers/error-formatter.d.ts.map +1 -1
- package/dist/types/gateway-core.d.ts +1 -0
- package/dist/types/gateway-core.d.ts.map +1 -1
- package/dist/types/memory-constraints.d.ts +1 -0
- package/dist/types/memory-constraints.d.ts.map +1 -1
- package/dist/types/memory-frontmatter.d.ts +18 -0
- package/dist/types/memory-frontmatter.d.ts.map +1 -0
- package/dist/types/tools/letta-toolset.d.ts +10 -0
- package/dist/types/tools/letta-toolset.d.ts.map +1 -0
- package/dist/types/tools/toolset-options.d.ts +4 -0
- package/dist/types/tools/toolset-options.d.ts.map +1 -0
- package/dist/types/tools/toolset-types.d.ts +1 -2
- package/dist/types/tools/toolset-types.d.ts.map +1 -1
- package/dist/types/tools/toolset.d.ts.map +1 -1
- package/dist/types/types/protocol_v2.d.ts +3 -2
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/dist/types/types/toolset-protocol.d.ts +10 -0
- package/dist/types/types/toolset-protocol.d.ts.map +1 -0
- package/dist/types/websocket/listener/device-toolset-status.d.ts +6 -0
- package/dist/types/websocket/listener/device-toolset-status.d.ts.map +1 -0
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/letta.js +968 -1482
- package/package.json +2 -1
- package/scripts/source-file-size-baseline.json +6 -6
- package/skills/image-generation/SKILL.md +5 -4
- package/skills/self-configuration/SKILL.md +1 -1
- package/skills/working-across-computers/SKILL.md +88 -0
- package/skills/teleporting-between-environments/SKILL.md +0 -114
package/dist/gateway-core.js
CHANGED
|
@@ -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 {
|
|
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=
|
|
3106
|
+
//# debugId=4672AE632A7F690464756E2164756E21
|