@letta-ai/letta-code 0.23.4 → 0.23.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/letta.js +1340 -291
- package/package.json +1 -1
- package/skills/scheduling-tasks/SKILL.md +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.23.
|
|
3272
|
+
version: "0.23.6",
|
|
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: {
|
|
@@ -8391,10 +8391,10 @@ var init_models2 = __esm(() => {
|
|
|
8391
8391
|
}
|
|
8392
8392
|
},
|
|
8393
8393
|
{
|
|
8394
|
-
id: "opus",
|
|
8394
|
+
id: "opus-4.6-high",
|
|
8395
8395
|
handle: "anthropic/claude-opus-4-6",
|
|
8396
8396
|
label: "Opus 4.6",
|
|
8397
|
-
description: "Anthropic's best model (high reasoning)",
|
|
8397
|
+
description: "Anthropic's (legacy) best model (high reasoning)",
|
|
8398
8398
|
isFeatured: true,
|
|
8399
8399
|
updateArgs: {
|
|
8400
8400
|
context_window: 200000,
|
|
@@ -8458,6 +8458,74 @@ var init_models2 = __esm(() => {
|
|
|
8458
8458
|
parallel_tool_calls: true
|
|
8459
8459
|
}
|
|
8460
8460
|
},
|
|
8461
|
+
{
|
|
8462
|
+
id: "opus",
|
|
8463
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8464
|
+
label: "Opus 4.7",
|
|
8465
|
+
description: "Anthropic's best model (med reasoning)",
|
|
8466
|
+
isFeatured: true,
|
|
8467
|
+
updateArgs: {
|
|
8468
|
+
context_window: 200000,
|
|
8469
|
+
max_output_tokens: 128000,
|
|
8470
|
+
reasoning_effort: "medium",
|
|
8471
|
+
enable_reasoner: true,
|
|
8472
|
+
max_reasoning_tokens: 12000,
|
|
8473
|
+
parallel_tool_calls: true
|
|
8474
|
+
}
|
|
8475
|
+
},
|
|
8476
|
+
{
|
|
8477
|
+
id: "opus-4.7-low",
|
|
8478
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8479
|
+
label: "Opus 4.7",
|
|
8480
|
+
description: "Opus 4.7 (low reasoning)",
|
|
8481
|
+
updateArgs: {
|
|
8482
|
+
context_window: 200000,
|
|
8483
|
+
max_output_tokens: 128000,
|
|
8484
|
+
reasoning_effort: "low",
|
|
8485
|
+
enable_reasoner: true,
|
|
8486
|
+
max_reasoning_tokens: 4000,
|
|
8487
|
+
parallel_tool_calls: true
|
|
8488
|
+
}
|
|
8489
|
+
},
|
|
8490
|
+
{
|
|
8491
|
+
id: "opus-4.7-high",
|
|
8492
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8493
|
+
label: "Opus 4.7",
|
|
8494
|
+
description: "Opus 4.7 (high reasoning)",
|
|
8495
|
+
updateArgs: {
|
|
8496
|
+
context_window: 200000,
|
|
8497
|
+
max_output_tokens: 128000,
|
|
8498
|
+
reasoning_effort: "high",
|
|
8499
|
+
enable_reasoner: true,
|
|
8500
|
+
parallel_tool_calls: true
|
|
8501
|
+
}
|
|
8502
|
+
},
|
|
8503
|
+
{
|
|
8504
|
+
id: "opus-4.7-xhigh",
|
|
8505
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8506
|
+
label: "Opus 4.7",
|
|
8507
|
+
description: "Opus 4.7 (extra-high reasoning)",
|
|
8508
|
+
updateArgs: {
|
|
8509
|
+
context_window: 200000,
|
|
8510
|
+
max_output_tokens: 128000,
|
|
8511
|
+
reasoning_effort: "xhigh",
|
|
8512
|
+
enable_reasoner: true,
|
|
8513
|
+
parallel_tool_calls: true
|
|
8514
|
+
}
|
|
8515
|
+
},
|
|
8516
|
+
{
|
|
8517
|
+
id: "opus-4.7-max",
|
|
8518
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8519
|
+
label: "Opus 4.7",
|
|
8520
|
+
description: "Opus 4.7 (max reasoning)",
|
|
8521
|
+
updateArgs: {
|
|
8522
|
+
context_window: 200000,
|
|
8523
|
+
max_output_tokens: 128000,
|
|
8524
|
+
reasoning_effort: "max",
|
|
8525
|
+
enable_reasoner: true,
|
|
8526
|
+
parallel_tool_calls: true
|
|
8527
|
+
}
|
|
8528
|
+
},
|
|
8461
8529
|
{
|
|
8462
8530
|
id: "opus-1m",
|
|
8463
8531
|
handle: "anthropic/claude-opus-4-6",
|
|
@@ -10179,6 +10247,11 @@ function getModelInfoForLlmConfig(modelHandle, llmConfig) {
|
|
|
10179
10247
|
const match = candidates.find((m) => m.updateArgs?.reasoning_effort === effort);
|
|
10180
10248
|
if (match)
|
|
10181
10249
|
return match;
|
|
10250
|
+
if (effort === "max") {
|
|
10251
|
+
const legacyXHighMatch = candidates.find((m) => m.updateArgs?.reasoning_effort === "xhigh");
|
|
10252
|
+
if (legacyXHighMatch)
|
|
10253
|
+
return legacyXHighMatch;
|
|
10254
|
+
}
|
|
10182
10255
|
}
|
|
10183
10256
|
if (llmConfig?.enable_reasoner === false) {
|
|
10184
10257
|
const match = candidates.find((m) => m.updateArgs?.enable_reasoner === false);
|
|
@@ -10295,7 +10368,8 @@ var init_model = __esm(() => {
|
|
|
10295
10368
|
"low",
|
|
10296
10369
|
"medium",
|
|
10297
10370
|
"high",
|
|
10298
|
-
"xhigh"
|
|
10371
|
+
"xhigh",
|
|
10372
|
+
"max"
|
|
10299
10373
|
];
|
|
10300
10374
|
RESUME_REFRESH_FIELDS = [
|
|
10301
10375
|
"max_output_tokens",
|
|
@@ -37776,6 +37850,11 @@ function getModelInfoForLlmConfig2(modelHandle, llmConfig) {
|
|
|
37776
37850
|
const match = candidates.find((m) => m.updateArgs?.reasoning_effort === effort);
|
|
37777
37851
|
if (match)
|
|
37778
37852
|
return match;
|
|
37853
|
+
if (effort === "max") {
|
|
37854
|
+
const legacyXHighMatch = candidates.find((m) => m.updateArgs?.reasoning_effort === "xhigh");
|
|
37855
|
+
if (legacyXHighMatch)
|
|
37856
|
+
return legacyXHighMatch;
|
|
37857
|
+
}
|
|
37779
37858
|
}
|
|
37780
37859
|
if (llmConfig?.enable_reasoner === false) {
|
|
37781
37860
|
const match = candidates.find((m) => m.updateArgs?.enable_reasoner === false);
|
|
@@ -37892,7 +37971,8 @@ var init_model2 = __esm(() => {
|
|
|
37892
37971
|
"low",
|
|
37893
37972
|
"medium",
|
|
37894
37973
|
"high",
|
|
37895
|
-
"xhigh"
|
|
37974
|
+
"xhigh",
|
|
37975
|
+
"max"
|
|
37896
37976
|
];
|
|
37897
37977
|
RESUME_REFRESH_FIELDS2 = [
|
|
37898
37978
|
"max_output_tokens",
|
|
@@ -38170,6 +38250,9 @@ __export(exports_modify, {
|
|
|
38170
38250
|
updateAgentLLMConfig: () => updateAgentLLMConfig2,
|
|
38171
38251
|
recompileAgentSystemPrompt: () => recompileAgentSystemPrompt
|
|
38172
38252
|
});
|
|
38253
|
+
function supportsDistinctAnthropicXHighEffort2(modelHandle) {
|
|
38254
|
+
return modelHandle.includes("claude-opus-4-7");
|
|
38255
|
+
}
|
|
38173
38256
|
function buildModelSettings2(modelHandle, updateArgs) {
|
|
38174
38257
|
const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
|
|
38175
38258
|
const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
|
|
@@ -38203,10 +38286,13 @@ function buildModelSettings2(modelHandle, updateArgs) {
|
|
|
38203
38286
|
parallel_tool_calls: true
|
|
38204
38287
|
};
|
|
38205
38288
|
const effort = updateArgs?.reasoning_effort;
|
|
38289
|
+
const hasDistinctXHigh = supportsDistinctAnthropicXHighEffort2(modelHandle);
|
|
38206
38290
|
if (effort === "low" || effort === "medium" || effort === "high") {
|
|
38207
38291
|
anthropicSettings.effort = effort;
|
|
38208
38292
|
} else if (effort === "xhigh") {
|
|
38209
|
-
anthropicSettings.effort = "max";
|
|
38293
|
+
anthropicSettings.effort = hasDistinctXHigh ? "xhigh" : "max";
|
|
38294
|
+
} else if (effort === "max") {
|
|
38295
|
+
anthropicSettings.effort = effort;
|
|
38210
38296
|
}
|
|
38211
38297
|
if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
|
|
38212
38298
|
anthropicSettings.thinking = {
|
|
@@ -38259,10 +38345,13 @@ function buildModelSettings2(modelHandle, updateArgs) {
|
|
|
38259
38345
|
parallel_tool_calls: true
|
|
38260
38346
|
};
|
|
38261
38347
|
const effort = updateArgs?.reasoning_effort;
|
|
38348
|
+
const hasDistinctXHigh = supportsDistinctAnthropicXHighEffort2(modelHandle);
|
|
38262
38349
|
if (effort === "low" || effort === "medium" || effort === "high") {
|
|
38263
38350
|
bedrockSettings.effort = effort;
|
|
38264
38351
|
} else if (effort === "xhigh") {
|
|
38265
|
-
bedrockSettings.effort = "max";
|
|
38352
|
+
bedrockSettings.effort = hasDistinctXHigh ? "xhigh" : "max";
|
|
38353
|
+
} else if (effort === "max") {
|
|
38354
|
+
bedrockSettings.effort = effort;
|
|
38266
38355
|
}
|
|
38267
38356
|
if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
|
|
38268
38357
|
bedrockSettings.thinking = {
|
|
@@ -39720,6 +39809,9 @@ function normalizeLoadedAccount(account) {
|
|
|
39720
39809
|
if (next.channel === "telegram" && (next.displayName === "Telegram bot" || next.displayName === "Migrated Telegram bot") || next.channel === "slack" && (next.displayName === "Slack app" || next.displayName === "Migrated Slack app")) {
|
|
39721
39810
|
next.displayName = undefined;
|
|
39722
39811
|
}
|
|
39812
|
+
if (next.channel === "slack") {
|
|
39813
|
+
next.defaultPermissionMode = next.defaultPermissionMode ?? "default";
|
|
39814
|
+
}
|
|
39723
39815
|
return next;
|
|
39724
39816
|
}
|
|
39725
39817
|
function makeDefaultLegacyAccount(channelId) {
|
|
@@ -39754,6 +39846,7 @@ function makeDefaultLegacyAccount(channelId) {
|
|
|
39754
39846
|
dmPolicy: config.dmPolicy,
|
|
39755
39847
|
allowedUsers: [...config.allowedUsers],
|
|
39756
39848
|
agentId: null,
|
|
39849
|
+
defaultPermissionMode: "default",
|
|
39757
39850
|
createdAt: now,
|
|
39758
39851
|
updatedAt: now
|
|
39759
39852
|
};
|
|
@@ -40574,14 +40667,27 @@ function getPackageManagerExecutable(packageManager) {
|
|
|
40574
40667
|
}
|
|
40575
40668
|
return packageManager;
|
|
40576
40669
|
}
|
|
40670
|
+
function resolveInstallPlatform() {
|
|
40671
|
+
return platformOverride ?? process.platform;
|
|
40672
|
+
}
|
|
40577
40673
|
function getInstallArgs(packageManager, installPackages) {
|
|
40674
|
+
const noBinLinks = resolveInstallPlatform() === "win32" && packageManager !== "bun";
|
|
40578
40675
|
switch (packageManager) {
|
|
40579
40676
|
case "bun":
|
|
40580
40677
|
return ["add", "--no-save", ...installPackages];
|
|
40581
40678
|
case "pnpm":
|
|
40582
|
-
return [
|
|
40679
|
+
return [
|
|
40680
|
+
"add",
|
|
40681
|
+
...noBinLinks ? ["--no-bin-links"] : [],
|
|
40682
|
+
...installPackages
|
|
40683
|
+
];
|
|
40583
40684
|
case "npm":
|
|
40584
|
-
return [
|
|
40685
|
+
return [
|
|
40686
|
+
"install",
|
|
40687
|
+
"--no-save",
|
|
40688
|
+
...noBinLinks ? ["--no-bin-links"] : [],
|
|
40689
|
+
...installPackages
|
|
40690
|
+
];
|
|
40585
40691
|
}
|
|
40586
40692
|
}
|
|
40587
40693
|
async function installChannelRuntime(channelId) {
|
|
@@ -41214,6 +41320,14 @@ var init_plugin = __esm(() => {
|
|
|
41214
41320
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
41215
41321
|
import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
41216
41322
|
import { basename as basename3, extname as extname2, join as join12 } from "node:path";
|
|
41323
|
+
function mapSlackThreadMessage(message) {
|
|
41324
|
+
return {
|
|
41325
|
+
text: resolveSlackThreadMessageText(message),
|
|
41326
|
+
userId: isNonEmptyString(message.user) ? message.user : undefined,
|
|
41327
|
+
botId: isNonEmptyString(message.bot_id) ? message.bot_id : undefined,
|
|
41328
|
+
ts: isNonEmptyString(message.ts) ? message.ts : undefined
|
|
41329
|
+
};
|
|
41330
|
+
}
|
|
41217
41331
|
function asRecord(value) {
|
|
41218
41332
|
return value && typeof value === "object" ? value : null;
|
|
41219
41333
|
}
|
|
@@ -41245,6 +41359,18 @@ function normalizeSlackAttachmentLike(value) {
|
|
|
41245
41359
|
files
|
|
41246
41360
|
};
|
|
41247
41361
|
}
|
|
41362
|
+
function resolveSlackThreadMessageText(message) {
|
|
41363
|
+
const text = typeof message.text === "string" ? message.text.trim() : "";
|
|
41364
|
+
if (text) {
|
|
41365
|
+
return text;
|
|
41366
|
+
}
|
|
41367
|
+
const files = Array.isArray(message.files) ? message.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : [];
|
|
41368
|
+
if (files.length === 0) {
|
|
41369
|
+
return "";
|
|
41370
|
+
}
|
|
41371
|
+
const fileNames = files.map((file) => file.name ?? "file").join(", ");
|
|
41372
|
+
return `[attached: ${fileNames}]`;
|
|
41373
|
+
}
|
|
41248
41374
|
function isAllowedSlackHostname(hostname3) {
|
|
41249
41375
|
const normalized = hostname3.trim().toLowerCase();
|
|
41250
41376
|
return ALLOWED_SLACK_HOST_SUFFIXES.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`));
|
|
@@ -41413,6 +41539,97 @@ async function resolveSlackInboundAttachments(params) {
|
|
|
41413
41539
|
}).catch(() => null)));
|
|
41414
41540
|
return resolved.filter((attachment) => Boolean(attachment));
|
|
41415
41541
|
}
|
|
41542
|
+
async function resolveSlackThreadStarter(params) {
|
|
41543
|
+
try {
|
|
41544
|
+
const response = await params.client.conversations.replies({
|
|
41545
|
+
channel: params.channelId,
|
|
41546
|
+
ts: params.threadTs,
|
|
41547
|
+
limit: 1,
|
|
41548
|
+
inclusive: true
|
|
41549
|
+
});
|
|
41550
|
+
const message = response.messages?.[0];
|
|
41551
|
+
if (!message) {
|
|
41552
|
+
return null;
|
|
41553
|
+
}
|
|
41554
|
+
const text = resolveSlackThreadMessageText(message);
|
|
41555
|
+
if (!text) {
|
|
41556
|
+
return null;
|
|
41557
|
+
}
|
|
41558
|
+
return {
|
|
41559
|
+
text,
|
|
41560
|
+
userId: isNonEmptyString(message.user) ? message.user : undefined,
|
|
41561
|
+
botId: isNonEmptyString(message.bot_id) ? message.bot_id : undefined,
|
|
41562
|
+
ts: isNonEmptyString(message.ts) ? message.ts : undefined
|
|
41563
|
+
};
|
|
41564
|
+
} catch {
|
|
41565
|
+
return null;
|
|
41566
|
+
}
|
|
41567
|
+
}
|
|
41568
|
+
async function resolveSlackThreadHistory(params) {
|
|
41569
|
+
const maxMessages = params.limit ?? 20;
|
|
41570
|
+
if (!Number.isFinite(maxMessages) || maxMessages <= 0) {
|
|
41571
|
+
return [];
|
|
41572
|
+
}
|
|
41573
|
+
const fetchLimit = 200;
|
|
41574
|
+
const retained = [];
|
|
41575
|
+
let cursor;
|
|
41576
|
+
try {
|
|
41577
|
+
do {
|
|
41578
|
+
const response = await params.client.conversations.replies({
|
|
41579
|
+
channel: params.channelId,
|
|
41580
|
+
ts: params.threadTs,
|
|
41581
|
+
limit: fetchLimit,
|
|
41582
|
+
inclusive: true,
|
|
41583
|
+
...cursor ? { cursor } : {}
|
|
41584
|
+
});
|
|
41585
|
+
for (const message of response.messages ?? []) {
|
|
41586
|
+
const text = resolveSlackThreadMessageText(message);
|
|
41587
|
+
if (!text) {
|
|
41588
|
+
continue;
|
|
41589
|
+
}
|
|
41590
|
+
if (params.currentMessageTs && message.ts === params.currentMessageTs) {
|
|
41591
|
+
continue;
|
|
41592
|
+
}
|
|
41593
|
+
if (message.ts === params.threadTs) {
|
|
41594
|
+
continue;
|
|
41595
|
+
}
|
|
41596
|
+
retained.push(message);
|
|
41597
|
+
if (retained.length > maxMessages) {
|
|
41598
|
+
retained.shift();
|
|
41599
|
+
}
|
|
41600
|
+
}
|
|
41601
|
+
const nextCursor = response.response_metadata?.next_cursor;
|
|
41602
|
+
cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
|
|
41603
|
+
} while (cursor);
|
|
41604
|
+
return retained.map(mapSlackThreadMessage);
|
|
41605
|
+
} catch {
|
|
41606
|
+
return [];
|
|
41607
|
+
}
|
|
41608
|
+
}
|
|
41609
|
+
async function resolveSlackChannelHistory(params) {
|
|
41610
|
+
const maxMessages = params.limit ?? 20;
|
|
41611
|
+
if (!Number.isFinite(maxMessages) || maxMessages <= 0) {
|
|
41612
|
+
return [];
|
|
41613
|
+
}
|
|
41614
|
+
const fetchLimit = Math.min(Math.max(maxMessages * 3, maxMessages), 100);
|
|
41615
|
+
try {
|
|
41616
|
+
const response = await params.client.conversations.history({
|
|
41617
|
+
channel: params.channelId,
|
|
41618
|
+
latest: params.beforeTs,
|
|
41619
|
+
inclusive: false,
|
|
41620
|
+
limit: fetchLimit
|
|
41621
|
+
});
|
|
41622
|
+
const retained = (response.messages ?? []).filter((message) => {
|
|
41623
|
+
if (message.ts === params.beforeTs) {
|
|
41624
|
+
return false;
|
|
41625
|
+
}
|
|
41626
|
+
return Boolean(resolveSlackThreadMessageText(message));
|
|
41627
|
+
}).slice(0, fetchLimit).reverse();
|
|
41628
|
+
return retained.slice(-maxMessages).map(mapSlackThreadMessage);
|
|
41629
|
+
} catch {
|
|
41630
|
+
return [];
|
|
41631
|
+
}
|
|
41632
|
+
}
|
|
41416
41633
|
var MAX_SLACK_ATTACHMENTS = 8, MAX_SLACK_ATTACHMENT_BYTES, ALLOWED_SLACK_HOST_SUFFIXES;
|
|
41417
41634
|
var init_media2 = __esm(() => {
|
|
41418
41635
|
init_config();
|
|
@@ -41428,6 +41645,9 @@ var init_media2 = __esm(() => {
|
|
|
41428
41645
|
async function loadSlackBoltModule() {
|
|
41429
41646
|
return loadChannelRuntimeModule("slack", "@slack/bolt");
|
|
41430
41647
|
}
|
|
41648
|
+
async function loadSlackWebApiModule() {
|
|
41649
|
+
return loadChannelRuntimeModule("slack", "@slack/web-api");
|
|
41650
|
+
}
|
|
41431
41651
|
async function ensureSlackRuntimeInstalled() {
|
|
41432
41652
|
return ensureChannelRuntimeInstalled("slack");
|
|
41433
41653
|
}
|
|
@@ -41457,6 +41677,22 @@ function resolveSlackAppConstructor(mod) {
|
|
|
41457
41677
|
}
|
|
41458
41678
|
return App2;
|
|
41459
41679
|
}
|
|
41680
|
+
function resolveSlackWebClientModule(value) {
|
|
41681
|
+
if (!value || typeof value !== "object") {
|
|
41682
|
+
return null;
|
|
41683
|
+
}
|
|
41684
|
+
const webClient = Reflect.get(value, "WebClient");
|
|
41685
|
+
return isConstructorFunction(webClient) ? webClient : null;
|
|
41686
|
+
}
|
|
41687
|
+
function resolveSlackWebClientConstructor(mod) {
|
|
41688
|
+
const defaultExport = mod && typeof mod === "object" ? Reflect.get(mod, "default") : undefined;
|
|
41689
|
+
const nestedDefault = defaultExport && typeof defaultExport === "object" ? Reflect.get(defaultExport, "default") : undefined;
|
|
41690
|
+
const WebClient = resolveSlackWebClientModule(mod) ?? resolveSlackWebClientModule(defaultExport) ?? resolveSlackWebClientModule(nestedDefault) ?? (isConstructorFunction(defaultExport) ? defaultExport : null);
|
|
41691
|
+
if (!WebClient) {
|
|
41692
|
+
throw new Error('Installed Slack runtime did not export constructor "WebClient".');
|
|
41693
|
+
}
|
|
41694
|
+
return WebClient;
|
|
41695
|
+
}
|
|
41460
41696
|
function isNonEmptyString2(value) {
|
|
41461
41697
|
return typeof value === "string" && value.length > 0;
|
|
41462
41698
|
}
|
|
@@ -41499,7 +41735,7 @@ function resolveUploadMimeType(filePath) {
|
|
|
41499
41735
|
return;
|
|
41500
41736
|
}
|
|
41501
41737
|
}
|
|
41502
|
-
async function uploadSlackFile(
|
|
41738
|
+
async function uploadSlackFile(slackClient, msg) {
|
|
41503
41739
|
if (!msg.mediaPath) {
|
|
41504
41740
|
throw new Error("mediaPath is required for Slack file uploads.");
|
|
41505
41741
|
}
|
|
@@ -41507,7 +41743,7 @@ async function uploadSlackFile(slackApp, msg) {
|
|
|
41507
41743
|
const uploadFileName = msg.fileName ?? basename4(msg.mediaPath);
|
|
41508
41744
|
const uploadTitle = msg.title ?? uploadFileName;
|
|
41509
41745
|
const uploadMimeType = resolveUploadMimeType(uploadFileName);
|
|
41510
|
-
const uploadUrlResp = await
|
|
41746
|
+
const uploadUrlResp = await slackClient.files.getUploadURLExternal({
|
|
41511
41747
|
filename: uploadFileName,
|
|
41512
41748
|
length: buffer.length
|
|
41513
41749
|
});
|
|
@@ -41522,7 +41758,7 @@ async function uploadSlackFile(slackApp, msg) {
|
|
|
41522
41758
|
if (!uploadResp.ok) {
|
|
41523
41759
|
throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
|
|
41524
41760
|
}
|
|
41525
|
-
const completeResp = await
|
|
41761
|
+
const completeResp = await slackClient.files.completeUploadExternal({
|
|
41526
41762
|
files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
|
|
41527
41763
|
channel_id: msg.chatId,
|
|
41528
41764
|
...msg.text.trim() ? { initial_comment: msg.text } : {},
|
|
@@ -41538,6 +41774,34 @@ function resolveSlackUserDisplayName(userInfo) {
|
|
|
41538
41774
|
const profile = asRecord2(user?.profile);
|
|
41539
41775
|
return firstNonEmptyString(profile?.display_name, profile?.real_name, user?.name);
|
|
41540
41776
|
}
|
|
41777
|
+
function truncateSlackThreadLabel(text, maxLength = 80) {
|
|
41778
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
41779
|
+
if (!normalized) {
|
|
41780
|
+
return null;
|
|
41781
|
+
}
|
|
41782
|
+
if (normalized.length <= maxLength) {
|
|
41783
|
+
return normalized;
|
|
41784
|
+
}
|
|
41785
|
+
return `${normalized.slice(0, maxLength - 1).trimEnd()}…`;
|
|
41786
|
+
}
|
|
41787
|
+
function buildSlackThreadLabel(msg, starterText) {
|
|
41788
|
+
if (msg.chatType !== "channel") {
|
|
41789
|
+
return;
|
|
41790
|
+
}
|
|
41791
|
+
const roomLabel = isNonEmptyString2(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
41792
|
+
const preview = truncateSlackThreadLabel(starterText ?? msg.text);
|
|
41793
|
+
if (preview) {
|
|
41794
|
+
return `Slack thread${roomLabel}: ${preview}`;
|
|
41795
|
+
}
|
|
41796
|
+
return roomLabel ? `Slack thread${roomLabel}` : `Slack thread ${msg.chatId}`;
|
|
41797
|
+
}
|
|
41798
|
+
function buildSlackChannelContextLabel(msg) {
|
|
41799
|
+
if (msg.chatType !== "channel") {
|
|
41800
|
+
return;
|
|
41801
|
+
}
|
|
41802
|
+
const roomLabel = isNonEmptyString2(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
41803
|
+
return roomLabel ? `Slack channel context${roomLabel} before thread start` : `Slack channel context before thread start`;
|
|
41804
|
+
}
|
|
41541
41805
|
async function resolveSlackAccountDisplayName(botToken, appToken) {
|
|
41542
41806
|
const bolt = await loadSlackBoltModule();
|
|
41543
41807
|
const App2 = resolveSlackAppConstructor(bolt);
|
|
@@ -41563,11 +41827,14 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
|
|
|
41563
41827
|
}
|
|
41564
41828
|
function createSlackAdapter(config) {
|
|
41565
41829
|
let app = null;
|
|
41830
|
+
let writeClient = null;
|
|
41566
41831
|
let running = false;
|
|
41567
41832
|
let botUserId = null;
|
|
41568
41833
|
const knownThreadIdsByMessageId = new Map;
|
|
41569
41834
|
const knownUserDisplayNames = new Map;
|
|
41570
41835
|
const seenIngressMessageKeys = new Map;
|
|
41836
|
+
const lifecycleStateByMessageKey = new Map;
|
|
41837
|
+
const lifecycleOperationByMessageKey = new Map;
|
|
41571
41838
|
function buildIngressMessageKey(channelId, messageId) {
|
|
41572
41839
|
if (!isNonEmptyString2(channelId) || !isNonEmptyString2(messageId)) {
|
|
41573
41840
|
return null;
|
|
@@ -41592,6 +41859,96 @@ function createSlackAdapter(config) {
|
|
|
41592
41859
|
}
|
|
41593
41860
|
}
|
|
41594
41861
|
}
|
|
41862
|
+
function getLifecycleMessageKey(source) {
|
|
41863
|
+
if (source.channel !== "slack" || !isNonEmptyString2(source.chatId) || !isNonEmptyString2(source.messageId)) {
|
|
41864
|
+
return null;
|
|
41865
|
+
}
|
|
41866
|
+
return `${source.chatId}:${source.messageId}`;
|
|
41867
|
+
}
|
|
41868
|
+
function pruneLifecycleState(now = Date.now()) {
|
|
41869
|
+
for (const [key, entry] of lifecycleStateByMessageKey) {
|
|
41870
|
+
if (entry.updatedAt + SLACK_LIFECYCLE_STATE_TTL_MS <= now) {
|
|
41871
|
+
lifecycleStateByMessageKey.delete(key);
|
|
41872
|
+
}
|
|
41873
|
+
}
|
|
41874
|
+
if (lifecycleStateByMessageKey.size <= SLACK_LIFECYCLE_STATE_MAX) {
|
|
41875
|
+
return;
|
|
41876
|
+
}
|
|
41877
|
+
const oldestEntries = Array.from(lifecycleStateByMessageKey.entries()).sort((a, b) => a[1].updatedAt - b[1].updatedAt);
|
|
41878
|
+
const overflowCount = lifecycleStateByMessageKey.size - SLACK_LIFECYCLE_STATE_MAX;
|
|
41879
|
+
for (let index = 0;index < overflowCount; index += 1) {
|
|
41880
|
+
const entry = oldestEntries[index];
|
|
41881
|
+
if (entry) {
|
|
41882
|
+
lifecycleStateByMessageKey.delete(entry[0]);
|
|
41883
|
+
}
|
|
41884
|
+
}
|
|
41885
|
+
}
|
|
41886
|
+
async function sendLifecycleReaction(source, emoji, removeReaction = false) {
|
|
41887
|
+
if (!isNonEmptyString2(source.messageId)) {
|
|
41888
|
+
return;
|
|
41889
|
+
}
|
|
41890
|
+
await ensureApp();
|
|
41891
|
+
const slackClient = await ensureWriteClient();
|
|
41892
|
+
if (removeReaction) {
|
|
41893
|
+
await slackClient.reactions.remove({
|
|
41894
|
+
channel: source.chatId,
|
|
41895
|
+
timestamp: source.messageId,
|
|
41896
|
+
name: emoji
|
|
41897
|
+
});
|
|
41898
|
+
return;
|
|
41899
|
+
}
|
|
41900
|
+
await slackClient.reactions.add({
|
|
41901
|
+
channel: source.chatId,
|
|
41902
|
+
timestamp: source.messageId,
|
|
41903
|
+
name: emoji
|
|
41904
|
+
});
|
|
41905
|
+
}
|
|
41906
|
+
function scheduleLifecycleTransition(source, nextState) {
|
|
41907
|
+
const key = getLifecycleMessageKey(source);
|
|
41908
|
+
if (!key) {
|
|
41909
|
+
return null;
|
|
41910
|
+
}
|
|
41911
|
+
const previous = lifecycleOperationByMessageKey.get(key) ?? Promise.resolve();
|
|
41912
|
+
const operation = previous.catch(() => {}).then(async () => {
|
|
41913
|
+
pruneLifecycleState();
|
|
41914
|
+
const currentState = lifecycleStateByMessageKey.get(key)?.state;
|
|
41915
|
+
if (currentState === nextState) {
|
|
41916
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41917
|
+
state: nextState,
|
|
41918
|
+
updatedAt: Date.now()
|
|
41919
|
+
});
|
|
41920
|
+
return;
|
|
41921
|
+
}
|
|
41922
|
+
if (nextState === "queued") {
|
|
41923
|
+
if (!currentState) {
|
|
41924
|
+
await sendLifecycleReaction(source, "eyes");
|
|
41925
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41926
|
+
state: nextState,
|
|
41927
|
+
updatedAt: Date.now()
|
|
41928
|
+
});
|
|
41929
|
+
}
|
|
41930
|
+
return;
|
|
41931
|
+
}
|
|
41932
|
+
if (currentState === "queued") {
|
|
41933
|
+
try {
|
|
41934
|
+
await sendLifecycleReaction(source, "eyes", true);
|
|
41935
|
+
} catch {}
|
|
41936
|
+
}
|
|
41937
|
+
await sendLifecycleReaction(source, nextState === "completed" ? "white_check_mark" : "x");
|
|
41938
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41939
|
+
state: nextState,
|
|
41940
|
+
updatedAt: Date.now()
|
|
41941
|
+
});
|
|
41942
|
+
}).catch((error) => {
|
|
41943
|
+
console.warn(`[Slack] Failed to update lifecycle reaction for ${key}:`, error instanceof Error ? error.message : error);
|
|
41944
|
+
}).finally(() => {
|
|
41945
|
+
if (lifecycleOperationByMessageKey.get(key) === operation) {
|
|
41946
|
+
lifecycleOperationByMessageKey.delete(key);
|
|
41947
|
+
}
|
|
41948
|
+
});
|
|
41949
|
+
lifecycleOperationByMessageKey.set(key, operation);
|
|
41950
|
+
return operation;
|
|
41951
|
+
}
|
|
41595
41952
|
function markIngressMessageSeen(channelId, messageId) {
|
|
41596
41953
|
const key = buildIngressMessageKey(channelId, messageId);
|
|
41597
41954
|
if (!key) {
|
|
@@ -41815,6 +42172,19 @@ function createSlackAdapter(config) {
|
|
|
41815
42172
|
app = instance;
|
|
41816
42173
|
return instance;
|
|
41817
42174
|
}
|
|
42175
|
+
async function ensureWriteClient() {
|
|
42176
|
+
if (writeClient) {
|
|
42177
|
+
return writeClient;
|
|
42178
|
+
}
|
|
42179
|
+
const webApi = await loadSlackWebApiModule();
|
|
42180
|
+
const WebClient = resolveSlackWebClientConstructor(webApi);
|
|
42181
|
+
writeClient = new WebClient(config.botToken, {
|
|
42182
|
+
retryConfig: {
|
|
42183
|
+
retries: 0
|
|
42184
|
+
}
|
|
42185
|
+
});
|
|
42186
|
+
return writeClient;
|
|
42187
|
+
}
|
|
41818
42188
|
const adapter = {
|
|
41819
42189
|
id: `slack:${config.accountId}`,
|
|
41820
42190
|
channelId: "slack",
|
|
@@ -41838,15 +42208,33 @@ function createSlackAdapter(config) {
|
|
|
41838
42208
|
await app.stop();
|
|
41839
42209
|
running = false;
|
|
41840
42210
|
app = null;
|
|
42211
|
+
writeClient = null;
|
|
41841
42212
|
botUserId = null;
|
|
41842
42213
|
seenIngressMessageKeys.clear();
|
|
42214
|
+
lifecycleStateByMessageKey.clear();
|
|
42215
|
+
lifecycleOperationByMessageKey.clear();
|
|
41843
42216
|
console.log("[Slack] App stopped");
|
|
41844
42217
|
},
|
|
41845
42218
|
isRunning() {
|
|
41846
42219
|
return running;
|
|
41847
42220
|
},
|
|
42221
|
+
async handleTurnLifecycleEvent(event) {
|
|
42222
|
+
if (!running) {
|
|
42223
|
+
return;
|
|
42224
|
+
}
|
|
42225
|
+
if (event.type === "queued") {
|
|
42226
|
+
await scheduleLifecycleTransition(event.source, "queued");
|
|
42227
|
+
return;
|
|
42228
|
+
}
|
|
42229
|
+
if (event.type === "processing") {
|
|
42230
|
+
return;
|
|
42231
|
+
}
|
|
42232
|
+
const nextState = event.outcome === "completed" ? "completed" : event.outcome === "cancelled" ? "cancelled" : "error";
|
|
42233
|
+
await Promise.all(event.sources.map((source) => scheduleLifecycleTransition(source, nextState)));
|
|
42234
|
+
},
|
|
41848
42235
|
async sendMessage(msg) {
|
|
41849
|
-
|
|
42236
|
+
await ensureApp();
|
|
42237
|
+
const slackClient = await ensureWriteClient();
|
|
41850
42238
|
if (msg.reaction) {
|
|
41851
42239
|
const targetMessageId = msg.targetMessageId ?? msg.replyToMessageId;
|
|
41852
42240
|
if (!targetMessageId) {
|
|
@@ -41857,13 +42245,13 @@ function createSlackAdapter(config) {
|
|
|
41857
42245
|
throw new Error("Slack reaction emoji cannot be empty.");
|
|
41858
42246
|
}
|
|
41859
42247
|
if (msg.removeReaction) {
|
|
41860
|
-
await
|
|
42248
|
+
await slackClient.reactions.remove({
|
|
41861
42249
|
channel: msg.chatId,
|
|
41862
42250
|
timestamp: targetMessageId,
|
|
41863
42251
|
name: emoji
|
|
41864
42252
|
});
|
|
41865
42253
|
} else {
|
|
41866
|
-
await
|
|
42254
|
+
await slackClient.reactions.add({
|
|
41867
42255
|
channel: msg.chatId,
|
|
41868
42256
|
timestamp: targetMessageId,
|
|
41869
42257
|
name: emoji
|
|
@@ -41872,9 +42260,9 @@ function createSlackAdapter(config) {
|
|
|
41872
42260
|
return { messageId: targetMessageId };
|
|
41873
42261
|
}
|
|
41874
42262
|
if (msg.mediaPath) {
|
|
41875
|
-
return uploadSlackFile(
|
|
42263
|
+
return uploadSlackFile(slackClient, msg);
|
|
41876
42264
|
}
|
|
41877
|
-
const response = await
|
|
42265
|
+
const response = await slackClient.chat.postMessage({
|
|
41878
42266
|
channel: msg.chatId,
|
|
41879
42267
|
text: msg.text,
|
|
41880
42268
|
...msg.threadId ?? msg.replyToMessageId ? { thread_ts: msg.threadId ?? msg.replyToMessageId } : {}
|
|
@@ -41883,22 +42271,98 @@ function createSlackAdapter(config) {
|
|
|
41883
42271
|
return { messageId: response.ts ?? "" };
|
|
41884
42272
|
},
|
|
41885
42273
|
async sendDirectReply(chatId, text, options) {
|
|
41886
|
-
|
|
41887
|
-
const
|
|
42274
|
+
await ensureApp();
|
|
42275
|
+
const slackClient = await ensureWriteClient();
|
|
42276
|
+
const response = await slackClient.chat.postMessage({
|
|
41888
42277
|
channel: chatId,
|
|
41889
42278
|
text,
|
|
41890
42279
|
...options?.replyToMessageId ? { thread_ts: options.replyToMessageId } : {}
|
|
41891
42280
|
});
|
|
41892
42281
|
rememberMessageThread(response.ts, options?.replyToMessageId ?? response.ts ?? null);
|
|
41893
42282
|
},
|
|
42283
|
+
async prepareInboundMessage(msg, options) {
|
|
42284
|
+
if (!options?.isFirstRouteTurn || msg.channel !== "slack" || msg.chatType !== "channel" || !isNonEmptyString2(msg.threadId) || !isNonEmptyString2(msg.messageId)) {
|
|
42285
|
+
return msg;
|
|
42286
|
+
}
|
|
42287
|
+
const shouldHydrateExistingThreadContext = msg.threadId !== msg.messageId;
|
|
42288
|
+
const shouldHydrateChannelBootstrapContext = msg.isMention === true && msg.threadId === msg.messageId;
|
|
42289
|
+
if (!shouldHydrateExistingThreadContext && !shouldHydrateChannelBootstrapContext) {
|
|
42290
|
+
return msg;
|
|
42291
|
+
}
|
|
42292
|
+
const slackApp = await ensureApp();
|
|
42293
|
+
const starter = shouldHydrateExistingThreadContext ? await resolveSlackThreadStarter({
|
|
42294
|
+
channelId: msg.chatId,
|
|
42295
|
+
threadTs: msg.threadId,
|
|
42296
|
+
client: slackApp.client
|
|
42297
|
+
}) : null;
|
|
42298
|
+
const history = shouldHydrateExistingThreadContext ? await resolveSlackThreadHistory({
|
|
42299
|
+
channelId: msg.chatId,
|
|
42300
|
+
threadTs: msg.threadId,
|
|
42301
|
+
client: slackApp.client,
|
|
42302
|
+
currentMessageTs: msg.messageId,
|
|
42303
|
+
limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT
|
|
42304
|
+
}) : await resolveSlackChannelHistory({
|
|
42305
|
+
channelId: msg.chatId,
|
|
42306
|
+
beforeTs: msg.messageId,
|
|
42307
|
+
client: slackApp.client,
|
|
42308
|
+
limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT
|
|
42309
|
+
});
|
|
42310
|
+
if (!starter && history.length === 0) {
|
|
42311
|
+
return msg;
|
|
42312
|
+
}
|
|
42313
|
+
const uniqueUserIds = new Set;
|
|
42314
|
+
if (isNonEmptyString2(starter?.userId)) {
|
|
42315
|
+
uniqueUserIds.add(starter.userId);
|
|
42316
|
+
}
|
|
42317
|
+
for (const entry of history) {
|
|
42318
|
+
if (isNonEmptyString2(entry.userId)) {
|
|
42319
|
+
uniqueUserIds.add(entry.userId);
|
|
42320
|
+
}
|
|
42321
|
+
}
|
|
42322
|
+
await Promise.all(Array.from(uniqueUserIds).map(async (userId) => {
|
|
42323
|
+
await resolveUserName(slackApp, userId);
|
|
42324
|
+
}));
|
|
42325
|
+
const resolveThreadSenderName = (userId, botId) => {
|
|
42326
|
+
if (isNonEmptyString2(userId)) {
|
|
42327
|
+
return knownUserDisplayNames.get(userId) ?? userId;
|
|
42328
|
+
}
|
|
42329
|
+
if (isNonEmptyString2(botId)) {
|
|
42330
|
+
return `Bot (${botId})`;
|
|
42331
|
+
}
|
|
42332
|
+
return;
|
|
42333
|
+
};
|
|
42334
|
+
return {
|
|
42335
|
+
...msg,
|
|
42336
|
+
threadContext: {
|
|
42337
|
+
label: shouldHydrateExistingThreadContext ? buildSlackThreadLabel(msg, starter?.text) : buildSlackChannelContextLabel(msg),
|
|
42338
|
+
...starter ? {
|
|
42339
|
+
starter: {
|
|
42340
|
+
messageId: starter.ts,
|
|
42341
|
+
senderId: starter.userId ?? starter.botId,
|
|
42342
|
+
senderName: resolveThreadSenderName(starter.userId, starter.botId),
|
|
42343
|
+
text: starter.text
|
|
42344
|
+
}
|
|
42345
|
+
} : {},
|
|
42346
|
+
...history.length > 0 ? {
|
|
42347
|
+
history: history.map((entry) => ({
|
|
42348
|
+
messageId: entry.ts,
|
|
42349
|
+
senderId: entry.userId ?? entry.botId,
|
|
42350
|
+
senderName: resolveThreadSenderName(entry.userId, entry.botId),
|
|
42351
|
+
text: entry.text
|
|
42352
|
+
}))
|
|
42353
|
+
} : {}
|
|
42354
|
+
}
|
|
42355
|
+
};
|
|
42356
|
+
},
|
|
41894
42357
|
onMessage: undefined
|
|
41895
42358
|
};
|
|
41896
42359
|
return adapter;
|
|
41897
42360
|
}
|
|
41898
|
-
var SLACK_INGRESS_DEDUPE_TTL_MS = 60000, SLACK_INGRESS_DEDUPE_MAX = 2000;
|
|
42361
|
+
var INITIAL_SLACK_THREAD_HISTORY_LIMIT = 20, SLACK_INGRESS_DEDUPE_TTL_MS = 60000, SLACK_INGRESS_DEDUPE_MAX = 2000, SLACK_LIFECYCLE_STATE_TTL_MS, SLACK_LIFECYCLE_STATE_MAX = 2000;
|
|
41899
42362
|
var init_adapter2 = __esm(() => {
|
|
41900
42363
|
init_media2();
|
|
41901
42364
|
init_runtime2();
|
|
42365
|
+
SLACK_LIFECYCLE_STATE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
41902
42366
|
});
|
|
41903
42367
|
|
|
41904
42368
|
// src/channels/slack/messageActions.ts
|
|
@@ -42040,6 +42504,7 @@ DM Policy — who can message this app directly?
|
|
|
42040
42504
|
botToken,
|
|
42041
42505
|
appToken,
|
|
42042
42506
|
agentId: null,
|
|
42507
|
+
defaultPermissionMode: "default",
|
|
42043
42508
|
dmPolicy: policy,
|
|
42044
42509
|
allowedUsers,
|
|
42045
42510
|
createdAt: now,
|
|
@@ -42081,8 +42546,8 @@ var init_plugin2 = __esm(() => {
|
|
|
42081
42546
|
metadata: {
|
|
42082
42547
|
id: "slack",
|
|
42083
42548
|
displayName: "Slack",
|
|
42084
|
-
runtimePackages: ["@slack/bolt@4.7.0"],
|
|
42085
|
-
runtimeModules: ["@slack/bolt"]
|
|
42549
|
+
runtimePackages: ["@slack/bolt@4.7.0", "@slack/web-api@7.15.0"],
|
|
42550
|
+
runtimeModules: ["@slack/bolt", "@slack/web-api"]
|
|
42086
42551
|
},
|
|
42087
42552
|
createAdapter(account) {
|
|
42088
42553
|
return createSlackAdapter(account);
|
|
@@ -42138,8 +42603,8 @@ var init_pluginRegistry = __esm(() => {
|
|
|
42138
42603
|
metadata: {
|
|
42139
42604
|
id: "slack",
|
|
42140
42605
|
displayName: "Slack",
|
|
42141
|
-
runtimePackages: ["@slack/bolt@4.7.0"],
|
|
42142
|
-
runtimeModules: ["@slack/bolt"]
|
|
42606
|
+
runtimePackages: ["@slack/bolt@4.7.0", "@slack/web-api@7.15.0"],
|
|
42607
|
+
runtimeModules: ["@slack/bolt", "@slack/web-api"]
|
|
42143
42608
|
},
|
|
42144
42609
|
load: async () => {
|
|
42145
42610
|
const { slackChannelPlugin: slackChannelPlugin2 } = await Promise.resolve().then(() => (init_plugin2(), exports_plugin2));
|
|
@@ -42724,6 +43189,47 @@ function buildReactionXml(msg) {
|
|
|
42724
43189
|
}
|
|
42725
43190
|
return `<reaction ${attrs.join(" ")} />`;
|
|
42726
43191
|
}
|
|
43192
|
+
function buildThreadContextEntryXml(tagName, entry) {
|
|
43193
|
+
const attrs = [];
|
|
43194
|
+
if (entry.senderId) {
|
|
43195
|
+
attrs.push(`sender_id="${escapeXmlAttribute(entry.senderId)}"`);
|
|
43196
|
+
}
|
|
43197
|
+
if (entry.senderName) {
|
|
43198
|
+
attrs.push(`sender_name="${escapeXmlAttribute(entry.senderName)}"`);
|
|
43199
|
+
}
|
|
43200
|
+
if (entry.messageId) {
|
|
43201
|
+
attrs.push(`message_id="${escapeXmlAttribute(entry.messageId)}"`);
|
|
43202
|
+
}
|
|
43203
|
+
const attrString = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
43204
|
+
return `<${tagName}${attrString}>
|
|
43205
|
+
${escapeXmlText(entry.text)}
|
|
43206
|
+
</${tagName}>`;
|
|
43207
|
+
}
|
|
43208
|
+
function buildThreadContextXml(msg) {
|
|
43209
|
+
const threadContext = msg.threadContext;
|
|
43210
|
+
if (!threadContext) {
|
|
43211
|
+
return null;
|
|
43212
|
+
}
|
|
43213
|
+
const parts = [];
|
|
43214
|
+
if (threadContext.starter) {
|
|
43215
|
+
parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter));
|
|
43216
|
+
}
|
|
43217
|
+
const historyEntries = threadContext.history ?? [];
|
|
43218
|
+
if (historyEntries.length > 0) {
|
|
43219
|
+
parts.push([
|
|
43220
|
+
"<thread-history>",
|
|
43221
|
+
...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry)),
|
|
43222
|
+
"</thread-history>"
|
|
43223
|
+
].join(`
|
|
43224
|
+
`));
|
|
43225
|
+
}
|
|
43226
|
+
if (parts.length === 0) {
|
|
43227
|
+
return null;
|
|
43228
|
+
}
|
|
43229
|
+
const attrs = threadContext.label ? ` label="${escapeXmlAttribute(threadContext.label)}"` : "";
|
|
43230
|
+
return [`<thread-context${attrs}>`, ...parts, "</thread-context>"].join(`
|
|
43231
|
+
`);
|
|
43232
|
+
}
|
|
42727
43233
|
function buildChannelNotificationXml(msg) {
|
|
42728
43234
|
const attrs = [
|
|
42729
43235
|
`source="${escapeXmlAttribute(msg.channel)}"`,
|
|
@@ -42742,8 +43248,9 @@ function buildChannelNotificationXml(msg) {
|
|
|
42742
43248
|
const attrString = attrs.join(" ");
|
|
42743
43249
|
const escapedText = msg.text ? escapeXmlText(msg.text) : "";
|
|
42744
43250
|
const reactionXml = buildReactionXml(msg);
|
|
43251
|
+
const threadContextXml = buildThreadContextXml(msg);
|
|
42745
43252
|
const attachmentXml = (msg.attachments ?? []).map(buildAttachmentXml);
|
|
42746
|
-
const body = [reactionXml, ...attachmentXml, escapedText].filter(Boolean).join(`
|
|
43253
|
+
const body = [threadContextXml, reactionXml, ...attachmentXml, escapedText].filter(Boolean).join(`
|
|
42747
43254
|
`);
|
|
42748
43255
|
return `<channel-notification ${attrString}>
|
|
42749
43256
|
${body}
|
|
@@ -42828,6 +43335,18 @@ function buildSlackConversationSummary(msg) {
|
|
|
42828
43335
|
}
|
|
42829
43336
|
return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
42830
43337
|
}
|
|
43338
|
+
function buildChannelTurnSource(route, msg) {
|
|
43339
|
+
return {
|
|
43340
|
+
channel: msg.channel,
|
|
43341
|
+
accountId: msg.accountId,
|
|
43342
|
+
chatId: msg.chatId,
|
|
43343
|
+
chatType: msg.chatType,
|
|
43344
|
+
messageId: msg.messageId,
|
|
43345
|
+
threadId: msg.threadId,
|
|
43346
|
+
agentId: route.agentId,
|
|
43347
|
+
conversationId: route.conversationId
|
|
43348
|
+
};
|
|
43349
|
+
}
|
|
42831
43350
|
function getChannelRegistry() {
|
|
42832
43351
|
return instance;
|
|
42833
43352
|
}
|
|
@@ -42867,6 +43386,51 @@ class ChannelRegistry {
|
|
|
42867
43386
|
getActiveChannelIds() {
|
|
42868
43387
|
return Array.from(this.adapters.values()).filter((adapter) => adapter.isRunning()).map((adapter) => adapter.channelId ?? adapter.id);
|
|
42869
43388
|
}
|
|
43389
|
+
async dispatchTurnLifecycleEvent(event) {
|
|
43390
|
+
const groups = new Map;
|
|
43391
|
+
const sources = event.type === "queued" ? [event.source] : event.sources;
|
|
43392
|
+
for (const source of sources) {
|
|
43393
|
+
const adapter = this.getAdapter(source.channel, source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID);
|
|
43394
|
+
if (!adapter?.handleTurnLifecycleEvent) {
|
|
43395
|
+
continue;
|
|
43396
|
+
}
|
|
43397
|
+
const groupKey = this.getAdapterKey(source.channel, source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID);
|
|
43398
|
+
const existing = groups.get(groupKey);
|
|
43399
|
+
if (existing) {
|
|
43400
|
+
existing.sources.push(source);
|
|
43401
|
+
continue;
|
|
43402
|
+
}
|
|
43403
|
+
groups.set(groupKey, {
|
|
43404
|
+
adapter,
|
|
43405
|
+
sources: [source]
|
|
43406
|
+
});
|
|
43407
|
+
}
|
|
43408
|
+
for (const { adapter, sources: groupedSources } of groups.values()) {
|
|
43409
|
+
const handleTurnLifecycleEvent = adapter.handleTurnLifecycleEvent;
|
|
43410
|
+
if (!handleTurnLifecycleEvent) {
|
|
43411
|
+
continue;
|
|
43412
|
+
}
|
|
43413
|
+
try {
|
|
43414
|
+
if (event.type === "queued") {
|
|
43415
|
+
const [firstSource] = groupedSources;
|
|
43416
|
+
if (!firstSource) {
|
|
43417
|
+
continue;
|
|
43418
|
+
}
|
|
43419
|
+
await handleTurnLifecycleEvent({
|
|
43420
|
+
type: "queued",
|
|
43421
|
+
source: firstSource
|
|
43422
|
+
});
|
|
43423
|
+
continue;
|
|
43424
|
+
}
|
|
43425
|
+
await handleTurnLifecycleEvent({
|
|
43426
|
+
...event,
|
|
43427
|
+
sources: groupedSources
|
|
43428
|
+
});
|
|
43429
|
+
} catch (error) {
|
|
43430
|
+
console.error(`[Channels] Failed to handle ${event.type} lifecycle event for ${adapter.channelId ?? adapter.id}/${adapter.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID}:`, error instanceof Error ? error.message : error);
|
|
43431
|
+
}
|
|
43432
|
+
}
|
|
43433
|
+
}
|
|
42870
43434
|
setMessageHandler(handler) {
|
|
42871
43435
|
this.messageHandler = handler;
|
|
42872
43436
|
}
|
|
@@ -42985,11 +43549,20 @@ class ChannelRegistry {
|
|
|
42985
43549
|
if (!config)
|
|
42986
43550
|
return;
|
|
42987
43551
|
if (msg.channel === "slack" && config.channel === "slack") {
|
|
42988
|
-
const
|
|
42989
|
-
if (!
|
|
43552
|
+
const slackResult = await this.ensureSlackRoute(adapter, msg, config);
|
|
43553
|
+
if (!slackResult) {
|
|
42990
43554
|
return;
|
|
42991
43555
|
}
|
|
42992
|
-
|
|
43556
|
+
const preparedMessage = adapter.prepareInboundMessage ? await adapter.prepareInboundMessage(msg, {
|
|
43557
|
+
isFirstRouteTurn: slackResult.isFirstRouteTurn
|
|
43558
|
+
}) : msg;
|
|
43559
|
+
this.deliverOrBuffer({
|
|
43560
|
+
route: slackResult.route,
|
|
43561
|
+
content: formatChannelNotification(preparedMessage),
|
|
43562
|
+
turnSources: [
|
|
43563
|
+
buildChannelTurnSource(slackResult.route, preparedMessage)
|
|
43564
|
+
]
|
|
43565
|
+
});
|
|
42993
43566
|
return;
|
|
42994
43567
|
}
|
|
42995
43568
|
if (config.dmPolicy === "allowlist") {
|
|
@@ -43021,7 +43594,11 @@ class ChannelRegistry {
|
|
|
43021
43594
|
return;
|
|
43022
43595
|
}
|
|
43023
43596
|
const content = formatChannelNotification(msg);
|
|
43024
|
-
this.deliverOrBuffer(
|
|
43597
|
+
this.deliverOrBuffer({
|
|
43598
|
+
route,
|
|
43599
|
+
content,
|
|
43600
|
+
turnSources: [buildChannelTurnSource(route, msg)]
|
|
43601
|
+
});
|
|
43025
43602
|
}
|
|
43026
43603
|
async createConversationForAgent(agentId, summary) {
|
|
43027
43604
|
const client = await getClient();
|
|
@@ -43050,6 +43627,16 @@ class ChannelRegistry {
|
|
|
43050
43627
|
updatedAt: now
|
|
43051
43628
|
};
|
|
43052
43629
|
addRoute(msg.channel, route);
|
|
43630
|
+
if (config.defaultPermissionMode !== "default") {
|
|
43631
|
+
this.eventHandler?.({
|
|
43632
|
+
type: "slack_conversation_created",
|
|
43633
|
+
channelId: "slack",
|
|
43634
|
+
accountId: config.accountId,
|
|
43635
|
+
agentId: config.agentId,
|
|
43636
|
+
conversationId,
|
|
43637
|
+
defaultPermissionMode: config.defaultPermissionMode
|
|
43638
|
+
});
|
|
43639
|
+
}
|
|
43053
43640
|
return route;
|
|
43054
43641
|
}
|
|
43055
43642
|
async ensureSlackRoute(adapter, msg, config) {
|
|
@@ -43071,7 +43658,10 @@ class ChannelRegistry {
|
|
|
43071
43658
|
route = getRoute(msg.channel, msg.chatId, accountId, routeThreadId);
|
|
43072
43659
|
}
|
|
43073
43660
|
if (route) {
|
|
43074
|
-
return
|
|
43661
|
+
return {
|
|
43662
|
+
route,
|
|
43663
|
+
isFirstRouteTurn: false
|
|
43664
|
+
};
|
|
43075
43665
|
}
|
|
43076
43666
|
if (msg.chatType === "channel" && !msg.isMention) {
|
|
43077
43667
|
return null;
|
|
@@ -43092,14 +43682,17 @@ class ChannelRegistry {
|
|
|
43092
43682
|
type: "targets_updated",
|
|
43093
43683
|
channelId: msg.channel
|
|
43094
43684
|
});
|
|
43095
|
-
return
|
|
43685
|
+
return {
|
|
43686
|
+
route: await this.createSlackRoute(config, msg),
|
|
43687
|
+
isFirstRouteTurn: true
|
|
43688
|
+
};
|
|
43096
43689
|
}
|
|
43097
|
-
deliverOrBuffer(
|
|
43690
|
+
deliverOrBuffer(delivery) {
|
|
43098
43691
|
if (this.isReady()) {
|
|
43099
|
-
this.messageHandler?.(
|
|
43692
|
+
this.messageHandler?.(delivery);
|
|
43100
43693
|
return;
|
|
43101
43694
|
}
|
|
43102
|
-
this.buffer.push(
|
|
43695
|
+
this.buffer.push(delivery);
|
|
43103
43696
|
}
|
|
43104
43697
|
flushBuffer() {
|
|
43105
43698
|
if (!this.messageHandler)
|
|
@@ -43107,7 +43700,7 @@ class ChannelRegistry {
|
|
|
43107
43700
|
while (this.buffer.length > 0) {
|
|
43108
43701
|
const item = this.buffer.shift();
|
|
43109
43702
|
if (item) {
|
|
43110
|
-
this.messageHandler(item
|
|
43703
|
+
this.messageHandler(item);
|
|
43111
43704
|
}
|
|
43112
43705
|
}
|
|
43113
43706
|
}
|
|
@@ -45617,10 +46210,12 @@ var exports_memoryFilesystem = {};
|
|
|
45617
46210
|
__export(exports_memoryFilesystem, {
|
|
45618
46211
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree,
|
|
45619
46212
|
labelFromRelativePath: () => labelFromRelativePath,
|
|
46213
|
+
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer,
|
|
45620
46214
|
isLettaCloud: () => isLettaCloud,
|
|
45621
46215
|
getMemorySystemDir: () => getMemorySystemDir,
|
|
45622
46216
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot,
|
|
45623
46217
|
ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs,
|
|
46218
|
+
ensureLocalMemfsCheckout: () => ensureLocalMemfsCheckout,
|
|
45624
46219
|
enableMemfsIfCloud: () => enableMemfsIfCloud,
|
|
45625
46220
|
applyMemfsFlags: () => applyMemfsFlags,
|
|
45626
46221
|
MEMORY_TREE_MAX_LINES: () => MEMORY_TREE_MAX_LINES,
|
|
@@ -45650,6 +46245,23 @@ function ensureMemoryFilesystemDirs(agentId, homeDir = homedir10()) {
|
|
|
45650
46245
|
mkdirSync13(systemDir, { recursive: true });
|
|
45651
46246
|
}
|
|
45652
46247
|
}
|
|
46248
|
+
async function isMemfsEnabledOnServer(agentId) {
|
|
46249
|
+
const { getClient: getClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
46250
|
+
const client = await getClient3();
|
|
46251
|
+
const agent = await client.agents.retrieve(agentId);
|
|
46252
|
+
const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
46253
|
+
const enabled = agent.tags?.includes(GIT_MEMORY_ENABLED_TAG2) ?? false;
|
|
46254
|
+
const { settingsManager: settingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
46255
|
+
settingsManager2.setMemfsEnabled(agentId, enabled);
|
|
46256
|
+
return enabled;
|
|
46257
|
+
}
|
|
46258
|
+
async function ensureLocalMemfsCheckout(agentId) {
|
|
46259
|
+
const { isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
46260
|
+
if (isGitRepo2(agentId)) {
|
|
46261
|
+
return;
|
|
46262
|
+
}
|
|
46263
|
+
await cloneMemoryRepo2(agentId);
|
|
46264
|
+
}
|
|
45653
46265
|
function labelFromRelativePath(relativePath) {
|
|
45654
46266
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
45655
46267
|
return normalized.replace(/\.md$/, "");
|
|
@@ -49895,6 +50507,19 @@ function resolveLettaInvocation(env3 = process.env, argv = process.argv, execPat
|
|
|
49895
50507
|
}
|
|
49896
50508
|
const scriptPath = argv[1] || "";
|
|
49897
50509
|
if (scriptPath && isDevLettaEntryScript(scriptPath)) {
|
|
50510
|
+
const runtimeName = path4.basename(execPath).toLowerCase();
|
|
50511
|
+
if (runtimeName.includes("bun")) {
|
|
50512
|
+
return {
|
|
50513
|
+
command: execPath,
|
|
50514
|
+
args: [
|
|
50515
|
+
"--loader:.md=text",
|
|
50516
|
+
"--loader:.mdx=text",
|
|
50517
|
+
"--loader:.txt=text",
|
|
50518
|
+
"run",
|
|
50519
|
+
scriptPath
|
|
50520
|
+
]
|
|
50521
|
+
};
|
|
50522
|
+
}
|
|
49898
50523
|
return { command: execPath, args: [scriptPath] };
|
|
49899
50524
|
}
|
|
49900
50525
|
return null;
|
|
@@ -74195,7 +74820,12 @@ async function executeTool(name, args, options) {
|
|
|
74195
74820
|
enhancedArgs = { ...enhancedArgs, signal: options.signal };
|
|
74196
74821
|
}
|
|
74197
74822
|
if (options?.onOutput) {
|
|
74198
|
-
enhancedArgs = {
|
|
74823
|
+
enhancedArgs = {
|
|
74824
|
+
...enhancedArgs,
|
|
74825
|
+
onOutput: (chunk, stream2) => {
|
|
74826
|
+
options.onOutput?.(scrubSecretsFromString(chunk), stream2);
|
|
74827
|
+
}
|
|
74828
|
+
};
|
|
74199
74829
|
}
|
|
74200
74830
|
enhancedArgs = substituteSecretsInArgs(enhancedArgs);
|
|
74201
74831
|
}
|
|
@@ -74695,6 +75325,7 @@ function toAccountSnapshot(account) {
|
|
|
74695
75325
|
hasBotToken: account.botToken.trim().length > 0,
|
|
74696
75326
|
hasAppToken: account.appToken.trim().length > 0,
|
|
74697
75327
|
agentId: account.agentId,
|
|
75328
|
+
defaultPermissionMode: account.defaultPermissionMode ?? "default",
|
|
74698
75329
|
createdAt: account.createdAt,
|
|
74699
75330
|
updatedAt: account.updatedAt
|
|
74700
75331
|
};
|
|
@@ -74727,6 +75358,7 @@ function createAccountFromPatch(channelId, accountId, patch) {
|
|
|
74727
75358
|
botToken: patch.botToken ?? "",
|
|
74728
75359
|
appToken: patch.appToken ?? "",
|
|
74729
75360
|
agentId: patch.agentId ?? null,
|
|
75361
|
+
defaultPermissionMode: patch.defaultPermissionMode ?? "default",
|
|
74730
75362
|
dmPolicy: patch.dmPolicy ?? "open",
|
|
74731
75363
|
allowedUsers: patch.allowedUsers ?? [],
|
|
74732
75364
|
createdAt: now,
|
|
@@ -74754,6 +75386,7 @@ function mergeAccountPatch(existing, patch) {
|
|
|
74754
75386
|
botToken: patch.botToken ?? existing.botToken,
|
|
74755
75387
|
appToken: patch.appToken ?? existing.appToken,
|
|
74756
75388
|
agentId: patch.agentId ?? existing.agentId,
|
|
75389
|
+
defaultPermissionMode: patch.defaultPermissionMode ?? existing.defaultPermissionMode ?? "default",
|
|
74757
75390
|
dmPolicy: patch.dmPolicy ?? existing.dmPolicy,
|
|
74758
75391
|
allowedUsers: patch.allowedUsers ?? existing.allowedUsers,
|
|
74759
75392
|
updatedAt: nextUpdatedAt
|
|
@@ -76790,7 +77423,7 @@ function addTask(input) {
|
|
|
76790
77423
|
prompt: input.prompt,
|
|
76791
77424
|
status: "active",
|
|
76792
77425
|
created_at: now.toISOString(),
|
|
76793
|
-
expires_at:
|
|
77426
|
+
expires_at: null,
|
|
76794
77427
|
last_fired_at: null,
|
|
76795
77428
|
fire_count: 0,
|
|
76796
77429
|
cancel_reason: null,
|
|
@@ -76918,10 +77551,9 @@ function getCronFileMtime() {
|
|
|
76918
77551
|
return 0;
|
|
76919
77552
|
}
|
|
76920
77553
|
}
|
|
76921
|
-
var CRON_FILE_NAME = "crons.json", LOCK_DIR_NAME = "crons.lock", LOCK_TOKEN_FILE = "owner.json", LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 50, LOCK_STALE_AGE_MS = 30000, MAX_ACTIVE_TASKS_PER_AGENT = 50, TASK_ID_BYTES = 4,
|
|
77554
|
+
var CRON_FILE_NAME = "crons.json", LOCK_DIR_NAME = "crons.lock", LOCK_TOKEN_FILE = "owner.json", LOCK_TIMEOUT_MS = 5000, LOCK_RETRY_MS = 50, LOCK_STALE_AGE_MS = 30000, MAX_ACTIVE_TASKS_PER_AGENT = 50, TASK_ID_BYTES = 4, GC_AGE_MS;
|
|
76922
77555
|
var init_cronFile = __esm(() => {
|
|
76923
77556
|
init_parseInterval();
|
|
76924
|
-
DEFAULT_TTL_MS = 3 * 24 * 60 * 60 * 1000;
|
|
76925
77557
|
GC_AGE_MS = 24 * 60 * 60 * 1000;
|
|
76926
77558
|
});
|
|
76927
77559
|
|
|
@@ -83968,6 +84600,25 @@ function normalizeInterruptOutputLines(value) {
|
|
|
83968
84600
|
const combinedLength = filtered.reduce((sum, entry) => sum + entry.length, 0);
|
|
83969
84601
|
return combinedLength <= INTERRUPT_TOOL_RETURN_MAX_CHARS ? filtered : undefined;
|
|
83970
84602
|
}
|
|
84603
|
+
function appendStreamingOutputWithCap(current, chunk) {
|
|
84604
|
+
if (chunk.length === 0) {
|
|
84605
|
+
return current;
|
|
84606
|
+
}
|
|
84607
|
+
const next = `${current}${chunk}`;
|
|
84608
|
+
if (next.length <= STREAMING_TOOL_OUTPUT_MAX_CHARS) {
|
|
84609
|
+
return next;
|
|
84610
|
+
}
|
|
84611
|
+
return next.slice(next.length - STREAMING_TOOL_OUTPUT_MAX_CHARS);
|
|
84612
|
+
}
|
|
84613
|
+
function normalizeStreamingOutputLines(text) {
|
|
84614
|
+
if (text.length === 0) {
|
|
84615
|
+
return;
|
|
84616
|
+
}
|
|
84617
|
+
const lines = text.replace(/\r\n/g, `
|
|
84618
|
+
`).split(`
|
|
84619
|
+
`).filter((line) => line.length > 0);
|
|
84620
|
+
return lines.length > 0 ? lines : undefined;
|
|
84621
|
+
}
|
|
83971
84622
|
function asToolReturnStatus(value) {
|
|
83972
84623
|
if (value === "success" || value === "error") {
|
|
83973
84624
|
return value;
|
|
@@ -84181,6 +84832,54 @@ function emitToolExecutionFinishedEvents(socket, runtime, params) {
|
|
|
84181
84832
|
});
|
|
84182
84833
|
}
|
|
84183
84834
|
}
|
|
84835
|
+
function createToolExecutionOutputEmitter(socket, runtime, params) {
|
|
84836
|
+
const outputByToolCallId = new Map;
|
|
84837
|
+
return (toolCallId, chunk, isStderr = false) => {
|
|
84838
|
+
if (!toolCallId || chunk.length === 0) {
|
|
84839
|
+
return;
|
|
84840
|
+
}
|
|
84841
|
+
const existing = outputByToolCallId.get(toolCallId);
|
|
84842
|
+
const outputState = existing ?? {
|
|
84843
|
+
messageId: `message-tool-return-stream-${toolCallId}`,
|
|
84844
|
+
stdout: "",
|
|
84845
|
+
stderr: ""
|
|
84846
|
+
};
|
|
84847
|
+
if (isStderr) {
|
|
84848
|
+
outputState.stderr = appendStreamingOutputWithCap(outputState.stderr, chunk);
|
|
84849
|
+
} else {
|
|
84850
|
+
outputState.stdout = appendStreamingOutputWithCap(outputState.stdout, chunk);
|
|
84851
|
+
}
|
|
84852
|
+
outputByToolCallId.set(toolCallId, outputState);
|
|
84853
|
+
const stdout = normalizeStreamingOutputLines(outputState.stdout);
|
|
84854
|
+
const stderr = normalizeStreamingOutputLines(outputState.stderr);
|
|
84855
|
+
const toolReturn = [stdout?.join(`
|
|
84856
|
+
`), stderr?.join(`
|
|
84857
|
+
`)].filter((part) => typeof part === "string" && part.length > 0).join(`
|
|
84858
|
+
`);
|
|
84859
|
+
emitCanonicalMessageDelta(socket, runtime, {
|
|
84860
|
+
type: "message",
|
|
84861
|
+
message_type: "tool_return_message",
|
|
84862
|
+
id: outputState.messageId,
|
|
84863
|
+
date: new Date().toISOString(),
|
|
84864
|
+
run_id: params.runId ?? runtime.activeRunId ?? undefined,
|
|
84865
|
+
status: "success",
|
|
84866
|
+
tool_call_id: toolCallId,
|
|
84867
|
+
tool_return: toolReturn,
|
|
84868
|
+
tool_returns: [
|
|
84869
|
+
{
|
|
84870
|
+
tool_call_id: toolCallId,
|
|
84871
|
+
status: "success",
|
|
84872
|
+
tool_return: toolReturn,
|
|
84873
|
+
...stdout ? { stdout } : {},
|
|
84874
|
+
...stderr ? { stderr } : {}
|
|
84875
|
+
}
|
|
84876
|
+
]
|
|
84877
|
+
}, {
|
|
84878
|
+
agent_id: params.agentId,
|
|
84879
|
+
conversation_id: params.conversationId
|
|
84880
|
+
});
|
|
84881
|
+
};
|
|
84882
|
+
}
|
|
84184
84883
|
function getInterruptApprovalsForEmission(runtime, params) {
|
|
84185
84884
|
if (params.lastExecutionResults && params.lastExecutionResults.length > 0) {
|
|
84186
84885
|
return params.lastExecutionResults;
|
|
@@ -84297,7 +84996,7 @@ function stashRecoveredApprovalInterrupts(runtime, recovered) {
|
|
|
84297
84996
|
clearRecoveredApprovalState(runtime);
|
|
84298
84997
|
return true;
|
|
84299
84998
|
}
|
|
84300
|
-
var INTERRUPT_TOOL_RETURN_MAX_CHARS;
|
|
84999
|
+
var INTERRUPT_TOOL_RETURN_MAX_CHARS, STREAMING_TOOL_OUTPUT_MAX_CHARS;
|
|
84301
85000
|
var init_interrupts = __esm(async () => {
|
|
84302
85001
|
init_approval_result_normalization();
|
|
84303
85002
|
init_constants();
|
|
@@ -84309,6 +85008,7 @@ var init_interrupts = __esm(async () => {
|
|
|
84309
85008
|
init_protocol_outbound()
|
|
84310
85009
|
]);
|
|
84311
85010
|
INTERRUPT_TOOL_RETURN_MAX_CHARS = LIMITS.BASH_OUTPUT_CHARS;
|
|
85011
|
+
STREAMING_TOOL_OUTPUT_MAX_CHARS = LIMITS.BASH_OUTPUT_CHARS;
|
|
84312
85012
|
});
|
|
84313
85013
|
|
|
84314
85014
|
// src/websocket/listener/permissionMode.ts
|
|
@@ -85382,7 +86082,7 @@ __export(exports_diff, {
|
|
|
85382
86082
|
ADV_DIFF_IGNORE_WHITESPACE: () => ADV_DIFF_IGNORE_WHITESPACE,
|
|
85383
86083
|
ADV_DIFF_CONTEXT_LINES: () => ADV_DIFF_CONTEXT_LINES
|
|
85384
86084
|
});
|
|
85385
|
-
import { basename as
|
|
86085
|
+
import { basename as basename8 } from "node:path";
|
|
85386
86086
|
function readFileOrNull(p) {
|
|
85387
86087
|
try {
|
|
85388
86088
|
return __require("node:fs").readFileSync(p, "utf-8");
|
|
@@ -85406,7 +86106,7 @@ function applyAllOccurrences(content, oldStr, newStr) {
|
|
|
85406
86106
|
return { ok: true, out: content.split(oldStr).join(newStr) };
|
|
85407
86107
|
}
|
|
85408
86108
|
function computeAdvancedDiff(input, opts) {
|
|
85409
|
-
const fileName =
|
|
86109
|
+
const fileName = basename8(input.filePath || "");
|
|
85410
86110
|
const fileContent = opts?.oldStrOverride !== undefined ? opts.oldStrOverride : readFileOrNull(input.filePath);
|
|
85411
86111
|
if (fileContent === null && input.kind !== "write") {
|
|
85412
86112
|
return { mode: "fallback", reason: "File not readable" };
|
|
@@ -85472,7 +86172,7 @@ function computeAdvancedDiff(input, opts) {
|
|
|
85472
86172
|
return { mode: "advanced", fileName, oldStr, newStr, hunks };
|
|
85473
86173
|
}
|
|
85474
86174
|
function parsePatchToAdvancedDiff(patchLines, filePath) {
|
|
85475
|
-
const fileName =
|
|
86175
|
+
const fileName = basename8(filePath);
|
|
85476
86176
|
const hunks = [];
|
|
85477
86177
|
let currentHunk = null;
|
|
85478
86178
|
let oldLine = 1;
|
|
@@ -85753,8 +86453,8 @@ function isFormatterSegment(tokens) {
|
|
|
85753
86453
|
}
|
|
85754
86454
|
}
|
|
85755
86455
|
function isShellExecutor2(token) {
|
|
85756
|
-
const
|
|
85757
|
-
return ["bash", "sh", "zsh", "dash", "ksh"].includes(
|
|
86456
|
+
const basename9 = token.split("/").pop() ?? token;
|
|
86457
|
+
return ["bash", "sh", "zsh", "dash", "ksh"].includes(basename9.toLowerCase());
|
|
85758
86458
|
}
|
|
85759
86459
|
function normalizeRawCommand(command) {
|
|
85760
86460
|
if (Array.isArray(command)) {
|
|
@@ -86463,7 +87163,7 @@ var init_formatArgsDisplay = __esm(async () => {
|
|
|
86463
87163
|
});
|
|
86464
87164
|
|
|
86465
87165
|
// src/helpers/diffPreview.ts
|
|
86466
|
-
import path21, { basename as
|
|
87166
|
+
import path21, { basename as basename9 } from "node:path";
|
|
86467
87167
|
function parseHunkLinePrefix(raw) {
|
|
86468
87168
|
if (raw.length === 0) {
|
|
86469
87169
|
return { type: "context", content: "" };
|
|
@@ -86569,7 +87269,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86569
87269
|
filePath: resolvedFilePath,
|
|
86570
87270
|
content: toolArgs.content || ""
|
|
86571
87271
|
});
|
|
86572
|
-
previews.push(toDiffPreview(result,
|
|
87272
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86573
87273
|
}
|
|
86574
87274
|
} else if (isFileEditTool2(toolName)) {
|
|
86575
87275
|
const filePath = toolArgs.file_path;
|
|
@@ -86581,7 +87281,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86581
87281
|
filePath: resolvedFilePath,
|
|
86582
87282
|
edits: toolArgs.edits
|
|
86583
87283
|
});
|
|
86584
|
-
previews.push(toDiffPreview(result,
|
|
87284
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86585
87285
|
} else {
|
|
86586
87286
|
const result = computeAdvancedDiff2({
|
|
86587
87287
|
kind: "edit",
|
|
@@ -86590,7 +87290,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86590
87290
|
newString: toolArgs.new_string || "",
|
|
86591
87291
|
replaceAll: toolArgs.replace_all
|
|
86592
87292
|
});
|
|
86593
|
-
previews.push(toDiffPreview(result,
|
|
87293
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86594
87294
|
}
|
|
86595
87295
|
}
|
|
86596
87296
|
} else if (isPatchTool2(toolName) && toolArgs.input) {
|
|
@@ -86599,7 +87299,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86599
87299
|
if (op.kind === "add" || op.kind === "update") {
|
|
86600
87300
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
86601
87301
|
if (result) {
|
|
86602
|
-
previews.push(toDiffPreview(result,
|
|
87302
|
+
previews.push(toDiffPreview(result, basename9(op.path)));
|
|
86603
87303
|
}
|
|
86604
87304
|
}
|
|
86605
87305
|
}
|
|
@@ -86609,7 +87309,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86609
87309
|
if (op.kind === "add" || op.kind === "update") {
|
|
86610
87310
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
86611
87311
|
if (result) {
|
|
86612
|
-
previews.push(toDiffPreview(result,
|
|
87312
|
+
previews.push(toDiffPreview(result, basename9(op.path)));
|
|
86613
87313
|
}
|
|
86614
87314
|
}
|
|
86615
87315
|
}
|
|
@@ -87149,6 +87849,11 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
87149
87849
|
agentId: recovered.agentId,
|
|
87150
87850
|
conversationId: recovered.conversationId
|
|
87151
87851
|
});
|
|
87852
|
+
const emitToolExecutionOutput = createToolExecutionOutputEmitter(socket, runtime, {
|
|
87853
|
+
runId: runtime.activeRunId ?? undefined,
|
|
87854
|
+
agentId: recovered.agentId,
|
|
87855
|
+
conversationId: recovered.conversationId
|
|
87856
|
+
});
|
|
87152
87857
|
const recoveryAbortController = new AbortController;
|
|
87153
87858
|
runtime.activeAbortController = recoveryAbortController;
|
|
87154
87859
|
const preparedToolContext = await prepareToolExecutionContextForScope({
|
|
@@ -87163,6 +87868,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
87163
87868
|
try {
|
|
87164
87869
|
const approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
87165
87870
|
abortSignal: recoveryAbortController.signal,
|
|
87871
|
+
onStreamingOutput: emitToolExecutionOutput,
|
|
87166
87872
|
toolContextId: preparedToolContext.preparedToolContext.contextId,
|
|
87167
87873
|
workingDirectory,
|
|
87168
87874
|
parentScope: recovered.agentId && recovered.conversationId ? {
|
|
@@ -87433,9 +88139,15 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
87433
88139
|
agentId: runtime.agentId ?? undefined,
|
|
87434
88140
|
conversationId: recoveryConversationId
|
|
87435
88141
|
});
|
|
88142
|
+
const emitToolExecutionOutput = createToolExecutionOutputEmitter(socket, runtime, {
|
|
88143
|
+
runId: runtime.activeRunId ?? undefined,
|
|
88144
|
+
agentId: runtime.agentId ?? undefined,
|
|
88145
|
+
conversationId: recoveryConversationId
|
|
88146
|
+
});
|
|
87436
88147
|
try {
|
|
87437
88148
|
const approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
87438
88149
|
abortSignal,
|
|
88150
|
+
onStreamingOutput: emitToolExecutionOutput,
|
|
87439
88151
|
toolContextId: preparedToolContext.preparedToolContext.contextId,
|
|
87440
88152
|
workingDirectory: recoveryWorkingDirectory,
|
|
87441
88153
|
parentScope: runtime.agentId && runtime.conversationId ? {
|
|
@@ -88004,6 +88716,11 @@ async function handleApprovalStop(params) {
|
|
|
88004
88716
|
agentId,
|
|
88005
88717
|
conversationId
|
|
88006
88718
|
});
|
|
88719
|
+
const emitToolExecutionOutput = createToolExecutionOutputEmitter(socket, runtime, {
|
|
88720
|
+
runId: executionRunId,
|
|
88721
|
+
agentId,
|
|
88722
|
+
conversationId
|
|
88723
|
+
});
|
|
88007
88724
|
if (shouldInterrupt()) {
|
|
88008
88725
|
return interruptTermination();
|
|
88009
88726
|
}
|
|
@@ -88022,6 +88739,7 @@ async function handleApprovalStop(params) {
|
|
|
88022
88739
|
const executionResults = await executeApprovalBatch(decisions, undefined, {
|
|
88023
88740
|
toolContextId: turnToolContextId ?? undefined,
|
|
88024
88741
|
abortSignal: abortController.signal,
|
|
88742
|
+
onStreamingOutput: emitToolExecutionOutput,
|
|
88025
88743
|
workingDirectory: turnWorkingDirectory,
|
|
88026
88744
|
parentScope: agentId && conversationId ? { agentId, conversationId } : undefined,
|
|
88027
88745
|
onFileWrite
|
|
@@ -89703,6 +90421,65 @@ function mergeDequeuedBatchContent(items) {
|
|
|
89703
90421
|
normalizeUserContent: (content) => content
|
|
89704
90422
|
});
|
|
89705
90423
|
}
|
|
90424
|
+
function getChannelTurnSourceKey(source) {
|
|
90425
|
+
return [
|
|
90426
|
+
source.channel,
|
|
90427
|
+
source.accountId ?? "",
|
|
90428
|
+
source.chatId,
|
|
90429
|
+
source.messageId ?? "",
|
|
90430
|
+
source.threadId ?? "",
|
|
90431
|
+
source.agentId,
|
|
90432
|
+
source.conversationId
|
|
90433
|
+
].join(":");
|
|
90434
|
+
}
|
|
90435
|
+
function collectBatchChannelTurnSources(runtime, batch) {
|
|
90436
|
+
const seen = new Set;
|
|
90437
|
+
const sources = [];
|
|
90438
|
+
for (const item of batch.items) {
|
|
90439
|
+
const template = runtime.queuedMessagesByItemId.get(item.id);
|
|
90440
|
+
for (const source of template?.channelTurnSources ?? []) {
|
|
90441
|
+
const key = getChannelTurnSourceKey(source);
|
|
90442
|
+
if (seen.has(key)) {
|
|
90443
|
+
continue;
|
|
90444
|
+
}
|
|
90445
|
+
seen.add(key);
|
|
90446
|
+
sources.push(source);
|
|
90447
|
+
}
|
|
90448
|
+
}
|
|
90449
|
+
return sources.length > 0 ? sources : undefined;
|
|
90450
|
+
}
|
|
90451
|
+
async function dispatchChannelTurnLifecycleEvent(event) {
|
|
90452
|
+
if (event.sources.length === 0) {
|
|
90453
|
+
return;
|
|
90454
|
+
}
|
|
90455
|
+
const registry = getChannelRegistry();
|
|
90456
|
+
if (!registry) {
|
|
90457
|
+
return;
|
|
90458
|
+
}
|
|
90459
|
+
if (event.type === "processing") {
|
|
90460
|
+
await registry.dispatchTurnLifecycleEvent(event);
|
|
90461
|
+
return;
|
|
90462
|
+
}
|
|
90463
|
+
await registry.dispatchTurnLifecycleEvent({
|
|
90464
|
+
type: "finished",
|
|
90465
|
+
batchId: event.batchId,
|
|
90466
|
+
sources: event.sources,
|
|
90467
|
+
outcome: event.outcome,
|
|
90468
|
+
...event.error ? { error: event.error } : {}
|
|
90469
|
+
});
|
|
90470
|
+
}
|
|
90471
|
+
function mapTurnLifecycleOutcome(lastStopReason, didThrow) {
|
|
90472
|
+
if (didThrow) {
|
|
90473
|
+
return "error";
|
|
90474
|
+
}
|
|
90475
|
+
if (lastStopReason === "cancelled") {
|
|
90476
|
+
return "cancelled";
|
|
90477
|
+
}
|
|
90478
|
+
if (lastStopReason && lastStopReason !== "end_turn") {
|
|
90479
|
+
return "error";
|
|
90480
|
+
}
|
|
90481
|
+
return "completed";
|
|
90482
|
+
}
|
|
89706
90483
|
function isBase64ImageContentPart(part) {
|
|
89707
90484
|
if (!part || typeof part !== "object") {
|
|
89708
90485
|
return false;
|
|
@@ -89762,6 +90539,7 @@ function getPrimaryQueueMessageItem(items) {
|
|
|
89762
90539
|
return null;
|
|
89763
90540
|
}
|
|
89764
90541
|
function buildQueuedTurnMessage(runtime, batch) {
|
|
90542
|
+
const channelTurnSources = collectBatchChannelTurnSources(runtime, batch);
|
|
89765
90543
|
const primaryItem = getPrimaryQueueMessageItem(batch.items);
|
|
89766
90544
|
if (!primaryItem) {
|
|
89767
90545
|
for (const item of batch.items) {
|
|
@@ -89776,6 +90554,7 @@ function buildQueuedTurnMessage(runtime, batch) {
|
|
|
89776
90554
|
type: "message",
|
|
89777
90555
|
agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
|
|
89778
90556
|
conversationId: scopeItem?.conversationId ?? runtime.conversationId,
|
|
90557
|
+
...channelTurnSources ? { channelTurnSources } : {},
|
|
89779
90558
|
messages: [
|
|
89780
90559
|
{
|
|
89781
90560
|
role: "user",
|
|
@@ -89808,6 +90587,7 @@ function buildQueuedTurnMessage(runtime, batch) {
|
|
|
89808
90587
|
messages[firstMessageIndex] = mergedFirstMessage;
|
|
89809
90588
|
return {
|
|
89810
90589
|
...template,
|
|
90590
|
+
...channelTurnSources ? { channelTurnSources } : {},
|
|
89811
90591
|
messages
|
|
89812
90592
|
};
|
|
89813
90593
|
}
|
|
@@ -89888,13 +90668,39 @@ async function drainQueuedMessages(runtime, socket, opts, processQueuedTurn) {
|
|
|
89888
90668
|
return;
|
|
89889
90669
|
}
|
|
89890
90670
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
90671
|
+
const channelTurnSources = queuedTurn.channelTurnSources ?? [];
|
|
89891
90672
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
89892
90673
|
const preTurnStatus = getListenerStatus(runtime.listener) === "processing" ? "processing" : "receiving";
|
|
89893
90674
|
if (opts.connectionId && runtime.listener.lastEmittedStatus !== preTurnStatus) {
|
|
89894
90675
|
runtime.listener.lastEmittedStatus = preTurnStatus;
|
|
89895
90676
|
opts.onStatusChange?.(preTurnStatus, opts.connectionId);
|
|
89896
90677
|
}
|
|
89897
|
-
|
|
90678
|
+
if (channelTurnSources.length > 0) {
|
|
90679
|
+
await dispatchChannelTurnLifecycleEvent({
|
|
90680
|
+
type: "processing",
|
|
90681
|
+
batchId: dequeuedBatch.batchId,
|
|
90682
|
+
sources: channelTurnSources
|
|
90683
|
+
});
|
|
90684
|
+
}
|
|
90685
|
+
let turnError;
|
|
90686
|
+
let didThrow = false;
|
|
90687
|
+
try {
|
|
90688
|
+
await processQueuedTurn(queuedTurn, dequeuedBatch);
|
|
90689
|
+
} catch (error) {
|
|
90690
|
+
didThrow = true;
|
|
90691
|
+
turnError = error instanceof Error ? error.message : String(error);
|
|
90692
|
+
throw error;
|
|
90693
|
+
} finally {
|
|
90694
|
+
if (channelTurnSources.length > 0) {
|
|
90695
|
+
await dispatchChannelTurnLifecycleEvent({
|
|
90696
|
+
type: "finished",
|
|
90697
|
+
batchId: dequeuedBatch.batchId,
|
|
90698
|
+
sources: channelTurnSources,
|
|
90699
|
+
outcome: mapTurnLifecycleOutcome(runtime.lastStopReason, didThrow),
|
|
90700
|
+
...turnError ? { error: turnError } : {}
|
|
90701
|
+
});
|
|
90702
|
+
}
|
|
90703
|
+
}
|
|
89898
90704
|
emitListenerStatus(runtime.listener, opts.onStatusChange, opts.connectionId);
|
|
89899
90705
|
evictConversationRuntimeIfIdle(runtime);
|
|
89900
90706
|
}
|
|
@@ -89927,6 +90733,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
|
|
|
89927
90733
|
});
|
|
89928
90734
|
}
|
|
89929
90735
|
var init_queue = __esm(async () => {
|
|
90736
|
+
init_registry();
|
|
89930
90737
|
init_queueRuntime();
|
|
89931
90738
|
init_errorReporting();
|
|
89932
90739
|
init_runtime3();
|
|
@@ -89961,11 +90768,6 @@ function refreshTaskCache(state) {
|
|
|
89961
90768
|
}
|
|
89962
90769
|
}
|
|
89963
90770
|
function shouldFireTask(task2, now) {
|
|
89964
|
-
if (task2.recurring && task2.expires_at) {
|
|
89965
|
-
if (new Date(task2.expires_at).getTime() <= now.getTime()) {
|
|
89966
|
-
return false;
|
|
89967
|
-
}
|
|
89968
|
-
}
|
|
89969
90771
|
if (!task2.recurring && task2.scheduled_for) {
|
|
89970
90772
|
const scheduledMs = new Date(task2.scheduled_for).getTime() + task2.jitter_offset_ms;
|
|
89971
90773
|
return scheduledMs <= now.getTime();
|
|
@@ -90005,16 +90807,6 @@ function fireCronTask(task2, now, socket, opts, processQueuedTurn) {
|
|
|
90005
90807
|
});
|
|
90006
90808
|
}
|
|
90007
90809
|
}
|
|
90008
|
-
function handleExpiredRecurring(task2, now) {
|
|
90009
|
-
if (!task2.recurring || !task2.expires_at)
|
|
90010
|
-
return;
|
|
90011
|
-
if (new Date(task2.expires_at).getTime() <= now.getTime()) {
|
|
90012
|
-
updateTask(task2.id, (t) => {
|
|
90013
|
-
t.status = "cancelled";
|
|
90014
|
-
t.cancel_reason = "expired";
|
|
90015
|
-
});
|
|
90016
|
-
}
|
|
90017
|
-
}
|
|
90018
90810
|
function handleMissedOneShot(task2, now) {
|
|
90019
90811
|
if (task2.recurring || !task2.scheduled_for)
|
|
90020
90812
|
return false;
|
|
@@ -90043,9 +90835,6 @@ function tick2(state, socket, opts, processQueuedTurn) {
|
|
|
90043
90835
|
}
|
|
90044
90836
|
refreshTaskCache(state);
|
|
90045
90837
|
for (const task2 of state.cachedTasks) {
|
|
90046
|
-
if (task2.status !== "active")
|
|
90047
|
-
continue;
|
|
90048
|
-
handleExpiredRecurring(task2, now);
|
|
90049
90838
|
if (task2.status !== "active")
|
|
90050
90839
|
continue;
|
|
90051
90840
|
if (handleMissedOneShot(task2, now))
|
|
@@ -90509,6 +91298,12 @@ function isListInDirectoryCommand(value) {
|
|
|
90509
91298
|
const c = value;
|
|
90510
91299
|
return c.type === "list_in_directory" && typeof c.path === "string";
|
|
90511
91300
|
}
|
|
91301
|
+
function isGetTreeCommand(value) {
|
|
91302
|
+
if (!value || typeof value !== "object")
|
|
91303
|
+
return false;
|
|
91304
|
+
const c = value;
|
|
91305
|
+
return c.type === "get_tree" && typeof c.path === "string" && typeof c.depth === "number" && typeof c.request_id === "string";
|
|
91306
|
+
}
|
|
90512
91307
|
function isReadFileCommand(value) {
|
|
90513
91308
|
if (!value || typeof value !== "object")
|
|
90514
91309
|
return false;
|
|
@@ -90835,7 +91630,7 @@ function parseServerMessage(data) {
|
|
|
90835
91630
|
try {
|
|
90836
91631
|
const raw = typeof data === "string" ? data : data.toString();
|
|
90837
91632
|
const parsed = JSON.parse(raw);
|
|
90838
|
-
if (isInputCommand(parsed) || isChangeDeviceStateCommand(parsed) || isAbortMessageCommand(parsed) || isSyncCommand(parsed) || isTerminalSpawnCommand(parsed) || isTerminalInputCommand(parsed) || isTerminalResizeCommand(parsed) || isTerminalKillCommand(parsed) || isSearchFilesCommand(parsed) || isListInDirectoryCommand(parsed) || isReadFileCommand(parsed) || isWriteFileCommand(parsed) || isWatchFileCommand(parsed) || isUnwatchFileCommand(parsed) || isEditFileCommand(parsed) || isFileOpsCommand(parsed) || isListMemoryCommand(parsed) || isMemoryHistoryCommand(parsed) || isMemoryFileAtRefCommand(parsed) || isEnableMemfsCommand(parsed) || isListModelsCommand(parsed) || isUpdateModelCommand(parsed) || isCronListCommand(parsed) || isCronAddCommand(parsed) || isCronGetCommand(parsed) || isCronDeleteCommand(parsed) || isCronDeleteAllCommand(parsed) || isSkillEnableCommand(parsed) || isSkillDisableCommand(parsed) || isCreateAgentCommand(parsed) || isGetReflectionSettingsCommand(parsed) || isSetReflectionSettingsCommand(parsed) || isChannelsListCommand(parsed) || isChannelAccountsListCommand(parsed) || isChannelAccountCreateCommand(parsed) || isChannelAccountUpdateCommand(parsed) || isChannelAccountBindCommand(parsed) || isChannelAccountUnbindCommand(parsed) || isChannelAccountDeleteCommand(parsed) || isChannelAccountStartCommand(parsed) || isChannelAccountStopCommand(parsed) || isChannelGetConfigCommand(parsed) || isChannelSetConfigCommand(parsed) || isChannelStartCommand(parsed) || isChannelStopCommand(parsed) || isChannelPairingsListCommand(parsed) || isChannelPairingBindCommand(parsed) || isChannelRoutesListCommand(parsed) || isChannelTargetsListCommand(parsed) || isChannelTargetBindCommand(parsed) || isChannelRouteUpdateCommand(parsed) || isChannelRouteRemoveCommand(parsed) || isExecuteCommandCommand(parsed) || isSearchBranchesCommand(parsed) || isCheckoutBranchCommand(parsed)) {
|
|
91633
|
+
if (isInputCommand(parsed) || isChangeDeviceStateCommand(parsed) || isAbortMessageCommand(parsed) || isSyncCommand(parsed) || isTerminalSpawnCommand(parsed) || isTerminalInputCommand(parsed) || isTerminalResizeCommand(parsed) || isTerminalKillCommand(parsed) || isSearchFilesCommand(parsed) || isListInDirectoryCommand(parsed) || isGetTreeCommand(parsed) || isReadFileCommand(parsed) || isWriteFileCommand(parsed) || isWatchFileCommand(parsed) || isUnwatchFileCommand(parsed) || isEditFileCommand(parsed) || isFileOpsCommand(parsed) || isListMemoryCommand(parsed) || isMemoryHistoryCommand(parsed) || isMemoryFileAtRefCommand(parsed) || isEnableMemfsCommand(parsed) || isListModelsCommand(parsed) || isUpdateModelCommand(parsed) || isCronListCommand(parsed) || isCronAddCommand(parsed) || isCronGetCommand(parsed) || isCronDeleteCommand(parsed) || isCronDeleteAllCommand(parsed) || isSkillEnableCommand(parsed) || isSkillDisableCommand(parsed) || isCreateAgentCommand(parsed) || isGetReflectionSettingsCommand(parsed) || isSetReflectionSettingsCommand(parsed) || isChannelsListCommand(parsed) || isChannelAccountsListCommand(parsed) || isChannelAccountCreateCommand(parsed) || isChannelAccountUpdateCommand(parsed) || isChannelAccountBindCommand(parsed) || isChannelAccountUnbindCommand(parsed) || isChannelAccountDeleteCommand(parsed) || isChannelAccountStartCommand(parsed) || isChannelAccountStopCommand(parsed) || isChannelGetConfigCommand(parsed) || isChannelSetConfigCommand(parsed) || isChannelStartCommand(parsed) || isChannelStopCommand(parsed) || isChannelPairingsListCommand(parsed) || isChannelPairingBindCommand(parsed) || isChannelRoutesListCommand(parsed) || isChannelTargetsListCommand(parsed) || isChannelTargetBindCommand(parsed) || isChannelRouteUpdateCommand(parsed) || isChannelRouteRemoveCommand(parsed) || isExecuteCommandCommand(parsed) || isSearchBranchesCommand(parsed) || isCheckoutBranchCommand(parsed)) {
|
|
90839
91634
|
return parsed;
|
|
90840
91635
|
}
|
|
90841
91636
|
const invalidInput = getInvalidInputReason(parsed);
|
|
@@ -91033,7 +91828,7 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
91033
91828
|
} catch {
|
|
91034
91829
|
return;
|
|
91035
91830
|
}
|
|
91036
|
-
const relativePath = relative12(memoryRoot, fullPath);
|
|
91831
|
+
const relativePath = relative12(memoryRoot, fullPath).replace(/\\/g, "/");
|
|
91037
91832
|
const isLast = index === sorted.length - 1;
|
|
91038
91833
|
nodes.push({
|
|
91039
91834
|
name: isDir ? `${name}/` : name,
|
|
@@ -91208,18 +92003,20 @@ function formatToolsetStatusMessageForModelUpdate(params) {
|
|
|
91208
92003
|
}
|
|
91209
92004
|
return "Manual toolset override remains active: " + formatToolsetName(toolsetPreference) + ".";
|
|
91210
92005
|
}
|
|
91211
|
-
function formatEffortSuffix(updateArgs) {
|
|
92006
|
+
function formatEffortSuffix(modelLabel, updateArgs) {
|
|
91212
92007
|
if (!updateArgs)
|
|
91213
92008
|
return "";
|
|
91214
92009
|
const effort = updateArgs.reasoning_effort;
|
|
91215
92010
|
if (typeof effort !== "string" || effort.length === 0)
|
|
91216
92011
|
return "";
|
|
92012
|
+
const xhighLabel = modelLabel.includes("Opus 4.7") ? "Extra-High" : "Max";
|
|
91217
92013
|
const labels = {
|
|
91218
92014
|
none: "No Reasoning",
|
|
91219
92015
|
low: "Low",
|
|
91220
92016
|
medium: "Medium",
|
|
91221
92017
|
high: "High",
|
|
91222
|
-
xhigh:
|
|
92018
|
+
xhigh: xhighLabel,
|
|
92019
|
+
max: "Max"
|
|
91223
92020
|
};
|
|
91224
92021
|
return ` (${labels[effort] ?? effort})`;
|
|
91225
92022
|
}
|
|
@@ -91232,7 +92029,7 @@ function buildModelUpdateStatusMessage(params) {
|
|
|
91232
92029
|
toolsetPreference,
|
|
91233
92030
|
updateArgs
|
|
91234
92031
|
} = params;
|
|
91235
|
-
let message = `Model updated to ${modelLabel}${formatEffortSuffix(updateArgs)}.`;
|
|
92032
|
+
let message = `Model updated to ${modelLabel}${formatEffortSuffix(modelLabel, updateArgs)}.`;
|
|
91236
92033
|
if (toolsetError) {
|
|
91237
92034
|
message += ` Warning: toolset switch failed (${toolsetError}).`;
|
|
91238
92035
|
return { message, level: "warning" };
|
|
@@ -91406,6 +92203,165 @@ function emitChannelTargetsUpdated(socket, channelId) {
|
|
|
91406
92203
|
channel_id: channelId
|
|
91407
92204
|
}, "listener_channels_send_failed", "listener_channels_command");
|
|
91408
92205
|
}
|
|
92206
|
+
async function handleListMemoryCommand(parsed, socket, overrides = {}) {
|
|
92207
|
+
try {
|
|
92208
|
+
const {
|
|
92209
|
+
ensureLocalMemfsCheckout: actualEnsureLocalMemfsCheckout,
|
|
92210
|
+
getMemoryFilesystemRoot: actualGetMemoryFilesystemRoot,
|
|
92211
|
+
isMemfsEnabledOnServer: actualIsMemfsEnabledOnServer
|
|
92212
|
+
} = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
92213
|
+
const ensureLocalMemfsCheckout2 = overrides.ensureLocalMemfsCheckout ?? actualEnsureLocalMemfsCheckout;
|
|
92214
|
+
const getMemoryFilesystemRoot2 = overrides.getMemoryFilesystemRoot ?? actualGetMemoryFilesystemRoot;
|
|
92215
|
+
const isMemfsEnabledOnServer2 = overrides.isMemfsEnabledOnServer ?? actualIsMemfsEnabledOnServer;
|
|
92216
|
+
const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memoryScanner(), exports_memoryScanner));
|
|
92217
|
+
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
|
|
92218
|
+
const { existsSync: existsSync26 } = await import("node:fs");
|
|
92219
|
+
const { join: join31, posix: posix2 } = await import("node:path");
|
|
92220
|
+
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
92221
|
+
let memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
|
|
92222
|
+
const memfsEnabled = memfsInitialized ? true : await isMemfsEnabledOnServer2(parsed.agent_id);
|
|
92223
|
+
if (!memfsEnabled) {
|
|
92224
|
+
safeSocketSend(socket, {
|
|
92225
|
+
type: "list_memory_response",
|
|
92226
|
+
request_id: parsed.request_id,
|
|
92227
|
+
entries: [],
|
|
92228
|
+
done: true,
|
|
92229
|
+
total: 0,
|
|
92230
|
+
success: true,
|
|
92231
|
+
memfs_enabled: false,
|
|
92232
|
+
memfs_initialized: false
|
|
92233
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92234
|
+
return true;
|
|
92235
|
+
}
|
|
92236
|
+
if (!memfsInitialized) {
|
|
92237
|
+
await ensureLocalMemfsCheckout2(parsed.agent_id);
|
|
92238
|
+
memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
|
|
92239
|
+
}
|
|
92240
|
+
if (!memfsInitialized) {
|
|
92241
|
+
throw new Error("MemFS is enabled, but the local memory checkout could not be initialized.");
|
|
92242
|
+
}
|
|
92243
|
+
const treeNodes = scanMemoryFilesystem2(memoryRoot);
|
|
92244
|
+
const fileNodes = getFileNodes2(treeNodes).filter((n) => n.name.endsWith(".md"));
|
|
92245
|
+
const includeReferences = parsed.include_references === true;
|
|
92246
|
+
const allPaths = new Set(fileNodes.map((node) => node.relativePath));
|
|
92247
|
+
const normalizeMemoryReference = (rawReference, sourcePath) => {
|
|
92248
|
+
let target = rawReference.trim();
|
|
92249
|
+
if (!target) {
|
|
92250
|
+
return null;
|
|
92251
|
+
}
|
|
92252
|
+
if (target.startsWith("http://") || target.startsWith("https://") || target.startsWith("mailto:")) {
|
|
92253
|
+
return null;
|
|
92254
|
+
}
|
|
92255
|
+
target = target.replace(/^<|>$/g, "");
|
|
92256
|
+
target = target.split("#")[0] ?? "";
|
|
92257
|
+
target = target.split("?")[0] ?? "";
|
|
92258
|
+
target = target.trim().replace(/\\/g, "/");
|
|
92259
|
+
if (!target || target.startsWith("#")) {
|
|
92260
|
+
return null;
|
|
92261
|
+
}
|
|
92262
|
+
if (target.includes("|")) {
|
|
92263
|
+
target = target.split("|")[0] ?? "";
|
|
92264
|
+
}
|
|
92265
|
+
if (!target) {
|
|
92266
|
+
return null;
|
|
92267
|
+
}
|
|
92268
|
+
const sourceDir = posix2.dirname(sourcePath.replace(/\\/g, "/"));
|
|
92269
|
+
const candidate = target.startsWith("./") || target.startsWith("../") ? posix2.normalize(posix2.join(sourceDir, target)) : posix2.normalize(target.startsWith("/") ? target.slice(1) : target);
|
|
92270
|
+
if (!candidate || candidate.startsWith("../") || candidate === "." || candidate === "..") {
|
|
92271
|
+
return null;
|
|
92272
|
+
}
|
|
92273
|
+
const withExtension = candidate.endsWith(".md") ? candidate : `${candidate}.md`;
|
|
92274
|
+
const candidates = new Set([withExtension]);
|
|
92275
|
+
const isExplicitRelative = target.startsWith("./") || target.startsWith("../");
|
|
92276
|
+
if (!isExplicitRelative && !target.startsWith("/") && sourceDir && sourceDir !== ".") {
|
|
92277
|
+
candidates.add(posix2.normalize(posix2.join(sourceDir, withExtension)));
|
|
92278
|
+
}
|
|
92279
|
+
if (!withExtension.startsWith("system/")) {
|
|
92280
|
+
candidates.add(posix2.normalize(`system/${withExtension}`));
|
|
92281
|
+
}
|
|
92282
|
+
for (const resolved of candidates) {
|
|
92283
|
+
if (allPaths.has(resolved)) {
|
|
92284
|
+
return resolved;
|
|
92285
|
+
}
|
|
92286
|
+
}
|
|
92287
|
+
return null;
|
|
92288
|
+
};
|
|
92289
|
+
const extractMemoryReferences = (body, sourcePath) => {
|
|
92290
|
+
if (!body.includes("[[")) {
|
|
92291
|
+
return [];
|
|
92292
|
+
}
|
|
92293
|
+
const refs = new Set;
|
|
92294
|
+
for (const wikiMatch of body.matchAll(WIKI_LINK_REGEX)) {
|
|
92295
|
+
const rawTarget = wikiMatch[1];
|
|
92296
|
+
if (!rawTarget)
|
|
92297
|
+
continue;
|
|
92298
|
+
const normalized = normalizeMemoryReference(rawTarget, sourcePath);
|
|
92299
|
+
if (normalized && normalized !== sourcePath) {
|
|
92300
|
+
refs.add(normalized);
|
|
92301
|
+
}
|
|
92302
|
+
}
|
|
92303
|
+
return [...refs];
|
|
92304
|
+
};
|
|
92305
|
+
const CHUNK_SIZE = 5;
|
|
92306
|
+
const total = fileNodes.length;
|
|
92307
|
+
for (let i = 0;i < total; i += CHUNK_SIZE) {
|
|
92308
|
+
const chunk = fileNodes.slice(i, i + CHUNK_SIZE);
|
|
92309
|
+
const entries = chunk.map((node) => {
|
|
92310
|
+
const raw = readFileContent2(node.fullPath);
|
|
92311
|
+
const { frontmatter, body } = parseFrontmatter2(raw);
|
|
92312
|
+
const desc = frontmatter.description;
|
|
92313
|
+
return {
|
|
92314
|
+
relative_path: node.relativePath,
|
|
92315
|
+
is_system: node.relativePath.startsWith("system/") || node.relativePath.startsWith("system\\"),
|
|
92316
|
+
description: typeof desc === "string" ? desc : null,
|
|
92317
|
+
content: body,
|
|
92318
|
+
size: body.length,
|
|
92319
|
+
...includeReferences ? {
|
|
92320
|
+
references: extractMemoryReferences(body, node.relativePath)
|
|
92321
|
+
} : {}
|
|
92322
|
+
};
|
|
92323
|
+
});
|
|
92324
|
+
const done = i + CHUNK_SIZE >= total;
|
|
92325
|
+
const sent = safeSocketSend(socket, {
|
|
92326
|
+
type: "list_memory_response",
|
|
92327
|
+
request_id: parsed.request_id,
|
|
92328
|
+
entries,
|
|
92329
|
+
done,
|
|
92330
|
+
total,
|
|
92331
|
+
success: true,
|
|
92332
|
+
memfs_enabled: true,
|
|
92333
|
+
memfs_initialized: true
|
|
92334
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92335
|
+
if (!sent) {
|
|
92336
|
+
return true;
|
|
92337
|
+
}
|
|
92338
|
+
}
|
|
92339
|
+
if (total === 0) {
|
|
92340
|
+
safeSocketSend(socket, {
|
|
92341
|
+
type: "list_memory_response",
|
|
92342
|
+
request_id: parsed.request_id,
|
|
92343
|
+
entries: [],
|
|
92344
|
+
done: true,
|
|
92345
|
+
total: 0,
|
|
92346
|
+
success: true,
|
|
92347
|
+
memfs_enabled: true,
|
|
92348
|
+
memfs_initialized: true
|
|
92349
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92350
|
+
}
|
|
92351
|
+
} catch (err) {
|
|
92352
|
+
trackListenerError("listener_list_memory_failed", err, "listener_memory_browser");
|
|
92353
|
+
safeSocketSend(socket, {
|
|
92354
|
+
type: "list_memory_response",
|
|
92355
|
+
request_id: parsed.request_id,
|
|
92356
|
+
entries: [],
|
|
92357
|
+
done: true,
|
|
92358
|
+
total: 0,
|
|
92359
|
+
success: false,
|
|
92360
|
+
error: err instanceof Error ? err.message : "Failed to list memory"
|
|
92361
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92362
|
+
}
|
|
92363
|
+
return true;
|
|
92364
|
+
}
|
|
91409
92365
|
async function handleCronCommand(parsed, socket) {
|
|
91410
92366
|
if (parsed.type === "cron_list") {
|
|
91411
92367
|
try {
|
|
@@ -91638,6 +92594,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
|
|
|
91638
92594
|
has_bot_token: snapshot.hasBotToken,
|
|
91639
92595
|
has_app_token: snapshot.hasAppToken,
|
|
91640
92596
|
agent_id: snapshot.agentId,
|
|
92597
|
+
default_permission_mode: snapshot.defaultPermissionMode,
|
|
91641
92598
|
created_at: snapshot.createdAt,
|
|
91642
92599
|
updated_at: snapshot.updatedAt
|
|
91643
92600
|
};
|
|
@@ -91731,6 +92688,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
|
|
|
91731
92688
|
appToken: "app_token" in parsed.account ? parsed.account.app_token : undefined,
|
|
91732
92689
|
mode: "mode" in parsed.account ? parsed.account.mode : undefined,
|
|
91733
92690
|
agentId: "agent_id" in parsed.account ? parsed.account.agent_id : undefined,
|
|
92691
|
+
defaultPermissionMode: "default_permission_mode" in parsed.account ? parsed.account.default_permission_mode : undefined,
|
|
91734
92692
|
dmPolicy: parsed.account.dm_policy,
|
|
91735
92693
|
allowedUsers: parsed.account.allowed_users
|
|
91736
92694
|
}, {
|
|
@@ -91771,6 +92729,7 @@ async function handleChannelsProtocolCommand(parsed, socket, runtime, opts, proc
|
|
|
91771
92729
|
appToken: "app_token" in parsed.patch ? parsed.patch.app_token : undefined,
|
|
91772
92730
|
mode: "mode" in parsed.patch ? parsed.patch.mode : undefined,
|
|
91773
92731
|
agentId: "agent_id" in parsed.patch ? parsed.patch.agent_id : undefined,
|
|
92732
|
+
defaultPermissionMode: "default_permission_mode" in parsed.patch ? parsed.patch.default_permission_mode : undefined,
|
|
91774
92733
|
dmPolicy: parsed.patch.dm_policy,
|
|
91775
92734
|
allowedUsers: parsed.patch.allowed_users
|
|
91776
92735
|
});
|
|
@@ -92259,7 +93218,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
92259
93218
|
symlinkSync,
|
|
92260
93219
|
unlinkSync: unlinkSync8
|
|
92261
93220
|
} = await import("node:fs");
|
|
92262
|
-
const { basename:
|
|
93221
|
+
const { basename: basename10, join: join31 } = await import("node:path");
|
|
92263
93222
|
const lettaHome = process.env.LETTA_HOME || join31(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
|
|
92264
93223
|
const globalSkillsDir = join31(lettaHome, "skills");
|
|
92265
93224
|
if (parsed.type === "skill_enable") {
|
|
@@ -92283,7 +93242,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
92283
93242
|
}, "listener_skill_send_failed", "listener_skill_command");
|
|
92284
93243
|
return true;
|
|
92285
93244
|
}
|
|
92286
|
-
const linkName =
|
|
93245
|
+
const linkName = basename10(parsed.skill_path);
|
|
92287
93246
|
const linkPath = join31(globalSkillsDir, linkName);
|
|
92288
93247
|
mkdirSync19(globalSkillsDir, { recursive: true });
|
|
92289
93248
|
if (existsSync26(linkPath)) {
|
|
@@ -92495,25 +93454,45 @@ function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
|
|
|
92495
93454
|
const registry = getChannelRegistry();
|
|
92496
93455
|
if (!registry)
|
|
92497
93456
|
return;
|
|
92498
|
-
registry.setMessageHandler((
|
|
92499
|
-
const rawRuntime = getOrCreateConversationRuntime(listener, route.agentId, route.conversationId);
|
|
93457
|
+
registry.setMessageHandler((delivery) => {
|
|
93458
|
+
const rawRuntime = getOrCreateConversationRuntime(listener, delivery.route.agentId, delivery.route.conversationId);
|
|
92500
93459
|
if (!rawRuntime)
|
|
92501
93460
|
return;
|
|
92502
93461
|
const conversationRuntime = ensureConversationQueueRuntime(listener, rawRuntime);
|
|
92503
|
-
enqueueChannelTurn(conversationRuntime, route,
|
|
93462
|
+
const enqueuedItem = enqueueChannelTurn(conversationRuntime, delivery.route, delivery.content, delivery.turnSources);
|
|
93463
|
+
if (!enqueuedItem) {
|
|
93464
|
+
return;
|
|
93465
|
+
}
|
|
93466
|
+
for (const turnSource of delivery.turnSources ?? []) {
|
|
93467
|
+
registry.dispatchTurnLifecycleEvent({
|
|
93468
|
+
type: "queued",
|
|
93469
|
+
source: turnSource
|
|
93470
|
+
});
|
|
93471
|
+
}
|
|
92504
93472
|
scheduleQueuePump(conversationRuntime, socket, opts, processQueuedTurn);
|
|
92505
93473
|
});
|
|
92506
93474
|
registry.setEventHandler((event) => {
|
|
92507
|
-
|
|
92508
|
-
emitChannelPairingsUpdated(socket, event.channelId);
|
|
92509
|
-
emitChannelsUpdated(socket, event.channelId);
|
|
92510
|
-
return;
|
|
92511
|
-
}
|
|
92512
|
-
emitChannelTargetsUpdated(socket, event.channelId);
|
|
92513
|
-
emitChannelsUpdated(socket, event.channelId);
|
|
93475
|
+
handleChannelRegistryEvent(event, socket, listener);
|
|
92514
93476
|
});
|
|
92515
93477
|
registry.setReady();
|
|
92516
93478
|
}
|
|
93479
|
+
function handleChannelRegistryEvent(event, socket, runtime) {
|
|
93480
|
+
if (event.type === "pairings_updated") {
|
|
93481
|
+
emitChannelPairingsUpdated(socket, event.channelId);
|
|
93482
|
+
emitChannelsUpdated(socket, event.channelId);
|
|
93483
|
+
return;
|
|
93484
|
+
}
|
|
93485
|
+
if (event.type === "targets_updated") {
|
|
93486
|
+
emitChannelTargetsUpdated(socket, event.channelId);
|
|
93487
|
+
emitChannelsUpdated(socket, event.channelId);
|
|
93488
|
+
return;
|
|
93489
|
+
}
|
|
93490
|
+
const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime, event.agentId, event.conversationId);
|
|
93491
|
+
permissionModeState.mode = event.defaultPermissionMode;
|
|
93492
|
+
permissionModeState.planFilePath = null;
|
|
93493
|
+
permissionModeState.modeBeforePlan = null;
|
|
93494
|
+
persistPermissionModeMapForRuntime(runtime);
|
|
93495
|
+
}
|
|
92517
93496
|
function stampInboundUserMessageOtids(incoming) {
|
|
92518
93497
|
let didChange = false;
|
|
92519
93498
|
const messages = incoming.messages.map((payload) => {
|
|
@@ -92534,7 +93513,7 @@ function stampInboundUserMessageOtids(incoming) {
|
|
|
92534
93513
|
messages
|
|
92535
93514
|
};
|
|
92536
93515
|
}
|
|
92537
|
-
function enqueueChannelTurn(runtime, route, messageContent) {
|
|
93516
|
+
function enqueueChannelTurn(runtime, route, messageContent, turnSources) {
|
|
92538
93517
|
const clientMessageId = `cm-channel-${crypto.randomUUID()}`;
|
|
92539
93518
|
const enqueuedItem = runtime.queueRuntime.enqueue({
|
|
92540
93519
|
kind: "message",
|
|
@@ -92551,6 +93530,7 @@ function enqueueChannelTurn(runtime, route, messageContent) {
|
|
|
92551
93530
|
type: "message",
|
|
92552
93531
|
agentId: route.agentId,
|
|
92553
93532
|
conversationId: route.conversationId,
|
|
93533
|
+
...turnSources?.length ? { channelTurnSources: turnSources } : {},
|
|
92554
93534
|
messages: [
|
|
92555
93535
|
{
|
|
92556
93536
|
role: "user",
|
|
@@ -92921,6 +93901,51 @@ async function startListenerClient(opts) {
|
|
|
92921
93901
|
telemetry.init();
|
|
92922
93902
|
await connectWithRetry(runtime, opts);
|
|
92923
93903
|
}
|
|
93904
|
+
async function listDirectoryHybrid(absDir, indexRoot3, includeFiles) {
|
|
93905
|
+
let indexedNames;
|
|
93906
|
+
const indexedFolders = [];
|
|
93907
|
+
const indexedFiles = [];
|
|
93908
|
+
if (indexRoot3 !== undefined) {
|
|
93909
|
+
const relPath = path23.relative(indexRoot3, absDir);
|
|
93910
|
+
if (!relPath.startsWith("..")) {
|
|
93911
|
+
const indexed = searchFileIndex({
|
|
93912
|
+
searchDir: relPath || ".",
|
|
93913
|
+
pattern: "",
|
|
93914
|
+
deep: false,
|
|
93915
|
+
maxResults: 1e4
|
|
93916
|
+
});
|
|
93917
|
+
indexedNames = new Set;
|
|
93918
|
+
for (const entry of indexed) {
|
|
93919
|
+
const name = entry.path.split(path23.sep).pop() ?? entry.path;
|
|
93920
|
+
indexedNames.add(name);
|
|
93921
|
+
if (entry.type === "dir") {
|
|
93922
|
+
indexedFolders.push(name);
|
|
93923
|
+
} else {
|
|
93924
|
+
indexedFiles.push(name);
|
|
93925
|
+
}
|
|
93926
|
+
}
|
|
93927
|
+
}
|
|
93928
|
+
}
|
|
93929
|
+
const { readdir: readdir7 } = await import("node:fs/promises");
|
|
93930
|
+
const entries = await readdir7(absDir, { withFileTypes: true });
|
|
93931
|
+
const extraFolders = [];
|
|
93932
|
+
const extraFiles = [];
|
|
93933
|
+
for (const e of entries) {
|
|
93934
|
+
if (DIR_LISTING_IGNORED_NAMES.has(e.name))
|
|
93935
|
+
continue;
|
|
93936
|
+
if (indexedNames?.has(e.name))
|
|
93937
|
+
continue;
|
|
93938
|
+
if (e.isDirectory()) {
|
|
93939
|
+
extraFolders.push(e.name);
|
|
93940
|
+
} else if (includeFiles) {
|
|
93941
|
+
extraFiles.push(e.name);
|
|
93942
|
+
}
|
|
93943
|
+
}
|
|
93944
|
+
return {
|
|
93945
|
+
folders: [...indexedFolders, ...extraFolders].sort((a, b) => a.localeCompare(b)),
|
|
93946
|
+
files: includeFiles ? [...indexedFiles, ...extraFiles].sort((a, b) => a.localeCompare(b)) : []
|
|
93947
|
+
};
|
|
93948
|
+
}
|
|
92924
93949
|
async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now()) {
|
|
92925
93950
|
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
92926
93951
|
return;
|
|
@@ -93241,33 +94266,21 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93241
94266
|
console.log(`[Listen] Received list_in_directory command: path=${parsed.path}`);
|
|
93242
94267
|
runDetachedListenerTask("list_in_directory", async () => {
|
|
93243
94268
|
try {
|
|
93244
|
-
|
|
94269
|
+
let indexRoot3;
|
|
94270
|
+
try {
|
|
94271
|
+
await ensureFileIndex2();
|
|
94272
|
+
indexRoot3 = getIndexRoot();
|
|
94273
|
+
} catch {}
|
|
93245
94274
|
console.log(`[Listen] Reading directory: ${parsed.path}`);
|
|
93246
|
-
const
|
|
93247
|
-
console.log(`[Listen] Directory read success, ${entries.length} entries`);
|
|
93248
|
-
const IGNORED_NAMES = new Set([
|
|
93249
|
-
".DS_Store",
|
|
93250
|
-
".git",
|
|
93251
|
-
".gitignore",
|
|
93252
|
-
"Thumbs.db"
|
|
93253
|
-
]);
|
|
93254
|
-
const sortedEntries = entries.filter((e) => !IGNORED_NAMES.has(e.name)).sort((a, b) => a.name.localeCompare(b.name));
|
|
93255
|
-
const allFolders = [];
|
|
93256
|
-
const allFiles = [];
|
|
93257
|
-
for (const e of sortedEntries) {
|
|
93258
|
-
if (e.isDirectory()) {
|
|
93259
|
-
allFolders.push(e.name);
|
|
93260
|
-
} else if (parsed.include_files) {
|
|
93261
|
-
allFiles.push(e.name);
|
|
93262
|
-
}
|
|
93263
|
-
}
|
|
94275
|
+
const { folders: allFolders, files: allFiles } = await listDirectoryHybrid(parsed.path, indexRoot3, !!parsed.include_files);
|
|
93264
94276
|
const total = allFolders.length + allFiles.length;
|
|
93265
94277
|
const offset = parsed.offset ?? 0;
|
|
93266
94278
|
const limit2 = parsed.limit ?? total;
|
|
93267
94279
|
const combined = [...allFolders, ...allFiles];
|
|
93268
94280
|
const page = combined.slice(offset, offset + limit2);
|
|
93269
|
-
const
|
|
93270
|
-
const
|
|
94281
|
+
const folderSet = new Set(allFolders);
|
|
94282
|
+
const folders = page.filter((name) => folderSet.has(name));
|
|
94283
|
+
const files = page.filter((name) => !folderSet.has(name));
|
|
93271
94284
|
const response = {
|
|
93272
94285
|
type: "list_in_directory_response",
|
|
93273
94286
|
path: parsed.path,
|
|
@@ -93298,6 +94311,71 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93298
94311
|
});
|
|
93299
94312
|
return;
|
|
93300
94313
|
}
|
|
94314
|
+
if (isGetTreeCommand(parsed)) {
|
|
94315
|
+
console.log(`[Listen] Received get_tree command: path=${parsed.path}, depth=${parsed.depth}`);
|
|
94316
|
+
runDetachedListenerTask("get_tree", async () => {
|
|
94317
|
+
try {
|
|
94318
|
+
const results = [];
|
|
94319
|
+
let hasMoreDepth = false;
|
|
94320
|
+
let indexRoot3;
|
|
94321
|
+
try {
|
|
94322
|
+
await ensureFileIndex2();
|
|
94323
|
+
indexRoot3 = getIndexRoot();
|
|
94324
|
+
} catch {}
|
|
94325
|
+
const queue = [[parsed.path, "", 0]];
|
|
94326
|
+
let qi = 0;
|
|
94327
|
+
while (qi < queue.length) {
|
|
94328
|
+
const item = queue[qi++];
|
|
94329
|
+
if (!item)
|
|
94330
|
+
break;
|
|
94331
|
+
const [absDir, relDir, depth] = item;
|
|
94332
|
+
if (depth >= parsed.depth) {
|
|
94333
|
+
if (depth === parsed.depth && relDir !== "") {
|
|
94334
|
+
hasMoreDepth = true;
|
|
94335
|
+
}
|
|
94336
|
+
continue;
|
|
94337
|
+
}
|
|
94338
|
+
let listing;
|
|
94339
|
+
try {
|
|
94340
|
+
listing = await listDirectoryHybrid(absDir, indexRoot3, true);
|
|
94341
|
+
} catch {
|
|
94342
|
+
continue;
|
|
94343
|
+
}
|
|
94344
|
+
for (const name of listing.folders) {
|
|
94345
|
+
const entryRel = relDir === "" ? name : `${relDir}/${name}`;
|
|
94346
|
+
results.push({ path: entryRel, type: "dir" });
|
|
94347
|
+
queue.push([path23.join(absDir, name), entryRel, depth + 1]);
|
|
94348
|
+
}
|
|
94349
|
+
for (const name of listing.files) {
|
|
94350
|
+
const entryRel = relDir === "" ? name : `${relDir}/${name}`;
|
|
94351
|
+
results.push({ path: entryRel, type: "file" });
|
|
94352
|
+
}
|
|
94353
|
+
}
|
|
94354
|
+
console.log(`[Listen] Sending get_tree_response: ${results.length} entries, has_more_depth=${hasMoreDepth}`);
|
|
94355
|
+
safeSocketSend(socket, {
|
|
94356
|
+
type: "get_tree_response",
|
|
94357
|
+
path: parsed.path,
|
|
94358
|
+
request_id: parsed.request_id,
|
|
94359
|
+
entries: results,
|
|
94360
|
+
has_more_depth: hasMoreDepth,
|
|
94361
|
+
success: true
|
|
94362
|
+
}, "listener_get_tree_send_failed", "listener_get_tree");
|
|
94363
|
+
} catch (err) {
|
|
94364
|
+
trackListenerError("listener_get_tree_failed", err, "listener_file_browser");
|
|
94365
|
+
console.error(`[Listen] get_tree error: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
94366
|
+
safeSocketSend(socket, {
|
|
94367
|
+
type: "get_tree_response",
|
|
94368
|
+
path: parsed.path,
|
|
94369
|
+
request_id: parsed.request_id,
|
|
94370
|
+
entries: [],
|
|
94371
|
+
has_more_depth: false,
|
|
94372
|
+
success: false,
|
|
94373
|
+
error: err instanceof Error ? err.message : "Failed to get tree"
|
|
94374
|
+
}, "listener_get_tree_send_failed", "listener_get_tree");
|
|
94375
|
+
}
|
|
94376
|
+
});
|
|
94377
|
+
return;
|
|
94378
|
+
}
|
|
93301
94379
|
if (isReadFileCommand(parsed)) {
|
|
93302
94380
|
console.log(`[Listen] Received read_file command: path=${parsed.path}, request_id=${parsed.request_id}`);
|
|
93303
94381
|
runDetachedListenerTask("read_file", async () => {
|
|
@@ -93358,6 +94436,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93358
94436
|
}
|
|
93359
94437
|
}
|
|
93360
94438
|
console.log(`[Listen] write_file success: ${parsed.path} (${parsed.content.length} bytes)`);
|
|
94439
|
+
refreshFileIndex();
|
|
93361
94440
|
safeSocketSend(socket, {
|
|
93362
94441
|
type: "write_file_response",
|
|
93363
94442
|
request_id: parsed.request_id,
|
|
@@ -93454,6 +94533,9 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93454
94533
|
expected_replacements: parsed.expected_replacements
|
|
93455
94534
|
});
|
|
93456
94535
|
console.log(`[Listen] edit_file success: ${result.replacements} replacement(s) at line ${result.startLine}`);
|
|
94536
|
+
if (result.replacements > 0) {
|
|
94537
|
+
refreshFileIndex();
|
|
94538
|
+
}
|
|
93457
94539
|
if (result.replacements > 0) {
|
|
93458
94540
|
try {
|
|
93459
94541
|
const contentAfter = await readFile11(parsed.file_path, "utf-8");
|
|
@@ -93509,144 +94591,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93509
94591
|
}
|
|
93510
94592
|
if (isListMemoryCommand(parsed)) {
|
|
93511
94593
|
runDetachedListenerTask("list_memory", async () => {
|
|
93512
|
-
|
|
93513
|
-
const { getMemoryFilesystemRoot: getMemoryFilesystemRoot2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
93514
|
-
const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memoryScanner(), exports_memoryScanner));
|
|
93515
|
-
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
|
|
93516
|
-
const { existsSync: existsSync26 } = await import("node:fs");
|
|
93517
|
-
const { join: join31, posix: posix2 } = await import("node:path");
|
|
93518
|
-
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
93519
|
-
const memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
|
|
93520
|
-
if (!memfsInitialized) {
|
|
93521
|
-
safeSocketSend(socket, {
|
|
93522
|
-
type: "list_memory_response",
|
|
93523
|
-
request_id: parsed.request_id,
|
|
93524
|
-
entries: [],
|
|
93525
|
-
done: true,
|
|
93526
|
-
total: 0,
|
|
93527
|
-
success: true,
|
|
93528
|
-
memfs_initialized: false
|
|
93529
|
-
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
93530
|
-
return;
|
|
93531
|
-
}
|
|
93532
|
-
const treeNodes = scanMemoryFilesystem2(memoryRoot);
|
|
93533
|
-
const fileNodes = getFileNodes2(treeNodes).filter((n) => n.name.endsWith(".md"));
|
|
93534
|
-
const includeReferences = parsed.include_references === true;
|
|
93535
|
-
const allPaths = new Set(fileNodes.map((node) => node.relativePath));
|
|
93536
|
-
const normalizeMemoryReference = (rawReference, sourcePath) => {
|
|
93537
|
-
let target = rawReference.trim();
|
|
93538
|
-
if (!target) {
|
|
93539
|
-
return null;
|
|
93540
|
-
}
|
|
93541
|
-
if (target.startsWith("http://") || target.startsWith("https://") || target.startsWith("mailto:")) {
|
|
93542
|
-
return null;
|
|
93543
|
-
}
|
|
93544
|
-
target = target.replace(/^<|>$/g, "");
|
|
93545
|
-
target = target.split("#")[0] ?? "";
|
|
93546
|
-
target = target.split("?")[0] ?? "";
|
|
93547
|
-
target = target.trim().replace(/\\/g, "/");
|
|
93548
|
-
if (!target || target.startsWith("#")) {
|
|
93549
|
-
return null;
|
|
93550
|
-
}
|
|
93551
|
-
if (target.includes("|")) {
|
|
93552
|
-
target = target.split("|")[0] ?? "";
|
|
93553
|
-
}
|
|
93554
|
-
if (!target) {
|
|
93555
|
-
return null;
|
|
93556
|
-
}
|
|
93557
|
-
const sourceDir = posix2.dirname(sourcePath.replace(/\\/g, "/"));
|
|
93558
|
-
const candidate = target.startsWith("./") || target.startsWith("../") ? posix2.normalize(posix2.join(sourceDir, target)) : posix2.normalize(target.startsWith("/") ? target.slice(1) : target);
|
|
93559
|
-
if (!candidate || candidate.startsWith("../") || candidate === "." || candidate === "..") {
|
|
93560
|
-
return null;
|
|
93561
|
-
}
|
|
93562
|
-
const withExtension = candidate.endsWith(".md") ? candidate : `${candidate}.md`;
|
|
93563
|
-
const candidates = new Set([withExtension]);
|
|
93564
|
-
const isExplicitRelative = target.startsWith("./") || target.startsWith("../");
|
|
93565
|
-
if (!isExplicitRelative && !target.startsWith("/") && sourceDir && sourceDir !== ".") {
|
|
93566
|
-
candidates.add(posix2.normalize(posix2.join(sourceDir, withExtension)));
|
|
93567
|
-
}
|
|
93568
|
-
if (!withExtension.startsWith("system/")) {
|
|
93569
|
-
candidates.add(posix2.normalize(`system/${withExtension}`));
|
|
93570
|
-
}
|
|
93571
|
-
for (const resolved of candidates) {
|
|
93572
|
-
if (allPaths.has(resolved)) {
|
|
93573
|
-
return resolved;
|
|
93574
|
-
}
|
|
93575
|
-
}
|
|
93576
|
-
return null;
|
|
93577
|
-
};
|
|
93578
|
-
const extractMemoryReferences = (body, sourcePath) => {
|
|
93579
|
-
if (!body.includes("[[")) {
|
|
93580
|
-
return [];
|
|
93581
|
-
}
|
|
93582
|
-
const refs = new Set;
|
|
93583
|
-
for (const wikiMatch of body.matchAll(WIKI_LINK_REGEX)) {
|
|
93584
|
-
const rawTarget = wikiMatch[1];
|
|
93585
|
-
if (!rawTarget)
|
|
93586
|
-
continue;
|
|
93587
|
-
const normalized = normalizeMemoryReference(rawTarget, sourcePath);
|
|
93588
|
-
if (normalized && normalized !== sourcePath) {
|
|
93589
|
-
refs.add(normalized);
|
|
93590
|
-
}
|
|
93591
|
-
}
|
|
93592
|
-
return [...refs];
|
|
93593
|
-
};
|
|
93594
|
-
const CHUNK_SIZE = 5;
|
|
93595
|
-
const total = fileNodes.length;
|
|
93596
|
-
for (let i = 0;i < total; i += CHUNK_SIZE) {
|
|
93597
|
-
const chunk = fileNodes.slice(i, i + CHUNK_SIZE);
|
|
93598
|
-
const entries = chunk.map((node) => {
|
|
93599
|
-
const raw2 = readFileContent2(node.fullPath);
|
|
93600
|
-
const { frontmatter, body } = parseFrontmatter2(raw2);
|
|
93601
|
-
const desc = frontmatter.description;
|
|
93602
|
-
return {
|
|
93603
|
-
relative_path: node.relativePath,
|
|
93604
|
-
is_system: node.relativePath.startsWith("system/") || node.relativePath.startsWith("system\\"),
|
|
93605
|
-
description: typeof desc === "string" ? desc : null,
|
|
93606
|
-
content: body,
|
|
93607
|
-
size: body.length,
|
|
93608
|
-
...includeReferences ? {
|
|
93609
|
-
references: extractMemoryReferences(body, node.relativePath)
|
|
93610
|
-
} : {}
|
|
93611
|
-
};
|
|
93612
|
-
});
|
|
93613
|
-
const done = i + CHUNK_SIZE >= total;
|
|
93614
|
-
const sent = safeSocketSend(socket, {
|
|
93615
|
-
type: "list_memory_response",
|
|
93616
|
-
request_id: parsed.request_id,
|
|
93617
|
-
entries,
|
|
93618
|
-
done,
|
|
93619
|
-
total,
|
|
93620
|
-
success: true,
|
|
93621
|
-
memfs_initialized: true
|
|
93622
|
-
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
93623
|
-
if (!sent) {
|
|
93624
|
-
return;
|
|
93625
|
-
}
|
|
93626
|
-
}
|
|
93627
|
-
if (total === 0) {
|
|
93628
|
-
safeSocketSend(socket, {
|
|
93629
|
-
type: "list_memory_response",
|
|
93630
|
-
request_id: parsed.request_id,
|
|
93631
|
-
entries: [],
|
|
93632
|
-
done: true,
|
|
93633
|
-
total: 0,
|
|
93634
|
-
success: true,
|
|
93635
|
-
memfs_initialized: true
|
|
93636
|
-
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
93637
|
-
}
|
|
93638
|
-
} catch (err) {
|
|
93639
|
-
trackListenerError("listener_list_memory_failed", err, "listener_memory_browser");
|
|
93640
|
-
safeSocketSend(socket, {
|
|
93641
|
-
type: "list_memory_response",
|
|
93642
|
-
request_id: parsed.request_id,
|
|
93643
|
-
entries: [],
|
|
93644
|
-
done: true,
|
|
93645
|
-
total: 0,
|
|
93646
|
-
success: false,
|
|
93647
|
-
error: err instanceof Error ? err.message : "Failed to list memory"
|
|
93648
|
-
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
93649
|
-
}
|
|
94594
|
+
await handleListMemoryCommand(parsed, socket);
|
|
93650
94595
|
});
|
|
93651
94596
|
return;
|
|
93652
94597
|
}
|
|
@@ -94225,7 +95170,7 @@ function createLegacyTestRuntime() {
|
|
|
94225
95170
|
}
|
|
94226
95171
|
return bridge;
|
|
94227
95172
|
}
|
|
94228
|
-
var channelsServiceLoaderOverride = null, WIKI_LINK_REGEX, __listenClientTestUtils;
|
|
95173
|
+
var channelsServiceLoaderOverride = null, WIKI_LINK_REGEX, DIR_LISTING_IGNORED_NAMES, __listenClientTestUtils;
|
|
94229
95174
|
var init_client4 = __esm(async () => {
|
|
94230
95175
|
init_available_models();
|
|
94231
95176
|
init_client2();
|
|
@@ -94272,6 +95217,7 @@ var init_client4 = __esm(async () => {
|
|
|
94272
95217
|
init_protocol_outbound()
|
|
94273
95218
|
]);
|
|
94274
95219
|
WIKI_LINK_REGEX = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
|
|
95220
|
+
DIR_LISTING_IGNORED_NAMES = new Set([".DS_Store", ".git", "Thumbs.db"]);
|
|
94275
95221
|
__listenClientTestUtils = {
|
|
94276
95222
|
setChannelsServiceLoaderForTests: (loader) => {
|
|
94277
95223
|
channelsServiceLoaderOverride = loader;
|
|
@@ -94324,8 +95270,10 @@ var init_client4 = __esm(async () => {
|
|
|
94324
95270
|
handleAbortMessageInput,
|
|
94325
95271
|
handleChangeDeviceStateInput,
|
|
94326
95272
|
handleCronCommand,
|
|
95273
|
+
handleListMemoryCommand,
|
|
94327
95274
|
isDetachedChannelsCommand,
|
|
94328
95275
|
handleChannelsProtocolCommand,
|
|
95276
|
+
handleChannelRegistryEvent,
|
|
94329
95277
|
handleSkillCommand,
|
|
94330
95278
|
handleCreateAgentCommand,
|
|
94331
95279
|
handleReflectionSettingsCommand,
|
|
@@ -99479,10 +100427,10 @@ var init_headless = __esm(async () => {
|
|
|
99479
100427
|
init_toolset()
|
|
99480
100428
|
]);
|
|
99481
100429
|
PROVIDER_FALLBACK_MAP = {
|
|
99482
|
-
opus: "bedrock-opus-4.6",
|
|
99483
100430
|
"opus-4.6-no-reasoning": "bedrock-opus-4.6",
|
|
99484
100431
|
"opus-4.6-low": "bedrock-opus-4.6",
|
|
99485
100432
|
"opus-4.6-medium": "bedrock-opus-4.6",
|
|
100433
|
+
"opus-4.6-high": "bedrock-opus-4.6",
|
|
99486
100434
|
"opus-4.6-xhigh": "bedrock-opus-4.6",
|
|
99487
100435
|
sonnet: "bedrock-sonnet-4.6",
|
|
99488
100436
|
"sonnet-1m": "bedrock-sonnet-4.6",
|
|
@@ -115408,16 +116356,16 @@ function clipStyledSpans(spans, maxColumns) {
|
|
|
115408
116356
|
return { spans: clipped, clipped: false };
|
|
115409
116357
|
}
|
|
115410
116358
|
function languageFromPath(filePath) {
|
|
115411
|
-
const
|
|
115412
|
-
const lower =
|
|
116359
|
+
const basename10 = filePath.split("/").pop() ?? filePath;
|
|
116360
|
+
const lower = basename10.toLowerCase();
|
|
115413
116361
|
if (lower === "makefile")
|
|
115414
116362
|
return "makefile";
|
|
115415
116363
|
if (lower === "dockerfile")
|
|
115416
116364
|
return "dockerfile";
|
|
115417
|
-
const dotIdx =
|
|
116365
|
+
const dotIdx = basename10.lastIndexOf(".");
|
|
115418
116366
|
if (dotIdx < 0)
|
|
115419
116367
|
return;
|
|
115420
|
-
const ext3 =
|
|
116368
|
+
const ext3 = basename10.slice(dotIdx + 1).toLowerCase();
|
|
115421
116369
|
return EXT_TO_LANG[ext3];
|
|
115422
116370
|
}
|
|
115423
116371
|
function colorForClassName(className, palette) {
|
|
@@ -121829,7 +122777,7 @@ var init_pasteRegistry = __esm(() => {
|
|
|
121829
122777
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
121830
122778
|
import { existsSync as existsSync34, readFileSync as readFileSync20, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
|
|
121831
122779
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
121832
|
-
import { basename as
|
|
122780
|
+
import { basename as basename10, extname as extname8, isAbsolute as isAbsolute20, join as join42, resolve as resolve29 } from "node:path";
|
|
121833
122781
|
function countLines2(text) {
|
|
121834
122782
|
return (text.match(/\r\n|\r|\n/g) || []).length + 1;
|
|
121835
122783
|
}
|
|
@@ -121886,7 +122834,7 @@ function translatePasteForImages(paste) {
|
|
|
121886
122834
|
const id = allocateImage({
|
|
121887
122835
|
data: b64,
|
|
121888
122836
|
mediaType: mt,
|
|
121889
|
-
filename:
|
|
122837
|
+
filename: basename10(filePath)
|
|
121890
122838
|
});
|
|
121891
122839
|
s = `[Image #${id}]`;
|
|
121892
122840
|
}
|
|
@@ -123493,7 +124441,7 @@ __export(exports_custom, {
|
|
|
123493
124441
|
});
|
|
123494
124442
|
import { existsSync as existsSync36 } from "node:fs";
|
|
123495
124443
|
import { readdir as readdir10, readFile as readFile14 } from "node:fs/promises";
|
|
123496
|
-
import { basename as
|
|
124444
|
+
import { basename as basename11, dirname as dirname17, join as join44 } from "node:path";
|
|
123497
124445
|
async function getCustomCommands() {
|
|
123498
124446
|
if (cachedCommands !== null) {
|
|
123499
124447
|
return cachedCommands;
|
|
@@ -123553,7 +124501,7 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
|
|
|
123553
124501
|
async function parseCommandFile(filePath, rootPath, source2) {
|
|
123554
124502
|
const content = await readFile14(filePath, "utf-8");
|
|
123555
124503
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
123556
|
-
const id =
|
|
124504
|
+
const id = basename11(filePath, ".md");
|
|
123557
124505
|
const relativePath = dirname17(filePath).slice(rootPath.length);
|
|
123558
124506
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
123559
124507
|
let description = getStringField(frontmatter, "description");
|
|
@@ -126340,6 +127288,8 @@ function formatReasoningLabel(effort) {
|
|
|
126340
127288
|
if (effort === "none")
|
|
126341
127289
|
return null;
|
|
126342
127290
|
if (effort === "xhigh")
|
|
127291
|
+
return "xhigh";
|
|
127292
|
+
if (effort === "max")
|
|
126343
127293
|
return "max";
|
|
126344
127294
|
if (effort === "minimal")
|
|
126345
127295
|
return "minimal";
|
|
@@ -127378,6 +128328,8 @@ function getReasoningEffortTag(effort) {
|
|
|
127378
128328
|
if (effort === "none")
|
|
127379
128329
|
return null;
|
|
127380
128330
|
if (effort === "xhigh")
|
|
128331
|
+
return "xhigh";
|
|
128332
|
+
if (effort === "max")
|
|
127381
128333
|
return "max";
|
|
127382
128334
|
if (effort === "minimal")
|
|
127383
128335
|
return "minimal";
|
|
@@ -135005,10 +135957,12 @@ var init_MessageSearch = __esm(async () => {
|
|
|
135005
135957
|
});
|
|
135006
135958
|
|
|
135007
135959
|
// src/cli/components/ModelReasoningSelector.tsx
|
|
135008
|
-
function formatEffortLabel(effort) {
|
|
135960
|
+
function formatEffortLabel(effort, hasDistinctMaxTier) {
|
|
135009
135961
|
if (effort === "none")
|
|
135010
135962
|
return "Off";
|
|
135011
135963
|
if (effort === "xhigh")
|
|
135964
|
+
return hasDistinctMaxTier ? "Extra-High" : "Max";
|
|
135965
|
+
if (effort === "max")
|
|
135012
135966
|
return "Max";
|
|
135013
135967
|
if (effort === "minimal")
|
|
135014
135968
|
return "Minimal";
|
|
@@ -135035,6 +135989,7 @@ function ModelReasoningSelector({
|
|
|
135035
135989
|
}, [options, initialModelId]);
|
|
135036
135990
|
const selectedOption = options[selectedIndex] ?? options[0];
|
|
135037
135991
|
const effortOptions = import_react82.useMemo(() => options.filter((option) => option.effort !== "none"), [options]);
|
|
135992
|
+
const hasDistinctMaxTier = import_react82.useMemo(() => options.some((option) => option.effort === "max"), [options]);
|
|
135038
135993
|
const totalBars = Math.max(effortOptions.length, 1);
|
|
135039
135994
|
const selectedBars = import_react82.useMemo(() => {
|
|
135040
135995
|
if (!selectedOption)
|
|
@@ -135073,7 +136028,7 @@ function ModelReasoningSelector({
|
|
|
135073
136028
|
setSelectedIndex((prev) => (prev + 1) % options.length);
|
|
135074
136029
|
}
|
|
135075
136030
|
});
|
|
135076
|
-
const effortLabel = selectedOption ? formatEffortLabel(selectedOption.effort) : "Medium";
|
|
136031
|
+
const effortLabel = selectedOption ? formatEffortLabel(selectedOption.effort, hasDistinctMaxTier) : "Medium";
|
|
135077
136032
|
const selectedText = selectedBars > 0 ? EFFORT_BLOCK.repeat(selectedBars) : "";
|
|
135078
136033
|
const remainingBars = totalBars > selectedBars ? EFFORT_BLOCK.repeat(totalBars - selectedBars) : "";
|
|
135079
136034
|
return /* @__PURE__ */ jsx_dev_runtime59.jsxDEV(Box_default, {
|
|
@@ -143160,12 +144115,12 @@ function deriveReasoningEffort(modelSettings, llmConfig) {
|
|
|
143160
144115
|
const effort = modelSettings.effort;
|
|
143161
144116
|
if (effort === "low" || effort === "medium" || effort === "high")
|
|
143162
144117
|
return effort;
|
|
143163
|
-
if (effort === "max")
|
|
143164
|
-
return
|
|
144118
|
+
if (effort === "xhigh" || effort === "max")
|
|
144119
|
+
return effort;
|
|
143165
144120
|
}
|
|
143166
144121
|
}
|
|
143167
144122
|
const re = llmConfig?.reasoning_effort;
|
|
143168
|
-
if (re === "none" || re === "minimal" || re === "low" || re === "medium" || re === "high" || re === "xhigh")
|
|
144123
|
+
if (re === "none" || re === "minimal" || re === "low" || re === "medium" || re === "high" || re === "xhigh" || re === "max")
|
|
143169
144124
|
return re;
|
|
143170
144125
|
if (llmConfig?.enable_reasoner === false)
|
|
143171
144126
|
return "none";
|
|
@@ -143174,7 +144129,7 @@ function deriveReasoningEffort(modelSettings, llmConfig) {
|
|
|
143174
144129
|
function inferReasoningEffortFromModelPreset(modelId, modelHandle) {
|
|
143175
144130
|
const modelInfo = (modelId ? getModelInfo2(modelId) : null) ?? (modelHandle ? getModelInfo2(modelHandle) : null);
|
|
143176
144131
|
const presetEffort = modelInfo?.updateArgs?.reasoning_effort;
|
|
143177
|
-
if (presetEffort === "none" || presetEffort === "minimal" || presetEffort === "low" || presetEffort === "medium" || presetEffort === "high" || presetEffort === "xhigh") {
|
|
144132
|
+
if (presetEffort === "none" || presetEffort === "minimal" || presetEffort === "low" || presetEffort === "medium" || presetEffort === "high" || presetEffort === "xhigh" || presetEffort === "max") {
|
|
143178
144133
|
return presetEffort;
|
|
143179
144134
|
}
|
|
143180
144135
|
return null;
|
|
@@ -143215,7 +144170,8 @@ function getErrorHintForStopReason(stopReason, currentModelId, modelEndpointType
|
|
|
143215
144170
|
}
|
|
143216
144171
|
const isAutoModel = currentModelId?.startsWith("auto") ?? false;
|
|
143217
144172
|
const statusInfo = modelEndpointType && !isAutoModel ? PROVIDER_STATUS_PAGES[modelEndpointType] : undefined;
|
|
143218
|
-
const
|
|
144173
|
+
const isOpus46 = currentModelId?.startsWith("opus-4.6") ?? false;
|
|
144174
|
+
const hasBedrockOpus = isOpus46 && modelEndpointType === "anthropic" && getModelInfo2("bedrock-opus-4.6");
|
|
143219
144175
|
const modelSwapSuffix = hasBedrockOpus ? " (e.g. Opus 4.6 via Amazon Bedrock)" : "";
|
|
143220
144176
|
if (statusInfo) {
|
|
143221
144177
|
return [
|
|
@@ -143554,6 +144510,10 @@ function App2({
|
|
|
143554
144510
|
import_react104.useEffect(() => {
|
|
143555
144511
|
conversationIdRef.current = conversationId;
|
|
143556
144512
|
}, [conversationId]);
|
|
144513
|
+
const setConversationIdAndRef = import_react104.useCallback((nextConversationId) => {
|
|
144514
|
+
conversationIdRef.current = nextConversationId;
|
|
144515
|
+
setConversationId3(nextConversationId);
|
|
144516
|
+
}, []);
|
|
143557
144517
|
const pendingTranscriptStartLineIndexRef = import_react104.useRef(null);
|
|
143558
144518
|
const lastRunIdRef = import_react104.useRef(null);
|
|
143559
144519
|
const resumeKey = useSuspend();
|
|
@@ -143577,10 +144537,9 @@ function App2({
|
|
|
143577
144537
|
import_react104.useEffect(() => {
|
|
143578
144538
|
if (initialConversationId !== prevInitialConversationIdRef.current) {
|
|
143579
144539
|
prevInitialConversationIdRef.current = initialConversationId;
|
|
143580
|
-
|
|
143581
|
-
setConversationId3(initialConversationId);
|
|
144540
|
+
setConversationIdAndRef(initialConversationId);
|
|
143582
144541
|
}
|
|
143583
|
-
}, [initialConversationId]);
|
|
144542
|
+
}, [initialConversationId, setConversationIdAndRef]);
|
|
143584
144543
|
import_react104.useEffect(() => {
|
|
143585
144544
|
if (agentId) {
|
|
143586
144545
|
setCurrentAgentId(agentId);
|
|
@@ -147071,7 +148030,7 @@ ${feedback}
|
|
|
147071
148030
|
const client = await getClient();
|
|
147072
148031
|
const resumeData = await getResumeData2(client, agentState, conversationId2);
|
|
147073
148032
|
await maybeCarryOverActiveConversationModel(conversationId2);
|
|
147074
|
-
|
|
148033
|
+
setConversationIdAndRef(conversationId2);
|
|
147075
148034
|
pendingConversationSwitchRef.current = {
|
|
147076
148035
|
origin: "fork",
|
|
147077
148036
|
conversationId: conversationId2,
|
|
@@ -147136,6 +148095,7 @@ ${feedback}
|
|
|
147136
148095
|
runEndHooks,
|
|
147137
148096
|
maybeCarryOverActiveConversationModel,
|
|
147138
148097
|
resetBootstrapReminderState,
|
|
148098
|
+
setConversationIdAndRef,
|
|
147139
148099
|
setCommandRunning,
|
|
147140
148100
|
setStreaming,
|
|
147141
148101
|
recoverRestoredPendingApprovals,
|
|
@@ -147188,7 +148148,7 @@ ${feedback}
|
|
|
147188
148148
|
setLlmConfig(agent.llm_config);
|
|
147189
148149
|
const agentModelHandle = getPreferredAgentModelHandle2(agent);
|
|
147190
148150
|
setCurrentModelHandle(agentModelHandle);
|
|
147191
|
-
|
|
148151
|
+
setConversationIdAndRef(targetConversationId);
|
|
147192
148152
|
resetBootstrapReminderState();
|
|
147193
148153
|
{
|
|
147194
148154
|
const { getModelDisplayName: getModelDisplayName3 } = await Promise.resolve().then(() => (init_model2(), exports_model2));
|
|
@@ -147241,7 +148201,8 @@ ${feedback}
|
|
|
147241
148201
|
resetDeferredToolCallCommits,
|
|
147242
148202
|
resetTrajectoryBases,
|
|
147243
148203
|
resetBootstrapReminderState,
|
|
147244
|
-
resetPendingReasoningCycle
|
|
148204
|
+
resetPendingReasoningCycle,
|
|
148205
|
+
setConversationIdAndRef
|
|
147245
148206
|
]);
|
|
147246
148207
|
const handleCreateNewAgent = import_react104.useCallback(async (name) => {
|
|
147247
148208
|
setActiveOverlay(null);
|
|
@@ -147309,7 +148270,7 @@ ${feedback}
|
|
|
147309
148270
|
setLlmConfig(agent.llm_config);
|
|
147310
148271
|
const agentModelHandle = getPreferredAgentModelHandle2(agent);
|
|
147311
148272
|
setCurrentModelHandle(agentModelHandle);
|
|
147312
|
-
|
|
148273
|
+
setConversationIdAndRef(targetConversationId);
|
|
147313
148274
|
pendingConversationSwitchRef.current = {
|
|
147314
148275
|
origin: "agent-switch",
|
|
147315
148276
|
conversationId: targetConversationId,
|
|
@@ -147343,7 +148304,8 @@ ${feedback}
|
|
|
147343
148304
|
setCommandRunning,
|
|
147344
148305
|
resetDeferredToolCallCommits,
|
|
147345
148306
|
resetTrajectoryBases,
|
|
147346
|
-
resetBootstrapReminderState
|
|
148307
|
+
resetBootstrapReminderState,
|
|
148308
|
+
setConversationIdAndRef
|
|
147347
148309
|
]);
|
|
147348
148310
|
const handleBashSubmit = import_react104.useCallback(async (command) => {
|
|
147349
148311
|
if (bashRunning)
|
|
@@ -148284,7 +149246,7 @@ Type your task to begin the loop.`, true);
|
|
|
148284
149246
|
hasSetConversationSummaryRef.current = true;
|
|
148285
149247
|
}
|
|
148286
149248
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
148287
|
-
|
|
149249
|
+
setConversationIdAndRef(conversation.id);
|
|
148288
149250
|
pendingConversationSwitchRef.current = {
|
|
148289
149251
|
origin: "new",
|
|
148290
149252
|
conversationId: conversation.id,
|
|
@@ -148329,7 +149291,7 @@ Type your task to begin the loop.`, true);
|
|
|
148329
149291
|
hasSetConversationSummaryRef.current = true;
|
|
148330
149292
|
}
|
|
148331
149293
|
await maybeCarryOverActiveConversationModel(forked.id);
|
|
148332
|
-
|
|
149294
|
+
setConversationIdAndRef(forked.id);
|
|
148333
149295
|
pendingConversationSwitchRef.current = {
|
|
148334
149296
|
origin: "fork",
|
|
148335
149297
|
conversationId: forked.id,
|
|
@@ -148383,7 +149345,7 @@ Type your task to begin the loop.`, true);
|
|
|
148383
149345
|
isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
|
|
148384
149346
|
});
|
|
148385
149347
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
148386
|
-
|
|
149348
|
+
setConversationIdAndRef(conversation.id);
|
|
148387
149349
|
pendingConversationSwitchRef.current = {
|
|
148388
149350
|
origin: "clear",
|
|
148389
149351
|
conversationId: conversation.id,
|
|
@@ -148634,7 +149596,7 @@ Type your task to begin the loop.`, true);
|
|
|
148634
149596
|
if (agentState) {
|
|
148635
149597
|
const client = await getClient();
|
|
148636
149598
|
const resumeData = await getResumeData2(client, agentState, targetConvId);
|
|
148637
|
-
|
|
149599
|
+
setConversationIdAndRef(targetConvId);
|
|
148638
149600
|
pendingConversationSwitchRef.current = {
|
|
148639
149601
|
origin: "resume-direct",
|
|
148640
149602
|
conversationId: targetConvId,
|
|
@@ -149569,7 +150531,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
149569
150531
|
name: agentName,
|
|
149570
150532
|
description: agentDescription,
|
|
149571
150533
|
lastRunAt: agentLastRunAt,
|
|
149572
|
-
conversationId
|
|
150534
|
+
conversationId: conversationIdRef.current
|
|
149573
150535
|
},
|
|
149574
150536
|
state: sharedReminderStateRef.current,
|
|
149575
150537
|
sessionContextReminderEnabled,
|
|
@@ -150022,6 +150984,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
150022
150984
|
agentName,
|
|
150023
150985
|
agentDescription,
|
|
150024
150986
|
agentLastRunAt,
|
|
150987
|
+
conversationId,
|
|
150025
150988
|
commandRunner,
|
|
150026
150989
|
handleExit,
|
|
150027
150990
|
isExecutingTool,
|
|
@@ -150040,7 +151003,8 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
150040
151003
|
resetTrajectoryBases,
|
|
150041
151004
|
sessionContextReminderEnabled,
|
|
150042
151005
|
appendTaskNotificationEvents,
|
|
150043
|
-
maybeCarryOverActiveConversationModel
|
|
151006
|
+
maybeCarryOverActiveConversationModel,
|
|
151007
|
+
setConversationIdAndRef
|
|
150044
151008
|
]);
|
|
150045
151009
|
const onSubmitRef = import_react104.useRef(onSubmit);
|
|
150046
151010
|
import_react104.useEffect(() => {
|
|
@@ -150555,7 +151519,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
150555
151519
|
const modelHandle = model.handle ?? model.id;
|
|
150556
151520
|
const modelUpdateArgs = model.updateArgs;
|
|
150557
151521
|
const rawReasoningEffort = modelUpdateArgs?.reasoning_effort;
|
|
150558
|
-
const reasoningLevel = typeof rawReasoningEffort === "string" ? rawReasoningEffort === "none" ? "no" : rawReasoningEffort === "xhigh" ? "max" : rawReasoningEffort : modelUpdateArgs?.enable_reasoner === false ? "no" : null;
|
|
151522
|
+
const reasoningLevel = typeof rawReasoningEffort === "string" ? rawReasoningEffort === "none" ? "no" : rawReasoningEffort === "xhigh" ? model.label.includes("Opus 4.7") ? "extra-high" : "max" : rawReasoningEffort : modelUpdateArgs?.enable_reasoner === false ? "no" : null;
|
|
150559
151523
|
const selectedContextWindow = model.updateArgs?.context_window;
|
|
150560
151524
|
const reasoningTierOptions = getReasoningTierOptionsForHandle3(modelHandle, selectedContextWindow);
|
|
150561
151525
|
if (!opts?.skipReasoningPrompt && activeOverlay === "model" && reasoningTierOptions.length > 1) {
|
|
@@ -151040,7 +152004,7 @@ ${guidance}`);
|
|
|
151040
152004
|
const client = await getClient();
|
|
151041
152005
|
if (agentState) {
|
|
151042
152006
|
const resumeData = await getResumeData2(client, agentState, action.conversationId);
|
|
151043
|
-
|
|
152007
|
+
setConversationIdAndRef(action.conversationId);
|
|
151044
152008
|
pendingConversationSwitchRef.current = {
|
|
151045
152009
|
origin: "resume-selector",
|
|
151046
152010
|
conversationId: action.conversationId,
|
|
@@ -151093,7 +152057,8 @@ ${guidance}`);
|
|
|
151093
152057
|
commandRunner.getHandle,
|
|
151094
152058
|
commandRunner.start,
|
|
151095
152059
|
recoverRestoredPendingApprovals,
|
|
151096
|
-
resetBootstrapReminderState
|
|
152060
|
+
resetBootstrapReminderState,
|
|
152061
|
+
setConversationIdAndRef
|
|
151097
152062
|
]);
|
|
151098
152063
|
const handleFeedbackSubmit = import_react104.useCallback(async (message) => {
|
|
151099
152064
|
const overlayCommand = consumeOverlayCommand("feedback");
|
|
@@ -151330,7 +152295,16 @@ ${guidance}`);
|
|
|
151330
152295
|
}).filter((m) => Boolean(m.effort));
|
|
151331
152296
|
if (tiers.length < 2)
|
|
151332
152297
|
return;
|
|
151333
|
-
const
|
|
152298
|
+
const anthropicXHighEffort = modelHandle.includes("claude-opus-4-7") ? "xhigh" : "max";
|
|
152299
|
+
const order = [
|
|
152300
|
+
"none",
|
|
152301
|
+
"minimal",
|
|
152302
|
+
"low",
|
|
152303
|
+
"medium",
|
|
152304
|
+
"high",
|
|
152305
|
+
"xhigh",
|
|
152306
|
+
"max"
|
|
152307
|
+
];
|
|
151334
152308
|
const rank = (effort) => {
|
|
151335
152309
|
const idx = order.indexOf(effort);
|
|
151336
152310
|
return idx >= 0 ? idx : 999;
|
|
@@ -151367,12 +152341,11 @@ ${guidance}`);
|
|
|
151367
152341
|
};
|
|
151368
152342
|
}
|
|
151369
152343
|
if (ms.provider_type === "anthropic" || ms.provider_type === "bedrock") {
|
|
151370
|
-
const anthropicEffort = next.effort === "xhigh" ? "max" : next.effort;
|
|
151371
152344
|
return {
|
|
151372
152345
|
...prev,
|
|
151373
152346
|
model_settings: {
|
|
151374
152347
|
...ms,
|
|
151375
|
-
effort:
|
|
152348
|
+
effort: next.effort === "xhigh" ? anthropicXHighEffort : next.effort
|
|
151376
152349
|
}
|
|
151377
152350
|
};
|
|
151378
152351
|
}
|
|
@@ -152351,7 +153324,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152351
153324
|
if (agentState) {
|
|
152352
153325
|
const client = await getClient();
|
|
152353
153326
|
const resumeData = await getResumeData2(client, agentState, convId);
|
|
152354
|
-
|
|
153327
|
+
setConversationIdAndRef(convId);
|
|
152355
153328
|
pendingConversationSwitchRef.current = {
|
|
152356
153329
|
origin: "resume-selector",
|
|
152357
153330
|
conversationId: convId,
|
|
@@ -152463,7 +153436,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152463
153436
|
isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
|
|
152464
153437
|
});
|
|
152465
153438
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
152466
|
-
|
|
153439
|
+
setConversationIdAndRef(conversation.id);
|
|
152467
153440
|
settingsManager.persistSession(agentId, conversation.id);
|
|
152468
153441
|
const currentAgentName = agentState?.name || "Unnamed Agent";
|
|
152469
153442
|
const shortConvId = conversation.id.slice(0, 20);
|
|
@@ -152547,7 +153520,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152547
153520
|
if (agentState) {
|
|
152548
153521
|
const client = await getClient();
|
|
152549
153522
|
const resumeData = await getResumeData2(client, agentState, actualTargetConv);
|
|
152550
|
-
|
|
153523
|
+
setConversationIdAndRef(actualTargetConv);
|
|
152551
153524
|
pendingConversationSwitchRef.current = {
|
|
152552
153525
|
origin: "search",
|
|
152553
153526
|
conversationId: actualTargetConv,
|
|
@@ -153919,10 +154892,12 @@ var exports_memoryFilesystem2 = {};
|
|
|
153919
154892
|
__export(exports_memoryFilesystem2, {
|
|
153920
154893
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree2,
|
|
153921
154894
|
labelFromRelativePath: () => labelFromRelativePath2,
|
|
154895
|
+
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer2,
|
|
153922
154896
|
isLettaCloud: () => isLettaCloud2,
|
|
153923
154897
|
getMemorySystemDir: () => getMemorySystemDir2,
|
|
153924
154898
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot2,
|
|
153925
154899
|
ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs2,
|
|
154900
|
+
ensureLocalMemfsCheckout: () => ensureLocalMemfsCheckout2,
|
|
153926
154901
|
enableMemfsIfCloud: () => enableMemfsIfCloud2,
|
|
153927
154902
|
applyMemfsFlags: () => applyMemfsFlags2,
|
|
153928
154903
|
MEMORY_TREE_MAX_LINES: () => MEMORY_TREE_MAX_LINES2,
|
|
@@ -153952,6 +154927,23 @@ function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir41()) {
|
|
|
153952
154927
|
mkdirSync30(systemDir, { recursive: true });
|
|
153953
154928
|
}
|
|
153954
154929
|
}
|
|
154930
|
+
async function isMemfsEnabledOnServer2(agentId) {
|
|
154931
|
+
const { getClient: getClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
154932
|
+
const client = await getClient3();
|
|
154933
|
+
const agent = await client.agents.retrieve(agentId);
|
|
154934
|
+
const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
154935
|
+
const enabled = agent.tags?.includes(GIT_MEMORY_ENABLED_TAG2) ?? false;
|
|
154936
|
+
const { settingsManager: settingsManager3 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
154937
|
+
settingsManager3.setMemfsEnabled(agentId, enabled);
|
|
154938
|
+
return enabled;
|
|
154939
|
+
}
|
|
154940
|
+
async function ensureLocalMemfsCheckout2(agentId) {
|
|
154941
|
+
const { isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
154942
|
+
if (isGitRepo2(agentId)) {
|
|
154943
|
+
return;
|
|
154944
|
+
}
|
|
154945
|
+
await cloneMemoryRepo2(agentId);
|
|
154946
|
+
}
|
|
153955
154947
|
function labelFromRelativePath2(relativePath) {
|
|
153956
154948
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
153957
154949
|
return normalized.replace(/\.md$/, "");
|
|
@@ -154794,6 +155786,9 @@ init_openai_codex_provider();
|
|
|
154794
155786
|
init_debug();
|
|
154795
155787
|
init_available_models();
|
|
154796
155788
|
init_client2();
|
|
155789
|
+
function supportsDistinctAnthropicXHighEffort(modelHandle) {
|
|
155790
|
+
return modelHandle.includes("claude-opus-4-7");
|
|
155791
|
+
}
|
|
154797
155792
|
function buildModelSettings(modelHandle, updateArgs) {
|
|
154798
155793
|
const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
|
|
154799
155794
|
const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
|
|
@@ -154827,10 +155822,13 @@ function buildModelSettings(modelHandle, updateArgs) {
|
|
|
154827
155822
|
parallel_tool_calls: true
|
|
154828
155823
|
};
|
|
154829
155824
|
const effort = updateArgs?.reasoning_effort;
|
|
155825
|
+
const hasDistinctXHigh = supportsDistinctAnthropicXHighEffort(modelHandle);
|
|
154830
155826
|
if (effort === "low" || effort === "medium" || effort === "high") {
|
|
154831
155827
|
anthropicSettings.effort = effort;
|
|
154832
155828
|
} else if (effort === "xhigh") {
|
|
154833
|
-
anthropicSettings.effort = "max";
|
|
155829
|
+
anthropicSettings.effort = hasDistinctXHigh ? "xhigh" : "max";
|
|
155830
|
+
} else if (effort === "max") {
|
|
155831
|
+
anthropicSettings.effort = effort;
|
|
154834
155832
|
}
|
|
154835
155833
|
if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
|
|
154836
155834
|
anthropicSettings.thinking = {
|
|
@@ -154883,10 +155881,13 @@ function buildModelSettings(modelHandle, updateArgs) {
|
|
|
154883
155881
|
parallel_tool_calls: true
|
|
154884
155882
|
};
|
|
154885
155883
|
const effort = updateArgs?.reasoning_effort;
|
|
155884
|
+
const hasDistinctXHigh = supportsDistinctAnthropicXHighEffort(modelHandle);
|
|
154886
155885
|
if (effort === "low" || effort === "medium" || effort === "high") {
|
|
154887
155886
|
bedrockSettings.effort = effort;
|
|
154888
155887
|
} else if (effort === "xhigh") {
|
|
154889
|
-
bedrockSettings.effort = "max";
|
|
155888
|
+
bedrockSettings.effort = hasDistinctXHigh ? "xhigh" : "max";
|
|
155889
|
+
} else if (effort === "max") {
|
|
155890
|
+
bedrockSettings.effort = effort;
|
|
154890
155891
|
}
|
|
154891
155892
|
if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
|
|
154892
155893
|
bedrockSettings.thinking = {
|
|
@@ -157714,8 +158715,14 @@ Usage:
|
|
|
157714
158715
|
letta channels route list [--channel <ch>] Show routing table
|
|
157715
158716
|
letta channels route add [options] Add a route
|
|
157716
158717
|
letta channels route remove [options] Remove a route
|
|
158718
|
+
letta channels bind [options] Bind a Slack app to an agent
|
|
157717
158719
|
letta channels pair [options] Approve pairing + bind to agent
|
|
157718
158720
|
|
|
158721
|
+
Bind options (Slack only):
|
|
158722
|
+
--channel slack Required
|
|
158723
|
+
--account-id <id> Channel account ID (optional; inferred when only one account exists)
|
|
158724
|
+
--agent <id> Agent ID (defaults to LETTA_AGENT_ID)
|
|
158725
|
+
|
|
157719
158726
|
Route add options:
|
|
157720
158727
|
--channel <name> Channel name (e.g. "telegram")
|
|
157721
158728
|
--account-id <id> Channel account ID (required when multiple accounts exist)
|
|
@@ -158009,6 +159016,46 @@ async function handlePair(values) {
|
|
|
158009
159016
|
}
|
|
158010
159017
|
return result.success ? 0 : 1;
|
|
158011
159018
|
}
|
|
159019
|
+
function handleBind(values) {
|
|
159020
|
+
const channelId = values.channel;
|
|
159021
|
+
const accountId = values["account-id"];
|
|
159022
|
+
const agentId = getAgentId3(values.agent);
|
|
159023
|
+
if (!channelId) {
|
|
159024
|
+
console.error("Error: --channel is required.");
|
|
159025
|
+
return 1;
|
|
159026
|
+
}
|
|
159027
|
+
if (channelId !== "slack") {
|
|
159028
|
+
console.error(`"bind" is only supported for Slack. Telegram binding is route-scoped — use "pair" or "route add" instead.`);
|
|
159029
|
+
return 1;
|
|
159030
|
+
}
|
|
159031
|
+
if (!agentId) {
|
|
159032
|
+
console.error("Error: --agent is required (or set LETTA_AGENT_ID env var).");
|
|
159033
|
+
return 1;
|
|
159034
|
+
}
|
|
159035
|
+
let resolvedAccountId;
|
|
159036
|
+
try {
|
|
159037
|
+
resolvedAccountId = resolveSelectedAccountId(channelId, accountId);
|
|
159038
|
+
} catch (error) {
|
|
159039
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
159040
|
+
return 1;
|
|
159041
|
+
}
|
|
159042
|
+
const account = getChannelAccount(channelId, resolvedAccountId);
|
|
159043
|
+
if (!account) {
|
|
159044
|
+
console.error(`Account "${resolvedAccountId}" not found for channel "${channelId}".`);
|
|
159045
|
+
return 1;
|
|
159046
|
+
}
|
|
159047
|
+
account.agentId = agentId;
|
|
159048
|
+
account.updatedAt = new Date().toISOString();
|
|
159049
|
+
upsertChannelAccount(channelId, account);
|
|
159050
|
+
console.log(JSON.stringify({
|
|
159051
|
+
success: true,
|
|
159052
|
+
channel: channelId,
|
|
159053
|
+
accountId: resolvedAccountId,
|
|
159054
|
+
agentId
|
|
159055
|
+
}, null, 2));
|
|
159056
|
+
console.warn("Note: If a listener is running, restart it for the binding to take effect.");
|
|
159057
|
+
return 0;
|
|
159058
|
+
}
|
|
158012
159059
|
async function runChannelsSubcommand(argv) {
|
|
158013
159060
|
const { values, positionals } = parseChannelsArgs(argv);
|
|
158014
159061
|
if (values.help) {
|
|
@@ -158049,6 +159096,8 @@ async function runChannelsSubcommand(argv) {
|
|
|
158049
159096
|
return 1;
|
|
158050
159097
|
}
|
|
158051
159098
|
}
|
|
159099
|
+
case "bind":
|
|
159100
|
+
return handleBind(values);
|
|
158052
159101
|
case "pair":
|
|
158053
159102
|
return await handlePair(values);
|
|
158054
159103
|
default:
|
|
@@ -158056,7 +159105,7 @@ async function runChannelsSubcommand(argv) {
|
|
|
158056
159105
|
printUsage3();
|
|
158057
159106
|
return 0;
|
|
158058
159107
|
}
|
|
158059
|
-
console.error(`Unknown channels action: "${action}". Use: install, configure, status, route, pair`);
|
|
159108
|
+
console.error(`Unknown channels action: "${action}". Use: install, configure, status, route, bind, pair`);
|
|
158060
159109
|
return 1;
|
|
158061
159110
|
}
|
|
158062
159111
|
}
|
|
@@ -163181,4 +164230,4 @@ Error during initialization: ${message}`);
|
|
|
163181
164230
|
}
|
|
163182
164231
|
main();
|
|
163183
164232
|
|
|
163184
|
-
//# debugId=
|
|
164233
|
+
//# debugId=B587994115421B1064756E2164756E21
|