@letta-ai/letta-code 0.30.10 → 0.30.11
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/dist/channels-public.js +411 -2
- package/dist/channels-public.js.map +6 -3
- package/dist/channels-slack.js +209 -11
- package/dist/channels-slack.js.map +6 -5
- package/dist/gateway-core.js +110 -13
- package/dist/gateway-core.js.map +6 -5
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/schedules.js +4 -2
- package/dist/schedules.js.map +3 -3
- package/dist/types/agent/client-skills.d.ts +2 -0
- package/dist/types/agent/client-skills.d.ts.map +1 -1
- package/dist/types/agent/message.d.ts.map +1 -1
- package/dist/types/backend/local/local-store.d.ts.map +1 -1
- package/dist/types/channels/command-surface.d.ts +54 -0
- package/dist/types/channels/command-surface.d.ts.map +1 -0
- package/dist/types/channels/gateway-core.d.ts +2 -1
- package/dist/types/channels/gateway-core.d.ts.map +1 -1
- package/dist/types/channels/message-channel-executor.d.ts +2 -0
- package/dist/types/channels/message-channel-executor.d.ts.map +1 -1
- package/dist/types/channels/message-channel-idempotency.d.ts +13 -0
- package/dist/types/channels/message-channel-idempotency.d.ts.map +1 -0
- package/dist/types/channels-public.d.ts +4 -0
- package/dist/types/channels-public.d.ts.map +1 -1
- package/dist/types/channels-slack.d.ts +1 -0
- package/dist/types/channels-slack.d.ts.map +1 -1
- package/dist/types/cron/scheduled-task-prompt.d.ts +7 -0
- package/dist/types/cron/scheduled-task-prompt.d.ts.map +1 -1
- package/dist/types/schedules.d.ts +1 -1
- package/dist/types/schedules.d.ts.map +1 -1
- package/dist/types/websocket/listener/runtime.d.ts.map +1 -1
- package/dist/types/websocket/listener/types.d.ts +2 -1
- package/dist/types/websocket/listener/types.d.ts.map +1 -1
- package/letta.js +388 -226
- package/package.json +1 -1
- package/scripts/source-file-size-baseline.json +1 -1
package/letta.js
CHANGED
|
@@ -5476,7 +5476,7 @@ var package_default;
|
|
|
5476
5476
|
var init_package = __esm(() => {
|
|
5477
5477
|
package_default = {
|
|
5478
5478
|
name: "@letta-ai/letta-code",
|
|
5479
|
-
version: "0.30.
|
|
5479
|
+
version: "0.30.11",
|
|
5480
5480
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5481
5481
|
type: "module",
|
|
5482
5482
|
packageManager: "bun@1.3.0",
|
|
@@ -152976,6 +152976,7 @@ function createConversationRuntime(listener, agentId, conversationId) {
|
|
|
152976
152976
|
currentToolset: null,
|
|
152977
152977
|
currentToolsetPreference: "auto",
|
|
152978
152978
|
currentLoadedTools: [],
|
|
152979
|
+
currentAvailableSkills: [],
|
|
152979
152980
|
pendingApprovalBatchByToolCallId: new Map,
|
|
152980
152981
|
approvalMessageIdByToolCallId: new Map,
|
|
152981
152982
|
pendingInterruptedResults: null,
|
|
@@ -157473,6 +157474,7 @@ function getSkillRootRevisions(components) {
|
|
|
157473
157474
|
function cloneResult(result) {
|
|
157474
157475
|
return {
|
|
157475
157476
|
clientSkills: result.clientSkills.map((s2) => ({ ...s2 })),
|
|
157477
|
+
availableSkills: result.availableSkills.map((skill) => ({ ...skill })),
|
|
157476
157478
|
skillPathById: { ...result.skillPathById },
|
|
157477
157479
|
errors: result.errors.map((e2) => ({ ...e2 }))
|
|
157478
157480
|
};
|
|
@@ -157657,6 +157659,13 @@ async function buildClientSkillsPayload(options3 = {}) {
|
|
|
157657
157659
|
}
|
|
157658
157660
|
const result = {
|
|
157659
157661
|
clientSkills: sortedSkills.map(toClientSkill),
|
|
157662
|
+
availableSkills: sortedSkills.map((skill) => ({
|
|
157663
|
+
id: skill.id,
|
|
157664
|
+
name: skill.name,
|
|
157665
|
+
description: skill.description,
|
|
157666
|
+
path: skill.path,
|
|
157667
|
+
source: skill.source
|
|
157668
|
+
})),
|
|
157660
157669
|
skillPathById: Object.fromEntries(sortedSkills.filter((skill) => typeof skill.path === "string" && skill.path.length > 0).map((skill) => [skill.id, skill.path])),
|
|
157661
157670
|
errors: errors7
|
|
157662
157671
|
};
|
|
@@ -157798,6 +157807,7 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
|
|
|
157798
157807
|
const { clientTools, contextId } = preparedToolContext;
|
|
157799
157808
|
const { clientSkills, errors: clientSkillDiscoveryErrors } = await buildClientSkillsPayload({
|
|
157800
157809
|
agentId: opts.agentId,
|
|
157810
|
+
skillsDirectory: getExecutionContextById(preparedToolContext.contextId)?.runtimeContext.skillsDirectory,
|
|
157801
157811
|
skillSources: opts.skillSources ?? getSkillSources()
|
|
157802
157812
|
});
|
|
157803
157813
|
const resolvedConversationId = conversationId;
|
|
@@ -330261,7 +330271,7 @@ function buildDeviceStatus(runtime, params) {
|
|
|
330261
330271
|
current_toolset: conversationRuntime?.currentToolset ?? (toolsetPreference === "auto" ? null : toolsetPreference),
|
|
330262
330272
|
current_toolset_preference: conversationRuntime?.currentToolsetPreference ?? toolsetPreference,
|
|
330263
330273
|
current_loaded_tools: conversationRuntime?.currentLoadedTools ?? [],
|
|
330264
|
-
current_available_skills: [],
|
|
330274
|
+
current_available_skills: conversationRuntime?.currentAvailableSkills ?? [],
|
|
330265
330275
|
background_processes: buildBackgroundProcessSnapshot(scopedAgentId, scopedConversationId),
|
|
330266
330276
|
pending_control_requests: interruptedCacheActive ? [] : getPendingControlRequests(listener, scope),
|
|
330267
330277
|
experiments: experimentManager.list(),
|
|
@@ -356536,7 +356546,8 @@ function createLocalConversationRecord(conversationId, agentId, _sequence, body
|
|
|
356536
356546
|
} : {},
|
|
356537
356547
|
...modelSettings !== undefined ? { model_settings: modelSettings } : {},
|
|
356538
356548
|
...typeof bodyRecord.context_window_limit === "number" ? { context_window_limit: bodyRecord.context_window_limit } : {},
|
|
356539
|
-
...typeof bodyRecord.hidden === "boolean" ? { hidden: bodyRecord.hidden } : {}
|
|
356549
|
+
...typeof bodyRecord.hidden === "boolean" ? { hidden: bodyRecord.hidden } : {},
|
|
356550
|
+
...isStringArray2(bodyRecord.tags) ? { tags: bodyRecord.tags } : {}
|
|
356540
356551
|
};
|
|
356541
356552
|
}
|
|
356542
356553
|
function updateLocalConversationRecord(current, body, updatedAt) {
|
|
@@ -411956,6 +411967,217 @@ var init_access_control = __esm(() => {
|
|
|
411956
411967
|
CHANNEL_COMMAND_FLOOR = ["help", "status", "whoami"];
|
|
411957
411968
|
});
|
|
411958
411969
|
|
|
411970
|
+
// src/channels/command-surface.ts
|
|
411971
|
+
function defaultChannelDisplayName(channelId) {
|
|
411972
|
+
return DEFAULT_CHANNEL_DISPLAY_NAMES[channelId] ?? channelId;
|
|
411973
|
+
}
|
|
411974
|
+
function listChannelSlashCommands() {
|
|
411975
|
+
return CHANNEL_SLASH_COMMANDS.map((definition) => ({
|
|
411976
|
+
...definition,
|
|
411977
|
+
aliases: definition.aliases ? [...definition.aliases] : undefined
|
|
411978
|
+
}));
|
|
411979
|
+
}
|
|
411980
|
+
function parseSingleLineChannelCommand(text2, prefix) {
|
|
411981
|
+
const trimmed = text2.trim();
|
|
411982
|
+
const escapedPrefix = prefix === "/" ? "\\/" : "!";
|
|
411983
|
+
const match4 = trimmed.match(new RegExp(`^${escapedPrefix}([A-Za-z][\\w-]*)(?:@[A-Za-z0-9_]+)?(?:[^\\S\\r\\n]+(.*))?$`));
|
|
411984
|
+
if (!match4) {
|
|
411985
|
+
return null;
|
|
411986
|
+
}
|
|
411987
|
+
const [, name, args] = match4;
|
|
411988
|
+
if (!name) {
|
|
411989
|
+
return null;
|
|
411990
|
+
}
|
|
411991
|
+
return {
|
|
411992
|
+
name: name.toLowerCase(),
|
|
411993
|
+
args: args?.trim() ?? "",
|
|
411994
|
+
raw: trimmed
|
|
411995
|
+
};
|
|
411996
|
+
}
|
|
411997
|
+
function parseAnySingleLineChannelCommand(text2) {
|
|
411998
|
+
return parseSingleLineChannelCommand(text2, "/") ?? parseSingleLineChannelCommand(text2, "!");
|
|
411999
|
+
}
|
|
412000
|
+
function parseChannelCommand(text2, prefix) {
|
|
412001
|
+
const lines = text2.trim().split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
412002
|
+
const [firstLine, ...remainingLines] = lines;
|
|
412003
|
+
if (!firstLine) {
|
|
412004
|
+
return null;
|
|
412005
|
+
}
|
|
412006
|
+
const firstCommand = parseSingleLineChannelCommand(firstLine, prefix);
|
|
412007
|
+
if (!firstCommand) {
|
|
412008
|
+
return null;
|
|
412009
|
+
}
|
|
412010
|
+
const laterCommand = remainingLines.find((line) => Boolean(parseAnySingleLineChannelCommand(line)));
|
|
412011
|
+
if (laterCommand) {
|
|
412012
|
+
return firstCommand;
|
|
412013
|
+
}
|
|
412014
|
+
const continuationArgs = remainingLines.join(`
|
|
412015
|
+
`).trim();
|
|
412016
|
+
if (!continuationArgs) {
|
|
412017
|
+
return firstCommand;
|
|
412018
|
+
}
|
|
412019
|
+
return {
|
|
412020
|
+
...firstCommand,
|
|
412021
|
+
args: [firstCommand.args, continuationArgs].filter((part) => part.length > 0).join(`
|
|
412022
|
+
`)
|
|
412023
|
+
};
|
|
412024
|
+
}
|
|
412025
|
+
function parseChannelSlashCommand(text2) {
|
|
412026
|
+
return parseChannelCommand(text2, "/");
|
|
412027
|
+
}
|
|
412028
|
+
function parseChannelBangCommand(text2) {
|
|
412029
|
+
return parseChannelCommand(text2, "!");
|
|
412030
|
+
}
|
|
412031
|
+
function supportedCommandsText(prefix = "/") {
|
|
412032
|
+
return listChannelSlashCommands().map((definition) => `${prefix}${definition.name}`).join(", ");
|
|
412033
|
+
}
|
|
412034
|
+
function supportedSlackMentionSlashCommandsText() {
|
|
412035
|
+
return SLACK_MENTION_SLASH_COMMAND_EXAMPLES.join(", ");
|
|
412036
|
+
}
|
|
412037
|
+
function supportedBangCommandsText() {
|
|
412038
|
+
return SLACK_MENTION_COMMAND_NAMES.map((name) => `!${name}`).join(", ");
|
|
412039
|
+
}
|
|
412040
|
+
function isSupportedSlackMentionCommand(commandName) {
|
|
412041
|
+
return SLACK_MENTION_COMMAND_NAMES.includes(commandName);
|
|
412042
|
+
}
|
|
412043
|
+
function buildChannelHelpMessage(channelId, resolveDisplayName = defaultChannelDisplayName) {
|
|
412044
|
+
const displayName = resolveDisplayName(channelId);
|
|
412045
|
+
if (channelId === "slack") {
|
|
412046
|
+
return [
|
|
412047
|
+
`${displayName} is connected to Letta Code.`,
|
|
412048
|
+
"Talk by mentioning the app in a channel thread. Once a thread is routed, normal replies continue the same agent conversation until detached.",
|
|
412049
|
+
"Control commands start immediately after the mention:",
|
|
412050
|
+
"@agent /model - show this thread's current model",
|
|
412051
|
+
"@agent /model list - show available models",
|
|
412052
|
+
"@agent /model <handle-or-id> - switch this thread's model",
|
|
412053
|
+
"@agent /status - show route and listener status",
|
|
412054
|
+
"@agent /cancel - cancel the current turn",
|
|
412055
|
+
"@agent /chat - show the web chat link",
|
|
412056
|
+
"@agent /feedback <message> - send feedback to the Letta team from this routed thread",
|
|
412057
|
+
"@agent /reflection - start a memory reflection pass",
|
|
412058
|
+
"@agent /detach - stop replying in this thread until mentioned again",
|
|
412059
|
+
"@agent /new - start a fresh conversation for this thread",
|
|
412060
|
+
"@agent /reload - reload settings, local mods, and agent secrets",
|
|
412061
|
+
`Legacy bang aliases still work after a mention: ${supportedBangCommandsText()}.`,
|
|
412062
|
+
"If this chat is not connected yet, send a normal message and follow the pairing instructions."
|
|
412063
|
+
].join(`
|
|
412064
|
+
`);
|
|
412065
|
+
}
|
|
412066
|
+
return [
|
|
412067
|
+
`${displayName} is connected to Letta Code.`,
|
|
412068
|
+
"Send a normal message here and the connected agent will reply in this chat.",
|
|
412069
|
+
`Supported slash commands here: ${supportedCommandsText()}.`,
|
|
412070
|
+
"If this chat is not connected yet, send any non-command message and follow the pairing instructions."
|
|
412071
|
+
].join(`
|
|
412072
|
+
|
|
412073
|
+
`);
|
|
412074
|
+
}
|
|
412075
|
+
function buildUnsupportedChannelCommandMessage(channelId, command, resolveDisplayName = defaultChannelDisplayName) {
|
|
412076
|
+
const displayName = resolveDisplayName(channelId);
|
|
412077
|
+
const isBang = command.raw.startsWith("!");
|
|
412078
|
+
const commandKind = isBang ? "bang" : "slash";
|
|
412079
|
+
const supportedCommands = isBang ? supportedBangCommandsText() : channelId === "slack" ? supportedSlackMentionSlashCommandsText() : supportedCommandsText();
|
|
412080
|
+
const supportedLabel = channelId === "slack" && !isBang ? "Slack mention commands" : `${commandKind} commands`;
|
|
412081
|
+
return [
|
|
412082
|
+
`${displayName} received ${command.raw}, but that ${commandKind} command is not supported in channels yet.`,
|
|
412083
|
+
`Supported ${supportedLabel}: ${supportedCommands}.`,
|
|
412084
|
+
`Send normal messages without a leading ${isBang ? "bang" : "slash"} command to talk to the connected agent.`
|
|
412085
|
+
].join(`
|
|
412086
|
+
|
|
412087
|
+
`);
|
|
412088
|
+
}
|
|
412089
|
+
var DEFAULT_CHANNEL_DISPLAY_NAMES, CHANNEL_SLASH_COMMANDS, SLACK_MENTION_COMMAND_NAMES, SLACK_MENTION_SLASH_COMMAND_EXAMPLES;
|
|
412090
|
+
var init_command_surface = __esm(() => {
|
|
412091
|
+
DEFAULT_CHANNEL_DISPLAY_NAMES = {
|
|
412092
|
+
custom: "Custom",
|
|
412093
|
+
discord: "Discord",
|
|
412094
|
+
signal: "Signal",
|
|
412095
|
+
slack: "Slack",
|
|
412096
|
+
telegram: "Telegram",
|
|
412097
|
+
whatsapp: "WhatsApp"
|
|
412098
|
+
};
|
|
412099
|
+
CHANNEL_SLASH_COMMANDS = [
|
|
412100
|
+
{
|
|
412101
|
+
name: "help",
|
|
412102
|
+
kind: "direct",
|
|
412103
|
+
summary: "Show channel usage guidance."
|
|
412104
|
+
},
|
|
412105
|
+
{
|
|
412106
|
+
name: "status",
|
|
412107
|
+
kind: "direct",
|
|
412108
|
+
summary: "Show this chat's channel connection status."
|
|
412109
|
+
},
|
|
412110
|
+
{
|
|
412111
|
+
name: "whoami",
|
|
412112
|
+
kind: "direct",
|
|
412113
|
+
summary: "Show your access tier and runnable commands here."
|
|
412114
|
+
},
|
|
412115
|
+
{
|
|
412116
|
+
name: "pause",
|
|
412117
|
+
kind: "direct",
|
|
412118
|
+
summary: "Pause agent routing for this chat."
|
|
412119
|
+
},
|
|
412120
|
+
{
|
|
412121
|
+
name: "resume",
|
|
412122
|
+
kind: "direct",
|
|
412123
|
+
summary: "Resume agent routing for this chat."
|
|
412124
|
+
},
|
|
412125
|
+
{
|
|
412126
|
+
name: "cancel",
|
|
412127
|
+
kind: "agent-scoped",
|
|
412128
|
+
summary: "Cancel the in-progress agent turn for this chat."
|
|
412129
|
+
},
|
|
412130
|
+
{
|
|
412131
|
+
name: "chat",
|
|
412132
|
+
kind: "direct",
|
|
412133
|
+
summary: "Show the Letta web chat link for this channel route."
|
|
412134
|
+
},
|
|
412135
|
+
{
|
|
412136
|
+
name: "feedback",
|
|
412137
|
+
kind: "direct",
|
|
412138
|
+
summary: "Send feedback about Letta Code from this routed chat."
|
|
412139
|
+
},
|
|
412140
|
+
{
|
|
412141
|
+
name: "model",
|
|
412142
|
+
kind: "agent-scoped",
|
|
412143
|
+
summary: "Show, list, or switch the model for this chat's routed conversation."
|
|
412144
|
+
},
|
|
412145
|
+
{
|
|
412146
|
+
name: "reflection",
|
|
412147
|
+
aliases: ["reflect"],
|
|
412148
|
+
kind: "agent-scoped",
|
|
412149
|
+
summary: "Start a memory reflection pass for this conversation."
|
|
412150
|
+
},
|
|
412151
|
+
{
|
|
412152
|
+
name: "reload",
|
|
412153
|
+
kind: "agent-scoped",
|
|
412154
|
+
summary: "Reload settings, local mods, and agent secrets."
|
|
412155
|
+
}
|
|
412156
|
+
];
|
|
412157
|
+
SLACK_MENTION_COMMAND_NAMES = [
|
|
412158
|
+
"help",
|
|
412159
|
+
"detach",
|
|
412160
|
+
"model",
|
|
412161
|
+
"new",
|
|
412162
|
+
"reload"
|
|
412163
|
+
];
|
|
412164
|
+
SLACK_MENTION_SLASH_COMMAND_EXAMPLES = [
|
|
412165
|
+
"@agent /help",
|
|
412166
|
+
"@agent /status",
|
|
412167
|
+
"@agent /whoami",
|
|
412168
|
+
"@agent /model",
|
|
412169
|
+
"@agent /model list",
|
|
412170
|
+
"@agent /model <handle-or-id>",
|
|
412171
|
+
"@agent /cancel",
|
|
412172
|
+
"@agent /chat",
|
|
412173
|
+
"@agent /feedback <message>",
|
|
412174
|
+
"@agent /reflection",
|
|
412175
|
+
"@agent /detach",
|
|
412176
|
+
"@agent /new",
|
|
412177
|
+
"@agent /reload"
|
|
412178
|
+
];
|
|
412179
|
+
});
|
|
412180
|
+
|
|
411959
412181
|
// src/channels/feedback.ts
|
|
411960
412182
|
function channelDisplayName2(channelId) {
|
|
411961
412183
|
try {
|
|
@@ -412224,126 +412446,17 @@ function channelDisplayName4(channelId) {
|
|
|
412224
412446
|
return channelId;
|
|
412225
412447
|
}
|
|
412226
412448
|
}
|
|
412227
|
-
function listChannelSlashCommands() {
|
|
412228
|
-
return CHANNEL_SLASH_COMMANDS.map((definition) => ({
|
|
412229
|
-
...definition,
|
|
412230
|
-
aliases: definition.aliases ? [...definition.aliases] : undefined
|
|
412231
|
-
}));
|
|
412232
|
-
}
|
|
412233
|
-
function parseSingleLineChannelCommand(text2, prefix) {
|
|
412234
|
-
const trimmed = text2.trim();
|
|
412235
|
-
const escapedPrefix = prefix === "/" ? "\\/" : "!";
|
|
412236
|
-
const match4 = trimmed.match(new RegExp(`^${escapedPrefix}([A-Za-z][\\w-]*)(?:@[A-Za-z0-9_]+)?(?:[^\\S\\r\\n]+(.*))?$`));
|
|
412237
|
-
if (!match4) {
|
|
412238
|
-
return null;
|
|
412239
|
-
}
|
|
412240
|
-
const [, name, args] = match4;
|
|
412241
|
-
if (!name) {
|
|
412242
|
-
return null;
|
|
412243
|
-
}
|
|
412244
|
-
return {
|
|
412245
|
-
name: name.toLowerCase(),
|
|
412246
|
-
args: args?.trim() ?? "",
|
|
412247
|
-
raw: trimmed
|
|
412248
|
-
};
|
|
412249
|
-
}
|
|
412250
|
-
function parseAnySingleLineChannelCommand(text2) {
|
|
412251
|
-
return parseSingleLineChannelCommand(text2, "/") ?? parseSingleLineChannelCommand(text2, "!");
|
|
412252
|
-
}
|
|
412253
|
-
function parseChannelCommand(text2, prefix) {
|
|
412254
|
-
const lines = text2.trim().split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
412255
|
-
const [firstLine, ...remainingLines] = lines;
|
|
412256
|
-
if (!firstLine) {
|
|
412257
|
-
return null;
|
|
412258
|
-
}
|
|
412259
|
-
const firstCommand = parseSingleLineChannelCommand(firstLine, prefix);
|
|
412260
|
-
if (!firstCommand) {
|
|
412261
|
-
return null;
|
|
412262
|
-
}
|
|
412263
|
-
const laterCommand = remainingLines.find((line) => Boolean(parseAnySingleLineChannelCommand(line)));
|
|
412264
|
-
if (laterCommand) {
|
|
412265
|
-
return firstCommand;
|
|
412266
|
-
}
|
|
412267
|
-
const continuationArgs = remainingLines.join(`
|
|
412268
|
-
`).trim();
|
|
412269
|
-
if (!continuationArgs) {
|
|
412270
|
-
return firstCommand;
|
|
412271
|
-
}
|
|
412272
|
-
return {
|
|
412273
|
-
...firstCommand,
|
|
412274
|
-
args: [firstCommand.args, continuationArgs].filter((part) => part.length > 0).join(`
|
|
412275
|
-
`)
|
|
412276
|
-
};
|
|
412277
|
-
}
|
|
412278
|
-
function parseChannelSlashCommand(text2) {
|
|
412279
|
-
return parseChannelCommand(text2, "/");
|
|
412280
|
-
}
|
|
412281
|
-
function parseChannelBangCommand(text2) {
|
|
412282
|
-
return parseChannelCommand(text2, "!");
|
|
412283
|
-
}
|
|
412284
|
-
function supportedCommandsText(prefix = "/") {
|
|
412285
|
-
return listChannelSlashCommands().map((definition) => `${prefix}${definition.name}`).join(", ");
|
|
412286
|
-
}
|
|
412287
|
-
function supportedSlackMentionSlashCommandsText() {
|
|
412288
|
-
return SLACK_MENTION_SLASH_COMMAND_EXAMPLES.join(", ");
|
|
412289
|
-
}
|
|
412290
|
-
function supportedBangCommandsText() {
|
|
412291
|
-
return SLACK_MENTION_COMMAND_NAMES.map((name) => `!${name}`).join(", ");
|
|
412292
|
-
}
|
|
412293
|
-
function isSupportedSlackMentionCommand(commandName) {
|
|
412294
|
-
return SLACK_MENTION_COMMAND_NAMES.includes(commandName);
|
|
412295
|
-
}
|
|
412296
412449
|
function isSlackMentionSlashCommand(msg, command) {
|
|
412297
412450
|
return msg.channel === "slack" && msg.isMention === true && command.raw.startsWith("/");
|
|
412298
412451
|
}
|
|
412299
412452
|
function isSlackMentionControlCommand(msg, command) {
|
|
412300
412453
|
return command.raw.startsWith("!") || isSlackMentionSlashCommand(msg, command);
|
|
412301
412454
|
}
|
|
412302
|
-
function
|
|
412303
|
-
|
|
412304
|
-
if (channelId === "slack") {
|
|
412305
|
-
return [
|
|
412306
|
-
`${displayName} is connected to Letta Code.`,
|
|
412307
|
-
"Talk by mentioning the app in a channel thread. Once a thread is routed, normal replies continue the same agent conversation until detached.",
|
|
412308
|
-
"Control commands start immediately after the mention:",
|
|
412309
|
-
"@agent /model - show this thread's current model",
|
|
412310
|
-
"@agent /model list - show available models",
|
|
412311
|
-
"@agent /model <handle-or-id> - switch this thread's model",
|
|
412312
|
-
"@agent /status - show route and listener status",
|
|
412313
|
-
"@agent /cancel - cancel the current turn",
|
|
412314
|
-
"@agent /chat - show the web chat link",
|
|
412315
|
-
"@agent /feedback <message> - send feedback to the Letta team from this routed thread",
|
|
412316
|
-
"@agent /reflection - start a memory reflection pass",
|
|
412317
|
-
"@agent /detach - stop replying in this thread until mentioned again",
|
|
412318
|
-
"@agent /new - start a fresh conversation for this thread",
|
|
412319
|
-
"@agent /reload - reload settings, local mods, and agent secrets",
|
|
412320
|
-
`Legacy bang aliases still work after a mention: ${supportedBangCommandsText()}.`,
|
|
412321
|
-
"If this chat is not connected yet, send a normal message and follow the pairing instructions."
|
|
412322
|
-
].join(`
|
|
412323
|
-
`);
|
|
412324
|
-
}
|
|
412325
|
-
return [
|
|
412326
|
-
`${displayName} is connected to Letta Code.`,
|
|
412327
|
-
"Send a normal message here and the connected agent will reply in this chat.",
|
|
412328
|
-
`Supported slash commands here: ${supportedCommandsText()}.`,
|
|
412329
|
-
"If this chat is not connected yet, send any non-command message and follow the pairing instructions."
|
|
412330
|
-
].join(`
|
|
412331
|
-
|
|
412332
|
-
`);
|
|
412455
|
+
function buildChannelHelpMessage2(channelId) {
|
|
412456
|
+
return buildChannelHelpMessage(channelId, channelDisplayName4);
|
|
412333
412457
|
}
|
|
412334
|
-
function
|
|
412335
|
-
|
|
412336
|
-
const isBang = command.raw.startsWith("!");
|
|
412337
|
-
const commandKind = isBang ? "bang" : "slash";
|
|
412338
|
-
const supportedCommands = isBang ? supportedBangCommandsText() : channelId === "slack" ? supportedSlackMentionSlashCommandsText() : supportedCommandsText();
|
|
412339
|
-
const supportedLabel = channelId === "slack" && !isBang ? "Slack mention commands" : `${commandKind} commands`;
|
|
412340
|
-
return [
|
|
412341
|
-
`${displayName} received ${command.raw}, but that ${commandKind} command is not supported in channels yet.`,
|
|
412342
|
-
`Supported ${supportedLabel}: ${supportedCommands}.`,
|
|
412343
|
-
`Send normal messages without a leading ${isBang ? "bang" : "slash"} command to talk to the connected agent.`
|
|
412344
|
-
].join(`
|
|
412345
|
-
|
|
412346
|
-
`);
|
|
412458
|
+
function buildUnsupportedChannelCommandMessage2(channelId, command) {
|
|
412459
|
+
return buildUnsupportedChannelCommandMessage(channelId, command, channelDisplayName4);
|
|
412347
412460
|
}
|
|
412348
412461
|
function buildChannelStatusMessage(msg, context3) {
|
|
412349
412462
|
const displayName = channelDisplayName4(msg.channel);
|
|
@@ -412622,7 +412735,7 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412622
412735
|
const isBangCommand = command.raw.startsWith("!");
|
|
412623
412736
|
const isSlackMentionControl = isSlackMentionControlCommand(msg, command);
|
|
412624
412737
|
if (isBangCommand && !isSupportedSlackMentionCommand(command.name)) {
|
|
412625
|
-
await adapter.sendDirectReply(msg.chatId,
|
|
412738
|
+
await adapter.sendDirectReply(msg.chatId, buildUnsupportedChannelCommandMessage2(msg.channel, command), buildDirectReplyOptions(msg));
|
|
412626
412739
|
return true;
|
|
412627
412740
|
}
|
|
412628
412741
|
const canonicalName = canonicalizeChannelCommandName(command.name);
|
|
@@ -412633,7 +412746,7 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412633
412746
|
const reply = normalizeDirectReplyPayload(await (async () => {
|
|
412634
412747
|
switch (command.name) {
|
|
412635
412748
|
case "help":
|
|
412636
|
-
return
|
|
412749
|
+
return buildChannelHelpMessage2(msg.channel);
|
|
412637
412750
|
case "whoami":
|
|
412638
412751
|
return buildChannelWhoamiMessage(msg, options3.commandGate);
|
|
412639
412752
|
case "status":
|
|
@@ -412675,7 +412788,7 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412675
412788
|
});
|
|
412676
412789
|
case "detach":
|
|
412677
412790
|
if (!isSlackMentionControl) {
|
|
412678
|
-
return
|
|
412791
|
+
return buildUnsupportedChannelCommandMessage2(msg.channel, command);
|
|
412679
412792
|
}
|
|
412680
412793
|
return handleScopedCommand({
|
|
412681
412794
|
msg,
|
|
@@ -412690,7 +412803,7 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412690
412803
|
});
|
|
412691
412804
|
case "new":
|
|
412692
412805
|
if (!isSlackMentionControl) {
|
|
412693
|
-
return
|
|
412806
|
+
return buildUnsupportedChannelCommandMessage2(msg.channel, command);
|
|
412694
412807
|
}
|
|
412695
412808
|
return handleScopedCommand({
|
|
412696
412809
|
msg,
|
|
@@ -412711,7 +412824,7 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412711
412824
|
handler: options3.handlers?.reload
|
|
412712
412825
|
});
|
|
412713
412826
|
default:
|
|
412714
|
-
return
|
|
412827
|
+
return buildUnsupportedChannelCommandMessage2(msg.channel, command);
|
|
412715
412828
|
}
|
|
412716
412829
|
})());
|
|
412717
412830
|
if (reply === null) {
|
|
@@ -412724,92 +412837,14 @@ async function tryHandleChannelSlashCommand(adapter, msg, options3 = {}) {
|
|
|
412724
412837
|
} : undefined);
|
|
412725
412838
|
return true;
|
|
412726
412839
|
}
|
|
412727
|
-
var
|
|
412840
|
+
var DEFAULT_CHANNEL_MODEL_LIST_LIMIT = 8;
|
|
412728
412841
|
var init_commands = __esm(() => {
|
|
412729
412842
|
init_access_control();
|
|
412843
|
+
init_command_surface();
|
|
412730
412844
|
init_feedback2();
|
|
412731
412845
|
init_plugin_registry();
|
|
412732
412846
|
init_registry_presentation();
|
|
412733
|
-
|
|
412734
|
-
{
|
|
412735
|
-
name: "help",
|
|
412736
|
-
kind: "direct",
|
|
412737
|
-
summary: "Show channel usage guidance."
|
|
412738
|
-
},
|
|
412739
|
-
{
|
|
412740
|
-
name: "status",
|
|
412741
|
-
kind: "direct",
|
|
412742
|
-
summary: "Show this chat's channel connection status."
|
|
412743
|
-
},
|
|
412744
|
-
{
|
|
412745
|
-
name: "whoami",
|
|
412746
|
-
kind: "direct",
|
|
412747
|
-
summary: "Show your access tier and runnable commands here."
|
|
412748
|
-
},
|
|
412749
|
-
{
|
|
412750
|
-
name: "pause",
|
|
412751
|
-
kind: "direct",
|
|
412752
|
-
summary: "Pause agent routing for this chat."
|
|
412753
|
-
},
|
|
412754
|
-
{
|
|
412755
|
-
name: "resume",
|
|
412756
|
-
kind: "direct",
|
|
412757
|
-
summary: "Resume agent routing for this chat."
|
|
412758
|
-
},
|
|
412759
|
-
{
|
|
412760
|
-
name: "cancel",
|
|
412761
|
-
kind: "agent-scoped",
|
|
412762
|
-
summary: "Cancel the in-progress agent turn for this chat."
|
|
412763
|
-
},
|
|
412764
|
-
{
|
|
412765
|
-
name: "chat",
|
|
412766
|
-
kind: "direct",
|
|
412767
|
-
summary: "Show the Letta web chat link for this channel route."
|
|
412768
|
-
},
|
|
412769
|
-
{
|
|
412770
|
-
name: "feedback",
|
|
412771
|
-
kind: "direct",
|
|
412772
|
-
summary: "Send feedback about Letta Code from this routed chat."
|
|
412773
|
-
},
|
|
412774
|
-
{
|
|
412775
|
-
name: "model",
|
|
412776
|
-
kind: "agent-scoped",
|
|
412777
|
-
summary: "Show, list, or switch the model for this chat's routed conversation."
|
|
412778
|
-
},
|
|
412779
|
-
{
|
|
412780
|
-
name: "reflection",
|
|
412781
|
-
aliases: ["reflect"],
|
|
412782
|
-
kind: "agent-scoped",
|
|
412783
|
-
summary: "Start a memory reflection pass for this conversation."
|
|
412784
|
-
},
|
|
412785
|
-
{
|
|
412786
|
-
name: "reload",
|
|
412787
|
-
kind: "agent-scoped",
|
|
412788
|
-
summary: "Reload settings, local mods, and agent secrets."
|
|
412789
|
-
}
|
|
412790
|
-
];
|
|
412791
|
-
SLACK_MENTION_COMMAND_NAMES = [
|
|
412792
|
-
"help",
|
|
412793
|
-
"detach",
|
|
412794
|
-
"model",
|
|
412795
|
-
"new",
|
|
412796
|
-
"reload"
|
|
412797
|
-
];
|
|
412798
|
-
SLACK_MENTION_SLASH_COMMAND_EXAMPLES = [
|
|
412799
|
-
"@agent /help",
|
|
412800
|
-
"@agent /status",
|
|
412801
|
-
"@agent /whoami",
|
|
412802
|
-
"@agent /model",
|
|
412803
|
-
"@agent /model list",
|
|
412804
|
-
"@agent /model <handle-or-id>",
|
|
412805
|
-
"@agent /cancel",
|
|
412806
|
-
"@agent /chat",
|
|
412807
|
-
"@agent /feedback <message>",
|
|
412808
|
-
"@agent /reflection",
|
|
412809
|
-
"@agent /detach",
|
|
412810
|
-
"@agent /new",
|
|
412811
|
-
"@agent /reload"
|
|
412812
|
-
];
|
|
412847
|
+
init_command_surface();
|
|
412813
412848
|
});
|
|
412814
412849
|
|
|
412815
412850
|
// src/channels/slack/model-picker-blocks.ts
|
|
@@ -424250,10 +424285,24 @@ var init_registry_inbound = __esm(() => {
|
|
|
424250
424285
|
});
|
|
424251
424286
|
|
|
424252
424287
|
// src/channels/registry-routes.ts
|
|
424288
|
+
async function resolveConversationModelPin(agentId) {
|
|
424289
|
+
try {
|
|
424290
|
+
const agent2 = await getBackend().retrieveAgent(agentId);
|
|
424291
|
+
return {
|
|
424292
|
+
...agent2.model ? { model: agent2.model } : {},
|
|
424293
|
+
...agent2.model_settings ? { model_settings: agent2.model_settings } : {}
|
|
424294
|
+
};
|
|
424295
|
+
} catch (error54) {
|
|
424296
|
+
debugWarn("channels", `Failed to resolve model for agent ${agentId}; creating channel conversation without a pinned model`, error54);
|
|
424297
|
+
return {};
|
|
424298
|
+
}
|
|
424299
|
+
}
|
|
424253
424300
|
function createChannelRouteProvisioner(deps) {
|
|
424254
424301
|
async function createConversationForAgent(agentId, summary) {
|
|
424302
|
+
const modelPin = await resolveConversationModelPin(agentId);
|
|
424255
424303
|
const conversation = await getBackend().createConversation({
|
|
424256
424304
|
agent_id: agentId,
|
|
424305
|
+
...modelPin,
|
|
424257
424306
|
...summary ? { summary } : {}
|
|
424258
424307
|
});
|
|
424259
424308
|
return conversation.id;
|
|
@@ -424596,6 +424645,7 @@ function createChannelRouteProvisioner(deps) {
|
|
|
424596
424645
|
}
|
|
424597
424646
|
var init_registry_routes = __esm(() => {
|
|
424598
424647
|
init_backend2();
|
|
424648
|
+
init_debug();
|
|
424599
424649
|
init_accounts();
|
|
424600
424650
|
init_registry_presentation();
|
|
424601
424651
|
init_routing();
|
|
@@ -437141,7 +437191,7 @@ function formatScheduledTaskPrompt(input) {
|
|
|
437141
437191
|
return lines.join(`
|
|
437142
437192
|
`);
|
|
437143
437193
|
}
|
|
437144
|
-
var AUTONOMOUS_NOTICE = "You are running autonomously: no user is watching this turn and questions will not be answered. Deliver results through your available channels or record them in memory, and work until the task is done or genuinely blocked.";
|
|
437194
|
+
var SCHEDULE_ORIGIN_TAG = "origin:schedule", AUTONOMOUS_NOTICE = "You are running autonomously: no user is watching this turn and questions will not be answered. Deliver results through your available channels or record them in memory, and work until the task is done or genuinely blocked.";
|
|
437145
437195
|
|
|
437146
437196
|
// src/cron/prompt.ts
|
|
437147
437197
|
function getIntendedCronOccurrence(task2, matchedAt) {
|
|
@@ -437179,14 +437229,12 @@ function minuteKey(date6) {
|
|
|
437179
437229
|
function wrapCronPrompt(task2, timing2) {
|
|
437180
437230
|
return formatCronPrompt(task2, timing2);
|
|
437181
437231
|
}
|
|
437182
|
-
function getCronConversationSummary(task2) {
|
|
437183
|
-
return `[Schedule] ${task2.name}`;
|
|
437184
|
-
}
|
|
437185
437232
|
async function resolveCronFireConversationId(task2) {
|
|
437186
437233
|
if (task2.conversation_id === NEW_CONVERSATION_TARGET) {
|
|
437187
437234
|
const conversation = await getBackend().createConversation({
|
|
437188
437235
|
agent_id: task2.agent_id,
|
|
437189
|
-
summary:
|
|
437236
|
+
summary: task2.name,
|
|
437237
|
+
tags: [SCHEDULE_ORIGIN_TAG]
|
|
437190
437238
|
});
|
|
437191
437239
|
return conversation.id;
|
|
437192
437240
|
}
|
|
@@ -459397,9 +459445,18 @@ async function prepareListenerTurn(params) {
|
|
|
459397
459445
|
if (isInterrupted()) {
|
|
459398
459446
|
return { kind: "interrupted" };
|
|
459399
459447
|
}
|
|
459448
|
+
const availableSkills = (await buildClientSkillsPayload({
|
|
459449
|
+
agentId,
|
|
459450
|
+
skillsDirectory: listenerOptions?.skillsDirectory,
|
|
459451
|
+
skillSources: runtime.skillSources
|
|
459452
|
+
})).availableSkills;
|
|
459453
|
+
if (isInterrupted()) {
|
|
459454
|
+
return { kind: "interrupted" };
|
|
459455
|
+
}
|
|
459400
459456
|
runtime.currentToolset = preparedToolContext.toolset;
|
|
459401
459457
|
runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
|
|
459402
459458
|
runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
|
|
459459
|
+
runtime.currentAvailableSkills = availableSkills;
|
|
459403
459460
|
return {
|
|
459404
459461
|
kind: "ready",
|
|
459405
459462
|
getCachedAgent: () => cachedAgent,
|
|
@@ -459413,6 +459470,7 @@ async function prepareListenerTurn(params) {
|
|
|
459413
459470
|
};
|
|
459414
459471
|
}
|
|
459415
459472
|
var init_turn_setup = __esm(async () => {
|
|
459473
|
+
init_client_skills();
|
|
459416
459474
|
init_context();
|
|
459417
459475
|
init_backend2();
|
|
459418
459476
|
init_engine3();
|
|
@@ -476801,6 +476859,56 @@ var init_message_channel_formatting = __esm(() => {
|
|
|
476801
476859
|
};
|
|
476802
476860
|
});
|
|
476803
476861
|
|
|
476862
|
+
// src/channels/message-channel-idempotency.ts
|
|
476863
|
+
function isErrorResult(result) {
|
|
476864
|
+
return result.startsWith("Error:");
|
|
476865
|
+
}
|
|
476866
|
+
function createMessageChannelIdempotencyScope() {
|
|
476867
|
+
const inFlight = new Map;
|
|
476868
|
+
let lastSuccessful = null;
|
|
476869
|
+
let latestInvocation = 0;
|
|
476870
|
+
return {
|
|
476871
|
+
async execute(key2, effect) {
|
|
476872
|
+
if (!key2) {
|
|
476873
|
+
latestInvocation += 1;
|
|
476874
|
+
lastSuccessful = null;
|
|
476875
|
+
return await effect();
|
|
476876
|
+
}
|
|
476877
|
+
const pendingDuplicate = inFlight.get(key2);
|
|
476878
|
+
if (pendingDuplicate) {
|
|
476879
|
+
throw new MessageChannelDuplicateActionError("in-flight");
|
|
476880
|
+
}
|
|
476881
|
+
if (lastSuccessful?.key === key2) {
|
|
476882
|
+
throw new MessageChannelDuplicateActionError("completed");
|
|
476883
|
+
}
|
|
476884
|
+
const invocation = ++latestInvocation;
|
|
476885
|
+
lastSuccessful = null;
|
|
476886
|
+
const pending = Promise.resolve().then(effect);
|
|
476887
|
+
inFlight.set(key2, pending);
|
|
476888
|
+
try {
|
|
476889
|
+
const result = await pending;
|
|
476890
|
+
if (invocation === latestInvocation && !isErrorResult(result)) {
|
|
476891
|
+
lastSuccessful = { key: key2 };
|
|
476892
|
+
}
|
|
476893
|
+
return result;
|
|
476894
|
+
} finally {
|
|
476895
|
+
if (inFlight.get(key2) === pending)
|
|
476896
|
+
inFlight.delete(key2);
|
|
476897
|
+
}
|
|
476898
|
+
}
|
|
476899
|
+
};
|
|
476900
|
+
}
|
|
476901
|
+
var MessageChannelDuplicateActionError;
|
|
476902
|
+
var init_message_channel_idempotency = __esm(() => {
|
|
476903
|
+
MessageChannelDuplicateActionError = class MessageChannelDuplicateActionError extends Error {
|
|
476904
|
+
constructor(state) {
|
|
476905
|
+
const detail = state === "in-flight" ? "an identical text send is already in progress" : "the immediately previous MessageChannel call already sent this exact text to the same destination";
|
|
476906
|
+
super(`Duplicate MessageChannel action suppressed: ${detail}. The duplicate was not sent; continue the turn instead of retrying it.`);
|
|
476907
|
+
this.name = "MessageChannelDuplicateActionError";
|
|
476908
|
+
}
|
|
476909
|
+
};
|
|
476910
|
+
});
|
|
476911
|
+
|
|
476804
476912
|
// src/channels/message-channel-executor.ts
|
|
476805
476913
|
function firstNonEmptyString4(...values2) {
|
|
476806
476914
|
for (const value of values2) {
|
|
@@ -476950,6 +477058,50 @@ async function dispatchMessageChannelAction(params) {
|
|
|
476950
477058
|
formatText: (text2) => formatOutboundChannelMessage(params.request.channel, text2)
|
|
476951
477059
|
});
|
|
476952
477060
|
}
|
|
477061
|
+
function trimmedOrNull(value) {
|
|
477062
|
+
const trimmed = value?.trim();
|
|
477063
|
+
return trimmed ? trimmed : null;
|
|
477064
|
+
}
|
|
477065
|
+
function effectiveTextThreadId(request, route) {
|
|
477066
|
+
const requestThreadId = trimmedOrNull(request.threadId);
|
|
477067
|
+
const routeThreadId = trimmedOrNull(route.threadId);
|
|
477068
|
+
if (request.channel === "telegram") {
|
|
477069
|
+
if (requestThreadId)
|
|
477070
|
+
return requestThreadId;
|
|
477071
|
+
if (route.chatType === "direct")
|
|
477072
|
+
return null;
|
|
477073
|
+
return route.chatId.trim().startsWith("-") ? routeThreadId : null;
|
|
477074
|
+
}
|
|
477075
|
+
if (request.channel === "discord") {
|
|
477076
|
+
return route.chatType === "direct" ? route.chatId : requestThreadId ?? routeThreadId;
|
|
477077
|
+
}
|
|
477078
|
+
if (request.channel === "slack") {
|
|
477079
|
+
const isDirect = route.chatType === "direct" || request.chatId.startsWith("D");
|
|
477080
|
+
if (isDirect)
|
|
477081
|
+
return requestThreadId ?? routeThreadId;
|
|
477082
|
+
return request.replyToMessageId ? null : requestThreadId ?? routeThreadId;
|
|
477083
|
+
}
|
|
477084
|
+
return null;
|
|
477085
|
+
}
|
|
477086
|
+
function effectiveTextReplyId(request, route) {
|
|
477087
|
+
const isSlackDirect = request.channel === "slack" && (route.chatType === "direct" || request.chatId.startsWith("D"));
|
|
477088
|
+
return isSlackDirect ? null : trimmedOrNull(request.replyToMessageId);
|
|
477089
|
+
}
|
|
477090
|
+
function messageIdempotencyKey(request, route) {
|
|
477091
|
+
if (request.action !== "send" && request.action !== "send-rich" || request.mediaPath) {
|
|
477092
|
+
return null;
|
|
477093
|
+
}
|
|
477094
|
+
return JSON.stringify({
|
|
477095
|
+
action: request.action,
|
|
477096
|
+
channel: request.channel,
|
|
477097
|
+
chatId: route.chatId,
|
|
477098
|
+
accountId: route.accountId ?? null,
|
|
477099
|
+
chatType: route.chatType ?? null,
|
|
477100
|
+
threadId: effectiveTextThreadId(request, route),
|
|
477101
|
+
message: request.message ?? null,
|
|
477102
|
+
replyToMessageId: effectiveTextReplyId(request, route)
|
|
477103
|
+
});
|
|
477104
|
+
}
|
|
476953
477105
|
async function executeMessageChannel(input, options3) {
|
|
476954
477106
|
const normalized = normalizeMessageChannelInput(input, options3.resolver);
|
|
476955
477107
|
if (typeof normalized === "string")
|
|
@@ -476984,10 +477136,8 @@ async function executeMessageChannel(input, options3) {
|
|
|
476984
477136
|
channelTurnSources: options3.channelTurnSources
|
|
476985
477137
|
});
|
|
476986
477138
|
const requestThreadId = normalized.action === "download-file" ? normalized.threadId : inferredThreadId ?? (normalized.channel === "telegram" && context4.route.chatType === "direct" ? normalized.threadId : context4.route.threadId ?? normalized.threadId);
|
|
476987
|
-
|
|
476988
|
-
|
|
476989
|
-
context: context4
|
|
476990
|
-
});
|
|
477139
|
+
const request2 = buildMessageChannelRequest(normalized, normalized.chatId, requestThreadId);
|
|
477140
|
+
return await dispatchWithIdempotency(request2, context4, options3.idempotencyScope);
|
|
476991
477141
|
}
|
|
476992
477142
|
if (normalized.channel !== "slack") {
|
|
476993
477143
|
return `Error: Explicit MessageChannel targets are not supported on ${normalized.channel}.`;
|
|
@@ -477008,17 +477158,23 @@ async function executeMessageChannel(input, options3) {
|
|
|
477008
477158
|
transport: proactive.transport,
|
|
477009
477159
|
messageActions: proactive.messageActions
|
|
477010
477160
|
};
|
|
477011
|
-
|
|
477012
|
-
|
|
477013
|
-
context: context3
|
|
477014
|
-
});
|
|
477161
|
+
const request = buildMessageChannelRequest(normalized, proactive.target.chatId, proactive.target.threadId);
|
|
477162
|
+
return await dispatchWithIdempotency(request, context3, options3.idempotencyScope);
|
|
477015
477163
|
} catch (error54) {
|
|
477164
|
+
if (error54 instanceof MessageChannelDuplicateActionError)
|
|
477165
|
+
throw error54;
|
|
477016
477166
|
const message = error54 instanceof Error ? error54.message : "unknown error";
|
|
477017
477167
|
return `Error sending message to ${normalized.channel}: ${message}`;
|
|
477018
477168
|
}
|
|
477019
477169
|
}
|
|
477170
|
+
function dispatchWithIdempotency(request, context3, scope) {
|
|
477171
|
+
const dispatch = () => dispatchMessageChannelAction({ request, context: context3 });
|
|
477172
|
+
const key2 = messageIdempotencyKey(request, context3.route);
|
|
477173
|
+
return scope ? scope.execute(key2, dispatch) : dispatch();
|
|
477174
|
+
}
|
|
477020
477175
|
var init_message_channel_executor = __esm(() => {
|
|
477021
477176
|
init_message_channel_formatting();
|
|
477177
|
+
init_message_channel_idempotency();
|
|
477022
477178
|
});
|
|
477023
477179
|
|
|
477024
477180
|
// src/channels/slack/proactive-accounts.ts
|
|
@@ -477140,7 +477296,7 @@ function createLocalMessageChannelResolver() {
|
|
|
477140
477296
|
}
|
|
477141
477297
|
};
|
|
477142
477298
|
}
|
|
477143
|
-
async function message_channel(args) {
|
|
477299
|
+
async function message_channel(args, idempotencyScope) {
|
|
477144
477300
|
if (!getChannelRegistry()) {
|
|
477145
477301
|
return "Error: Channel system is not initialized. Start with --channels flag.";
|
|
477146
477302
|
}
|
|
@@ -477150,7 +477306,8 @@ async function message_channel(args) {
|
|
|
477150
477306
|
return await executeMessageChannel(args, {
|
|
477151
477307
|
scope: args.parentScope,
|
|
477152
477308
|
resolver: createLocalMessageChannelResolver(),
|
|
477153
|
-
channelTurnSources: args.channelTurnSources
|
|
477309
|
+
channelTurnSources: args.channelTurnSources,
|
|
477310
|
+
idempotencyScope
|
|
477154
477311
|
});
|
|
477155
477312
|
}
|
|
477156
477313
|
var init_message_channel = __esm(() => {
|
|
@@ -478089,8 +478246,9 @@ class ChannelGateway {
|
|
|
478089
478246
|
this.hooks = hooks;
|
|
478090
478247
|
this.disposers.push(client.onMessage((message) => this.handleMessage(message)), client.onExternalToolCall((request) => {
|
|
478091
478248
|
const state = request.runtime ? this.states.get(runtimeKey(request.runtime)) : undefined;
|
|
478092
|
-
const
|
|
478093
|
-
|
|
478249
|
+
const active = state?.active;
|
|
478250
|
+
const sources = active?.sources ?? state?.routedSources ?? [];
|
|
478251
|
+
return hooks.executeExternalTool(request, sources, active?.idempotencyScope ?? null);
|
|
478094
478252
|
}));
|
|
478095
478253
|
}
|
|
478096
478254
|
close() {
|
|
@@ -478178,7 +478336,8 @@ class ChannelGateway {
|
|
|
478178
478336
|
batchId: `channel-recovered-${crypto.randomUUID()}`,
|
|
478179
478337
|
sources: uniqueSources(sources),
|
|
478180
478338
|
progress: createChannelTurnProgressBuilder(),
|
|
478181
|
-
richDraft: null
|
|
478339
|
+
richDraft: null,
|
|
478340
|
+
idempotencyScope: createMessageChannelIdempotencyScope()
|
|
478182
478341
|
};
|
|
478183
478342
|
state.active = recoveredTurn;
|
|
478184
478343
|
}
|
|
@@ -478400,7 +478559,8 @@ class ChannelGateway {
|
|
|
478400
478559
|
richDraft: this.hooks.createRichDraft?.({
|
|
478401
478560
|
batchId: `channel-${clientMessageId}`,
|
|
478402
478561
|
sources
|
|
478403
|
-
}) ?? null
|
|
478562
|
+
}) ?? null,
|
|
478563
|
+
idempotencyScope: createMessageChannelIdempotencyScope()
|
|
478404
478564
|
};
|
|
478405
478565
|
const processingEvent = {
|
|
478406
478566
|
type: "processing",
|
|
@@ -478479,6 +478639,7 @@ class ChannelGateway {
|
|
|
478479
478639
|
var MAX_ACCEPTED_CLIENT_MESSAGE_IDS = 2048;
|
|
478480
478640
|
var init_gateway_core = __esm(() => {
|
|
478481
478641
|
init_interactive_policy();
|
|
478642
|
+
init_message_channel_idempotency();
|
|
478482
478643
|
init_progress_builder();
|
|
478483
478644
|
});
|
|
478484
478645
|
|
|
@@ -479972,7 +480133,7 @@ async function startLocalChannelGateway(options3) {
|
|
|
479972
480133
|
buildExternalTool: async (runtime) => {
|
|
479973
480134
|
return buildGatewayMessageChannelTool(registry2.resolveTurnSourcesForScope(runtime.agent_id, runtime.conversation_id));
|
|
479974
480135
|
},
|
|
479975
|
-
executeExternalTool: async (request, sources) => {
|
|
480136
|
+
executeExternalTool: async (request, sources, idempotencyScope) => {
|
|
479976
480137
|
if (request.tool_name !== "MessageChannel" || !request.runtime) {
|
|
479977
480138
|
throw new Error(`Unsupported gateway tool: ${request.tool_name}`);
|
|
479978
480139
|
}
|
|
@@ -479985,9 +480146,10 @@ async function startLocalChannelGateway(options3) {
|
|
|
479985
480146
|
conversationId: request.runtime.conversation_id
|
|
479986
480147
|
},
|
|
479987
480148
|
channelTurnSources: sources
|
|
479988
|
-
});
|
|
480149
|
+
}, idempotencyScope);
|
|
479989
480150
|
return {
|
|
479990
|
-
content: [{ type: "text", text: text2 }]
|
|
480151
|
+
content: [{ type: "text", text: text2 }],
|
|
480152
|
+
is_error: text2.startsWith("Error:")
|
|
479991
480153
|
};
|
|
479992
480154
|
},
|
|
479993
480155
|
onLifecycle: (event2) => registry2.dispatchTurnLifecycleEvent(event2),
|
|
@@ -492535,7 +492697,7 @@ var init_mcp_client = __esm(() => {
|
|
|
492535
492697
|
init_streamableHttp();
|
|
492536
492698
|
DEFAULT_CLIENT_INFO = {
|
|
492537
492699
|
name: "letta-code",
|
|
492538
|
-
version: "0.30.
|
|
492700
|
+
version: "0.30.11"
|
|
492539
492701
|
};
|
|
492540
492702
|
});
|
|
492541
492703
|
|
|
@@ -559650,4 +559812,4 @@ function registerBunOAuthFlows() {
|
|
|
559650
559812
|
registerBunOAuthFlows();
|
|
559651
559813
|
await init_src5().then(() => exports_src2);
|
|
559652
559814
|
|
|
559653
|
-
//# debugId=
|
|
559815
|
+
//# debugId=49F16715F241AC4A64756E2164756E21
|