@letta-ai/letta-code 0.23.4 → 0.23.5
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 +909 -213
- package/package.json +1 -1
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.23.
|
|
3272
|
+
version: "0.23.5",
|
|
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: {
|
|
@@ -8394,7 +8394,7 @@ var init_models2 = __esm(() => {
|
|
|
8394
8394
|
id: "opus",
|
|
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,88 @@ var init_models2 = __esm(() => {
|
|
|
8458
8458
|
parallel_tool_calls: true
|
|
8459
8459
|
}
|
|
8460
8460
|
},
|
|
8461
|
+
{
|
|
8462
|
+
id: "opus-4.7",
|
|
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-medium",
|
|
8492
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8493
|
+
label: "Opus 4.7",
|
|
8494
|
+
description: "Opus 4.7 (med reasoning)",
|
|
8495
|
+
updateArgs: {
|
|
8496
|
+
context_window: 200000,
|
|
8497
|
+
max_output_tokens: 128000,
|
|
8498
|
+
reasoning_effort: "medium",
|
|
8499
|
+
enable_reasoner: true,
|
|
8500
|
+
max_reasoning_tokens: 12000,
|
|
8501
|
+
parallel_tool_calls: true
|
|
8502
|
+
}
|
|
8503
|
+
},
|
|
8504
|
+
{
|
|
8505
|
+
id: "opus-4.7-high",
|
|
8506
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8507
|
+
label: "Opus 4.7",
|
|
8508
|
+
description: "Opus 4.7 (high reasoning)",
|
|
8509
|
+
updateArgs: {
|
|
8510
|
+
context_window: 200000,
|
|
8511
|
+
max_output_tokens: 128000,
|
|
8512
|
+
reasoning_effort: "high",
|
|
8513
|
+
enable_reasoner: true,
|
|
8514
|
+
parallel_tool_calls: true
|
|
8515
|
+
}
|
|
8516
|
+
},
|
|
8517
|
+
{
|
|
8518
|
+
id: "opus-4.7-xhigh",
|
|
8519
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8520
|
+
label: "Opus 4.7",
|
|
8521
|
+
description: "Opus 4.7 (extra-high reasoning)",
|
|
8522
|
+
updateArgs: {
|
|
8523
|
+
context_window: 200000,
|
|
8524
|
+
max_output_tokens: 128000,
|
|
8525
|
+
reasoning_effort: "xhigh",
|
|
8526
|
+
enable_reasoner: true,
|
|
8527
|
+
parallel_tool_calls: true
|
|
8528
|
+
}
|
|
8529
|
+
},
|
|
8530
|
+
{
|
|
8531
|
+
id: "opus-4.7-max",
|
|
8532
|
+
handle: "anthropic/claude-opus-4-7",
|
|
8533
|
+
label: "Opus 4.7",
|
|
8534
|
+
description: "Opus 4.7 (max reasoning)",
|
|
8535
|
+
updateArgs: {
|
|
8536
|
+
context_window: 200000,
|
|
8537
|
+
max_output_tokens: 128000,
|
|
8538
|
+
reasoning_effort: "max",
|
|
8539
|
+
enable_reasoner: true,
|
|
8540
|
+
parallel_tool_calls: true
|
|
8541
|
+
}
|
|
8542
|
+
},
|
|
8461
8543
|
{
|
|
8462
8544
|
id: "opus-1m",
|
|
8463
8545
|
handle: "anthropic/claude-opus-4-6",
|
|
@@ -41245,6 +41327,18 @@ function normalizeSlackAttachmentLike(value) {
|
|
|
41245
41327
|
files
|
|
41246
41328
|
};
|
|
41247
41329
|
}
|
|
41330
|
+
function resolveSlackThreadMessageText(message) {
|
|
41331
|
+
const text = typeof message.text === "string" ? message.text.trim() : "";
|
|
41332
|
+
if (text) {
|
|
41333
|
+
return text;
|
|
41334
|
+
}
|
|
41335
|
+
const files = Array.isArray(message.files) ? message.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : [];
|
|
41336
|
+
if (files.length === 0) {
|
|
41337
|
+
return "";
|
|
41338
|
+
}
|
|
41339
|
+
const fileNames = files.map((file) => file.name ?? "file").join(", ");
|
|
41340
|
+
return `[attached: ${fileNames}]`;
|
|
41341
|
+
}
|
|
41248
41342
|
function isAllowedSlackHostname(hostname3) {
|
|
41249
41343
|
const normalized = hostname3.trim().toLowerCase();
|
|
41250
41344
|
return ALLOWED_SLACK_HOST_SUFFIXES.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`));
|
|
@@ -41413,6 +41507,78 @@ async function resolveSlackInboundAttachments(params) {
|
|
|
41413
41507
|
}).catch(() => null)));
|
|
41414
41508
|
return resolved.filter((attachment) => Boolean(attachment));
|
|
41415
41509
|
}
|
|
41510
|
+
async function resolveSlackThreadStarter(params) {
|
|
41511
|
+
try {
|
|
41512
|
+
const response = await params.client.conversations.replies({
|
|
41513
|
+
channel: params.channelId,
|
|
41514
|
+
ts: params.threadTs,
|
|
41515
|
+
limit: 1,
|
|
41516
|
+
inclusive: true
|
|
41517
|
+
});
|
|
41518
|
+
const message = response.messages?.[0];
|
|
41519
|
+
if (!message) {
|
|
41520
|
+
return null;
|
|
41521
|
+
}
|
|
41522
|
+
const text = resolveSlackThreadMessageText(message);
|
|
41523
|
+
if (!text) {
|
|
41524
|
+
return null;
|
|
41525
|
+
}
|
|
41526
|
+
return {
|
|
41527
|
+
text,
|
|
41528
|
+
userId: isNonEmptyString(message.user) ? message.user : undefined,
|
|
41529
|
+
botId: isNonEmptyString(message.bot_id) ? message.bot_id : undefined,
|
|
41530
|
+
ts: isNonEmptyString(message.ts) ? message.ts : undefined
|
|
41531
|
+
};
|
|
41532
|
+
} catch {
|
|
41533
|
+
return null;
|
|
41534
|
+
}
|
|
41535
|
+
}
|
|
41536
|
+
async function resolveSlackThreadHistory(params) {
|
|
41537
|
+
const maxMessages = params.limit ?? 20;
|
|
41538
|
+
if (!Number.isFinite(maxMessages) || maxMessages <= 0) {
|
|
41539
|
+
return [];
|
|
41540
|
+
}
|
|
41541
|
+
const fetchLimit = 200;
|
|
41542
|
+
const retained = [];
|
|
41543
|
+
let cursor;
|
|
41544
|
+
try {
|
|
41545
|
+
do {
|
|
41546
|
+
const response = await params.client.conversations.replies({
|
|
41547
|
+
channel: params.channelId,
|
|
41548
|
+
ts: params.threadTs,
|
|
41549
|
+
limit: fetchLimit,
|
|
41550
|
+
inclusive: true,
|
|
41551
|
+
...cursor ? { cursor } : {}
|
|
41552
|
+
});
|
|
41553
|
+
for (const message of response.messages ?? []) {
|
|
41554
|
+
const text = resolveSlackThreadMessageText(message);
|
|
41555
|
+
if (!text) {
|
|
41556
|
+
continue;
|
|
41557
|
+
}
|
|
41558
|
+
if (params.currentMessageTs && message.ts === params.currentMessageTs) {
|
|
41559
|
+
continue;
|
|
41560
|
+
}
|
|
41561
|
+
if (message.ts === params.threadTs) {
|
|
41562
|
+
continue;
|
|
41563
|
+
}
|
|
41564
|
+
retained.push(message);
|
|
41565
|
+
if (retained.length > maxMessages) {
|
|
41566
|
+
retained.shift();
|
|
41567
|
+
}
|
|
41568
|
+
}
|
|
41569
|
+
const nextCursor = response.response_metadata?.next_cursor;
|
|
41570
|
+
cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
|
|
41571
|
+
} while (cursor);
|
|
41572
|
+
return retained.map((message) => ({
|
|
41573
|
+
text: resolveSlackThreadMessageText(message),
|
|
41574
|
+
userId: isNonEmptyString(message.user) ? message.user : undefined,
|
|
41575
|
+
botId: isNonEmptyString(message.bot_id) ? message.bot_id : undefined,
|
|
41576
|
+
ts: isNonEmptyString(message.ts) ? message.ts : undefined
|
|
41577
|
+
}));
|
|
41578
|
+
} catch {
|
|
41579
|
+
return [];
|
|
41580
|
+
}
|
|
41581
|
+
}
|
|
41416
41582
|
var MAX_SLACK_ATTACHMENTS = 8, MAX_SLACK_ATTACHMENT_BYTES, ALLOWED_SLACK_HOST_SUFFIXES;
|
|
41417
41583
|
var init_media2 = __esm(() => {
|
|
41418
41584
|
init_config();
|
|
@@ -41428,6 +41594,9 @@ var init_media2 = __esm(() => {
|
|
|
41428
41594
|
async function loadSlackBoltModule() {
|
|
41429
41595
|
return loadChannelRuntimeModule("slack", "@slack/bolt");
|
|
41430
41596
|
}
|
|
41597
|
+
async function loadSlackWebApiModule() {
|
|
41598
|
+
return loadChannelRuntimeModule("slack", "@slack/web-api");
|
|
41599
|
+
}
|
|
41431
41600
|
async function ensureSlackRuntimeInstalled() {
|
|
41432
41601
|
return ensureChannelRuntimeInstalled("slack");
|
|
41433
41602
|
}
|
|
@@ -41457,6 +41626,22 @@ function resolveSlackAppConstructor(mod) {
|
|
|
41457
41626
|
}
|
|
41458
41627
|
return App2;
|
|
41459
41628
|
}
|
|
41629
|
+
function resolveSlackWebClientModule(value) {
|
|
41630
|
+
if (!value || typeof value !== "object") {
|
|
41631
|
+
return null;
|
|
41632
|
+
}
|
|
41633
|
+
const webClient = Reflect.get(value, "WebClient");
|
|
41634
|
+
return isConstructorFunction(webClient) ? webClient : null;
|
|
41635
|
+
}
|
|
41636
|
+
function resolveSlackWebClientConstructor(mod) {
|
|
41637
|
+
const defaultExport = mod && typeof mod === "object" ? Reflect.get(mod, "default") : undefined;
|
|
41638
|
+
const nestedDefault = defaultExport && typeof defaultExport === "object" ? Reflect.get(defaultExport, "default") : undefined;
|
|
41639
|
+
const WebClient = resolveSlackWebClientModule(mod) ?? resolveSlackWebClientModule(defaultExport) ?? resolveSlackWebClientModule(nestedDefault) ?? (isConstructorFunction(defaultExport) ? defaultExport : null);
|
|
41640
|
+
if (!WebClient) {
|
|
41641
|
+
throw new Error('Installed Slack runtime did not export constructor "WebClient".');
|
|
41642
|
+
}
|
|
41643
|
+
return WebClient;
|
|
41644
|
+
}
|
|
41460
41645
|
function isNonEmptyString2(value) {
|
|
41461
41646
|
return typeof value === "string" && value.length > 0;
|
|
41462
41647
|
}
|
|
@@ -41499,7 +41684,7 @@ function resolveUploadMimeType(filePath) {
|
|
|
41499
41684
|
return;
|
|
41500
41685
|
}
|
|
41501
41686
|
}
|
|
41502
|
-
async function uploadSlackFile(
|
|
41687
|
+
async function uploadSlackFile(slackClient, msg) {
|
|
41503
41688
|
if (!msg.mediaPath) {
|
|
41504
41689
|
throw new Error("mediaPath is required for Slack file uploads.");
|
|
41505
41690
|
}
|
|
@@ -41507,7 +41692,7 @@ async function uploadSlackFile(slackApp, msg) {
|
|
|
41507
41692
|
const uploadFileName = msg.fileName ?? basename4(msg.mediaPath);
|
|
41508
41693
|
const uploadTitle = msg.title ?? uploadFileName;
|
|
41509
41694
|
const uploadMimeType = resolveUploadMimeType(uploadFileName);
|
|
41510
|
-
const uploadUrlResp = await
|
|
41695
|
+
const uploadUrlResp = await slackClient.files.getUploadURLExternal({
|
|
41511
41696
|
filename: uploadFileName,
|
|
41512
41697
|
length: buffer.length
|
|
41513
41698
|
});
|
|
@@ -41522,7 +41707,7 @@ async function uploadSlackFile(slackApp, msg) {
|
|
|
41522
41707
|
if (!uploadResp.ok) {
|
|
41523
41708
|
throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
|
|
41524
41709
|
}
|
|
41525
|
-
const completeResp = await
|
|
41710
|
+
const completeResp = await slackClient.files.completeUploadExternal({
|
|
41526
41711
|
files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
|
|
41527
41712
|
channel_id: msg.chatId,
|
|
41528
41713
|
...msg.text.trim() ? { initial_comment: msg.text } : {},
|
|
@@ -41538,6 +41723,27 @@ function resolveSlackUserDisplayName(userInfo) {
|
|
|
41538
41723
|
const profile = asRecord2(user?.profile);
|
|
41539
41724
|
return firstNonEmptyString(profile?.display_name, profile?.real_name, user?.name);
|
|
41540
41725
|
}
|
|
41726
|
+
function truncateSlackThreadLabel(text, maxLength = 80) {
|
|
41727
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
41728
|
+
if (!normalized) {
|
|
41729
|
+
return null;
|
|
41730
|
+
}
|
|
41731
|
+
if (normalized.length <= maxLength) {
|
|
41732
|
+
return normalized;
|
|
41733
|
+
}
|
|
41734
|
+
return `${normalized.slice(0, maxLength - 1).trimEnd()}…`;
|
|
41735
|
+
}
|
|
41736
|
+
function buildSlackThreadLabel(msg, starterText) {
|
|
41737
|
+
if (msg.chatType !== "channel") {
|
|
41738
|
+
return;
|
|
41739
|
+
}
|
|
41740
|
+
const roomLabel = isNonEmptyString2(msg.chatLabel) && msg.chatLabel !== msg.chatId ? ` in ${msg.chatLabel}` : "";
|
|
41741
|
+
const preview = truncateSlackThreadLabel(starterText ?? msg.text);
|
|
41742
|
+
if (preview) {
|
|
41743
|
+
return `Slack thread${roomLabel}: ${preview}`;
|
|
41744
|
+
}
|
|
41745
|
+
return roomLabel ? `Slack thread${roomLabel}` : `Slack thread ${msg.chatId}`;
|
|
41746
|
+
}
|
|
41541
41747
|
async function resolveSlackAccountDisplayName(botToken, appToken) {
|
|
41542
41748
|
const bolt = await loadSlackBoltModule();
|
|
41543
41749
|
const App2 = resolveSlackAppConstructor(bolt);
|
|
@@ -41563,11 +41769,14 @@ async function resolveSlackAccountDisplayName(botToken, appToken) {
|
|
|
41563
41769
|
}
|
|
41564
41770
|
function createSlackAdapter(config) {
|
|
41565
41771
|
let app = null;
|
|
41772
|
+
let writeClient = null;
|
|
41566
41773
|
let running = false;
|
|
41567
41774
|
let botUserId = null;
|
|
41568
41775
|
const knownThreadIdsByMessageId = new Map;
|
|
41569
41776
|
const knownUserDisplayNames = new Map;
|
|
41570
41777
|
const seenIngressMessageKeys = new Map;
|
|
41778
|
+
const lifecycleStateByMessageKey = new Map;
|
|
41779
|
+
const lifecycleOperationByMessageKey = new Map;
|
|
41571
41780
|
function buildIngressMessageKey(channelId, messageId) {
|
|
41572
41781
|
if (!isNonEmptyString2(channelId) || !isNonEmptyString2(messageId)) {
|
|
41573
41782
|
return null;
|
|
@@ -41592,6 +41801,96 @@ function createSlackAdapter(config) {
|
|
|
41592
41801
|
}
|
|
41593
41802
|
}
|
|
41594
41803
|
}
|
|
41804
|
+
function getLifecycleMessageKey(source) {
|
|
41805
|
+
if (source.channel !== "slack" || !isNonEmptyString2(source.chatId) || !isNonEmptyString2(source.messageId)) {
|
|
41806
|
+
return null;
|
|
41807
|
+
}
|
|
41808
|
+
return `${source.chatId}:${source.messageId}`;
|
|
41809
|
+
}
|
|
41810
|
+
function pruneLifecycleState(now = Date.now()) {
|
|
41811
|
+
for (const [key, entry] of lifecycleStateByMessageKey) {
|
|
41812
|
+
if (entry.updatedAt + SLACK_LIFECYCLE_STATE_TTL_MS <= now) {
|
|
41813
|
+
lifecycleStateByMessageKey.delete(key);
|
|
41814
|
+
}
|
|
41815
|
+
}
|
|
41816
|
+
if (lifecycleStateByMessageKey.size <= SLACK_LIFECYCLE_STATE_MAX) {
|
|
41817
|
+
return;
|
|
41818
|
+
}
|
|
41819
|
+
const oldestEntries = Array.from(lifecycleStateByMessageKey.entries()).sort((a, b) => a[1].updatedAt - b[1].updatedAt);
|
|
41820
|
+
const overflowCount = lifecycleStateByMessageKey.size - SLACK_LIFECYCLE_STATE_MAX;
|
|
41821
|
+
for (let index = 0;index < overflowCount; index += 1) {
|
|
41822
|
+
const entry = oldestEntries[index];
|
|
41823
|
+
if (entry) {
|
|
41824
|
+
lifecycleStateByMessageKey.delete(entry[0]);
|
|
41825
|
+
}
|
|
41826
|
+
}
|
|
41827
|
+
}
|
|
41828
|
+
async function sendLifecycleReaction(source, emoji, removeReaction = false) {
|
|
41829
|
+
if (!isNonEmptyString2(source.messageId)) {
|
|
41830
|
+
return;
|
|
41831
|
+
}
|
|
41832
|
+
await ensureApp();
|
|
41833
|
+
const slackClient = await ensureWriteClient();
|
|
41834
|
+
if (removeReaction) {
|
|
41835
|
+
await slackClient.reactions.remove({
|
|
41836
|
+
channel: source.chatId,
|
|
41837
|
+
timestamp: source.messageId,
|
|
41838
|
+
name: emoji
|
|
41839
|
+
});
|
|
41840
|
+
return;
|
|
41841
|
+
}
|
|
41842
|
+
await slackClient.reactions.add({
|
|
41843
|
+
channel: source.chatId,
|
|
41844
|
+
timestamp: source.messageId,
|
|
41845
|
+
name: emoji
|
|
41846
|
+
});
|
|
41847
|
+
}
|
|
41848
|
+
function scheduleLifecycleTransition(source, nextState) {
|
|
41849
|
+
const key = getLifecycleMessageKey(source);
|
|
41850
|
+
if (!key) {
|
|
41851
|
+
return null;
|
|
41852
|
+
}
|
|
41853
|
+
const previous = lifecycleOperationByMessageKey.get(key) ?? Promise.resolve();
|
|
41854
|
+
const operation = previous.catch(() => {}).then(async () => {
|
|
41855
|
+
pruneLifecycleState();
|
|
41856
|
+
const currentState = lifecycleStateByMessageKey.get(key)?.state;
|
|
41857
|
+
if (currentState === nextState) {
|
|
41858
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41859
|
+
state: nextState,
|
|
41860
|
+
updatedAt: Date.now()
|
|
41861
|
+
});
|
|
41862
|
+
return;
|
|
41863
|
+
}
|
|
41864
|
+
if (nextState === "queued") {
|
|
41865
|
+
if (!currentState) {
|
|
41866
|
+
await sendLifecycleReaction(source, "eyes");
|
|
41867
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41868
|
+
state: nextState,
|
|
41869
|
+
updatedAt: Date.now()
|
|
41870
|
+
});
|
|
41871
|
+
}
|
|
41872
|
+
return;
|
|
41873
|
+
}
|
|
41874
|
+
if (currentState === "queued") {
|
|
41875
|
+
try {
|
|
41876
|
+
await sendLifecycleReaction(source, "eyes", true);
|
|
41877
|
+
} catch {}
|
|
41878
|
+
}
|
|
41879
|
+
await sendLifecycleReaction(source, nextState === "completed" ? "white_check_mark" : "x");
|
|
41880
|
+
lifecycleStateByMessageKey.set(key, {
|
|
41881
|
+
state: nextState,
|
|
41882
|
+
updatedAt: Date.now()
|
|
41883
|
+
});
|
|
41884
|
+
}).catch((error) => {
|
|
41885
|
+
console.warn(`[Slack] Failed to update lifecycle reaction for ${key}:`, error instanceof Error ? error.message : error);
|
|
41886
|
+
}).finally(() => {
|
|
41887
|
+
if (lifecycleOperationByMessageKey.get(key) === operation) {
|
|
41888
|
+
lifecycleOperationByMessageKey.delete(key);
|
|
41889
|
+
}
|
|
41890
|
+
});
|
|
41891
|
+
lifecycleOperationByMessageKey.set(key, operation);
|
|
41892
|
+
return operation;
|
|
41893
|
+
}
|
|
41595
41894
|
function markIngressMessageSeen(channelId, messageId) {
|
|
41596
41895
|
const key = buildIngressMessageKey(channelId, messageId);
|
|
41597
41896
|
if (!key) {
|
|
@@ -41815,6 +42114,19 @@ function createSlackAdapter(config) {
|
|
|
41815
42114
|
app = instance;
|
|
41816
42115
|
return instance;
|
|
41817
42116
|
}
|
|
42117
|
+
async function ensureWriteClient() {
|
|
42118
|
+
if (writeClient) {
|
|
42119
|
+
return writeClient;
|
|
42120
|
+
}
|
|
42121
|
+
const webApi = await loadSlackWebApiModule();
|
|
42122
|
+
const WebClient = resolveSlackWebClientConstructor(webApi);
|
|
42123
|
+
writeClient = new WebClient(config.botToken, {
|
|
42124
|
+
retryConfig: {
|
|
42125
|
+
retries: 0
|
|
42126
|
+
}
|
|
42127
|
+
});
|
|
42128
|
+
return writeClient;
|
|
42129
|
+
}
|
|
41818
42130
|
const adapter = {
|
|
41819
42131
|
id: `slack:${config.accountId}`,
|
|
41820
42132
|
channelId: "slack",
|
|
@@ -41838,15 +42150,33 @@ function createSlackAdapter(config) {
|
|
|
41838
42150
|
await app.stop();
|
|
41839
42151
|
running = false;
|
|
41840
42152
|
app = null;
|
|
42153
|
+
writeClient = null;
|
|
41841
42154
|
botUserId = null;
|
|
41842
42155
|
seenIngressMessageKeys.clear();
|
|
42156
|
+
lifecycleStateByMessageKey.clear();
|
|
42157
|
+
lifecycleOperationByMessageKey.clear();
|
|
41843
42158
|
console.log("[Slack] App stopped");
|
|
41844
42159
|
},
|
|
41845
42160
|
isRunning() {
|
|
41846
42161
|
return running;
|
|
41847
42162
|
},
|
|
42163
|
+
async handleTurnLifecycleEvent(event) {
|
|
42164
|
+
if (!running) {
|
|
42165
|
+
return;
|
|
42166
|
+
}
|
|
42167
|
+
if (event.type === "queued") {
|
|
42168
|
+
await scheduleLifecycleTransition(event.source, "queued");
|
|
42169
|
+
return;
|
|
42170
|
+
}
|
|
42171
|
+
if (event.type === "processing") {
|
|
42172
|
+
return;
|
|
42173
|
+
}
|
|
42174
|
+
const nextState = event.outcome === "completed" ? "completed" : event.outcome === "cancelled" ? "cancelled" : "error";
|
|
42175
|
+
await Promise.all(event.sources.map((source) => scheduleLifecycleTransition(source, nextState)));
|
|
42176
|
+
},
|
|
41848
42177
|
async sendMessage(msg) {
|
|
41849
|
-
|
|
42178
|
+
await ensureApp();
|
|
42179
|
+
const slackClient = await ensureWriteClient();
|
|
41850
42180
|
if (msg.reaction) {
|
|
41851
42181
|
const targetMessageId = msg.targetMessageId ?? msg.replyToMessageId;
|
|
41852
42182
|
if (!targetMessageId) {
|
|
@@ -41857,13 +42187,13 @@ function createSlackAdapter(config) {
|
|
|
41857
42187
|
throw new Error("Slack reaction emoji cannot be empty.");
|
|
41858
42188
|
}
|
|
41859
42189
|
if (msg.removeReaction) {
|
|
41860
|
-
await
|
|
42190
|
+
await slackClient.reactions.remove({
|
|
41861
42191
|
channel: msg.chatId,
|
|
41862
42192
|
timestamp: targetMessageId,
|
|
41863
42193
|
name: emoji
|
|
41864
42194
|
});
|
|
41865
42195
|
} else {
|
|
41866
|
-
await
|
|
42196
|
+
await slackClient.reactions.add({
|
|
41867
42197
|
channel: msg.chatId,
|
|
41868
42198
|
timestamp: targetMessageId,
|
|
41869
42199
|
name: emoji
|
|
@@ -41872,9 +42202,9 @@ function createSlackAdapter(config) {
|
|
|
41872
42202
|
return { messageId: targetMessageId };
|
|
41873
42203
|
}
|
|
41874
42204
|
if (msg.mediaPath) {
|
|
41875
|
-
return uploadSlackFile(
|
|
42205
|
+
return uploadSlackFile(slackClient, msg);
|
|
41876
42206
|
}
|
|
41877
|
-
const response = await
|
|
42207
|
+
const response = await slackClient.chat.postMessage({
|
|
41878
42208
|
channel: msg.chatId,
|
|
41879
42209
|
text: msg.text,
|
|
41880
42210
|
...msg.threadId ?? msg.replyToMessageId ? { thread_ts: msg.threadId ?? msg.replyToMessageId } : {}
|
|
@@ -41883,22 +42213,88 @@ function createSlackAdapter(config) {
|
|
|
41883
42213
|
return { messageId: response.ts ?? "" };
|
|
41884
42214
|
},
|
|
41885
42215
|
async sendDirectReply(chatId, text, options) {
|
|
41886
|
-
|
|
41887
|
-
const
|
|
42216
|
+
await ensureApp();
|
|
42217
|
+
const slackClient = await ensureWriteClient();
|
|
42218
|
+
const response = await slackClient.chat.postMessage({
|
|
41888
42219
|
channel: chatId,
|
|
41889
42220
|
text,
|
|
41890
42221
|
...options?.replyToMessageId ? { thread_ts: options.replyToMessageId } : {}
|
|
41891
42222
|
});
|
|
41892
42223
|
rememberMessageThread(response.ts, options?.replyToMessageId ?? response.ts ?? null);
|
|
41893
42224
|
},
|
|
42225
|
+
async prepareInboundMessage(msg, options) {
|
|
42226
|
+
if (!options?.isFirstRouteTurn || msg.channel !== "slack" || msg.chatType !== "channel" || !isNonEmptyString2(msg.threadId) || !isNonEmptyString2(msg.messageId) || msg.threadId === msg.messageId) {
|
|
42227
|
+
return msg;
|
|
42228
|
+
}
|
|
42229
|
+
const slackApp = await ensureApp();
|
|
42230
|
+
const starter = await resolveSlackThreadStarter({
|
|
42231
|
+
channelId: msg.chatId,
|
|
42232
|
+
threadTs: msg.threadId,
|
|
42233
|
+
client: slackApp.client
|
|
42234
|
+
});
|
|
42235
|
+
const history = await resolveSlackThreadHistory({
|
|
42236
|
+
channelId: msg.chatId,
|
|
42237
|
+
threadTs: msg.threadId,
|
|
42238
|
+
client: slackApp.client,
|
|
42239
|
+
currentMessageTs: msg.messageId,
|
|
42240
|
+
limit: INITIAL_SLACK_THREAD_HISTORY_LIMIT
|
|
42241
|
+
});
|
|
42242
|
+
if (!starter && history.length === 0) {
|
|
42243
|
+
return msg;
|
|
42244
|
+
}
|
|
42245
|
+
const uniqueUserIds = new Set;
|
|
42246
|
+
if (isNonEmptyString2(starter?.userId)) {
|
|
42247
|
+
uniqueUserIds.add(starter.userId);
|
|
42248
|
+
}
|
|
42249
|
+
for (const entry of history) {
|
|
42250
|
+
if (isNonEmptyString2(entry.userId)) {
|
|
42251
|
+
uniqueUserIds.add(entry.userId);
|
|
42252
|
+
}
|
|
42253
|
+
}
|
|
42254
|
+
await Promise.all(Array.from(uniqueUserIds).map(async (userId) => {
|
|
42255
|
+
await resolveUserName(slackApp, userId);
|
|
42256
|
+
}));
|
|
42257
|
+
const resolveThreadSenderName = (userId, botId) => {
|
|
42258
|
+
if (isNonEmptyString2(userId)) {
|
|
42259
|
+
return knownUserDisplayNames.get(userId) ?? userId;
|
|
42260
|
+
}
|
|
42261
|
+
if (isNonEmptyString2(botId)) {
|
|
42262
|
+
return `Bot (${botId})`;
|
|
42263
|
+
}
|
|
42264
|
+
return;
|
|
42265
|
+
};
|
|
42266
|
+
return {
|
|
42267
|
+
...msg,
|
|
42268
|
+
threadContext: {
|
|
42269
|
+
label: buildSlackThreadLabel(msg, starter?.text),
|
|
42270
|
+
...starter ? {
|
|
42271
|
+
starter: {
|
|
42272
|
+
messageId: starter.ts,
|
|
42273
|
+
senderId: starter.userId ?? starter.botId,
|
|
42274
|
+
senderName: resolveThreadSenderName(starter.userId, starter.botId),
|
|
42275
|
+
text: starter.text
|
|
42276
|
+
}
|
|
42277
|
+
} : {},
|
|
42278
|
+
...history.length > 0 ? {
|
|
42279
|
+
history: history.map((entry) => ({
|
|
42280
|
+
messageId: entry.ts,
|
|
42281
|
+
senderId: entry.userId ?? entry.botId,
|
|
42282
|
+
senderName: resolveThreadSenderName(entry.userId, entry.botId),
|
|
42283
|
+
text: entry.text
|
|
42284
|
+
}))
|
|
42285
|
+
} : {}
|
|
42286
|
+
}
|
|
42287
|
+
};
|
|
42288
|
+
},
|
|
41894
42289
|
onMessage: undefined
|
|
41895
42290
|
};
|
|
41896
42291
|
return adapter;
|
|
41897
42292
|
}
|
|
41898
|
-
var SLACK_INGRESS_DEDUPE_TTL_MS = 60000, SLACK_INGRESS_DEDUPE_MAX = 2000;
|
|
42293
|
+
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
42294
|
var init_adapter2 = __esm(() => {
|
|
41900
42295
|
init_media2();
|
|
41901
42296
|
init_runtime2();
|
|
42297
|
+
SLACK_LIFECYCLE_STATE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
41902
42298
|
});
|
|
41903
42299
|
|
|
41904
42300
|
// src/channels/slack/messageActions.ts
|
|
@@ -42081,8 +42477,8 @@ var init_plugin2 = __esm(() => {
|
|
|
42081
42477
|
metadata: {
|
|
42082
42478
|
id: "slack",
|
|
42083
42479
|
displayName: "Slack",
|
|
42084
|
-
runtimePackages: ["@slack/bolt@4.7.0"],
|
|
42085
|
-
runtimeModules: ["@slack/bolt"]
|
|
42480
|
+
runtimePackages: ["@slack/bolt@4.7.0", "@slack/web-api@7.15.0"],
|
|
42481
|
+
runtimeModules: ["@slack/bolt", "@slack/web-api"]
|
|
42086
42482
|
},
|
|
42087
42483
|
createAdapter(account) {
|
|
42088
42484
|
return createSlackAdapter(account);
|
|
@@ -42138,8 +42534,8 @@ var init_pluginRegistry = __esm(() => {
|
|
|
42138
42534
|
metadata: {
|
|
42139
42535
|
id: "slack",
|
|
42140
42536
|
displayName: "Slack",
|
|
42141
|
-
runtimePackages: ["@slack/bolt@4.7.0"],
|
|
42142
|
-
runtimeModules: ["@slack/bolt"]
|
|
42537
|
+
runtimePackages: ["@slack/bolt@4.7.0", "@slack/web-api@7.15.0"],
|
|
42538
|
+
runtimeModules: ["@slack/bolt", "@slack/web-api"]
|
|
42143
42539
|
},
|
|
42144
42540
|
load: async () => {
|
|
42145
42541
|
const { slackChannelPlugin: slackChannelPlugin2 } = await Promise.resolve().then(() => (init_plugin2(), exports_plugin2));
|
|
@@ -42724,6 +43120,47 @@ function buildReactionXml(msg) {
|
|
|
42724
43120
|
}
|
|
42725
43121
|
return `<reaction ${attrs.join(" ")} />`;
|
|
42726
43122
|
}
|
|
43123
|
+
function buildThreadContextEntryXml(tagName, entry) {
|
|
43124
|
+
const attrs = [];
|
|
43125
|
+
if (entry.senderId) {
|
|
43126
|
+
attrs.push(`sender_id="${escapeXmlAttribute(entry.senderId)}"`);
|
|
43127
|
+
}
|
|
43128
|
+
if (entry.senderName) {
|
|
43129
|
+
attrs.push(`sender_name="${escapeXmlAttribute(entry.senderName)}"`);
|
|
43130
|
+
}
|
|
43131
|
+
if (entry.messageId) {
|
|
43132
|
+
attrs.push(`message_id="${escapeXmlAttribute(entry.messageId)}"`);
|
|
43133
|
+
}
|
|
43134
|
+
const attrString = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
43135
|
+
return `<${tagName}${attrString}>
|
|
43136
|
+
${escapeXmlText(entry.text)}
|
|
43137
|
+
</${tagName}>`;
|
|
43138
|
+
}
|
|
43139
|
+
function buildThreadContextXml(msg) {
|
|
43140
|
+
const threadContext = msg.threadContext;
|
|
43141
|
+
if (!threadContext) {
|
|
43142
|
+
return null;
|
|
43143
|
+
}
|
|
43144
|
+
const parts = [];
|
|
43145
|
+
if (threadContext.starter) {
|
|
43146
|
+
parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter));
|
|
43147
|
+
}
|
|
43148
|
+
const historyEntries = threadContext.history ?? [];
|
|
43149
|
+
if (historyEntries.length > 0) {
|
|
43150
|
+
parts.push([
|
|
43151
|
+
"<thread-history>",
|
|
43152
|
+
...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry)),
|
|
43153
|
+
"</thread-history>"
|
|
43154
|
+
].join(`
|
|
43155
|
+
`));
|
|
43156
|
+
}
|
|
43157
|
+
if (parts.length === 0) {
|
|
43158
|
+
return null;
|
|
43159
|
+
}
|
|
43160
|
+
const attrs = threadContext.label ? ` label="${escapeXmlAttribute(threadContext.label)}"` : "";
|
|
43161
|
+
return [`<thread-context${attrs}>`, ...parts, "</thread-context>"].join(`
|
|
43162
|
+
`);
|
|
43163
|
+
}
|
|
42727
43164
|
function buildChannelNotificationXml(msg) {
|
|
42728
43165
|
const attrs = [
|
|
42729
43166
|
`source="${escapeXmlAttribute(msg.channel)}"`,
|
|
@@ -42742,8 +43179,9 @@ function buildChannelNotificationXml(msg) {
|
|
|
42742
43179
|
const attrString = attrs.join(" ");
|
|
42743
43180
|
const escapedText = msg.text ? escapeXmlText(msg.text) : "";
|
|
42744
43181
|
const reactionXml = buildReactionXml(msg);
|
|
43182
|
+
const threadContextXml = buildThreadContextXml(msg);
|
|
42745
43183
|
const attachmentXml = (msg.attachments ?? []).map(buildAttachmentXml);
|
|
42746
|
-
const body = [reactionXml, ...attachmentXml, escapedText].filter(Boolean).join(`
|
|
43184
|
+
const body = [threadContextXml, reactionXml, ...attachmentXml, escapedText].filter(Boolean).join(`
|
|
42747
43185
|
`);
|
|
42748
43186
|
return `<channel-notification ${attrString}>
|
|
42749
43187
|
${body}
|
|
@@ -42828,6 +43266,18 @@ function buildSlackConversationSummary(msg) {
|
|
|
42828
43266
|
}
|
|
42829
43267
|
return `[Slack] Thread${channelLabel || ` ${msg.chatId}`}`;
|
|
42830
43268
|
}
|
|
43269
|
+
function buildChannelTurnSource(route, msg) {
|
|
43270
|
+
return {
|
|
43271
|
+
channel: msg.channel,
|
|
43272
|
+
accountId: msg.accountId,
|
|
43273
|
+
chatId: msg.chatId,
|
|
43274
|
+
chatType: msg.chatType,
|
|
43275
|
+
messageId: msg.messageId,
|
|
43276
|
+
threadId: msg.threadId,
|
|
43277
|
+
agentId: route.agentId,
|
|
43278
|
+
conversationId: route.conversationId
|
|
43279
|
+
};
|
|
43280
|
+
}
|
|
42831
43281
|
function getChannelRegistry() {
|
|
42832
43282
|
return instance;
|
|
42833
43283
|
}
|
|
@@ -42867,6 +43317,51 @@ class ChannelRegistry {
|
|
|
42867
43317
|
getActiveChannelIds() {
|
|
42868
43318
|
return Array.from(this.adapters.values()).filter((adapter) => adapter.isRunning()).map((adapter) => adapter.channelId ?? adapter.id);
|
|
42869
43319
|
}
|
|
43320
|
+
async dispatchTurnLifecycleEvent(event) {
|
|
43321
|
+
const groups = new Map;
|
|
43322
|
+
const sources = event.type === "queued" ? [event.source] : event.sources;
|
|
43323
|
+
for (const source of sources) {
|
|
43324
|
+
const adapter = this.getAdapter(source.channel, source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID);
|
|
43325
|
+
if (!adapter?.handleTurnLifecycleEvent) {
|
|
43326
|
+
continue;
|
|
43327
|
+
}
|
|
43328
|
+
const groupKey = this.getAdapterKey(source.channel, source.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID);
|
|
43329
|
+
const existing = groups.get(groupKey);
|
|
43330
|
+
if (existing) {
|
|
43331
|
+
existing.sources.push(source);
|
|
43332
|
+
continue;
|
|
43333
|
+
}
|
|
43334
|
+
groups.set(groupKey, {
|
|
43335
|
+
adapter,
|
|
43336
|
+
sources: [source]
|
|
43337
|
+
});
|
|
43338
|
+
}
|
|
43339
|
+
for (const { adapter, sources: groupedSources } of groups.values()) {
|
|
43340
|
+
const handleTurnLifecycleEvent = adapter.handleTurnLifecycleEvent;
|
|
43341
|
+
if (!handleTurnLifecycleEvent) {
|
|
43342
|
+
continue;
|
|
43343
|
+
}
|
|
43344
|
+
try {
|
|
43345
|
+
if (event.type === "queued") {
|
|
43346
|
+
const [firstSource] = groupedSources;
|
|
43347
|
+
if (!firstSource) {
|
|
43348
|
+
continue;
|
|
43349
|
+
}
|
|
43350
|
+
await handleTurnLifecycleEvent({
|
|
43351
|
+
type: "queued",
|
|
43352
|
+
source: firstSource
|
|
43353
|
+
});
|
|
43354
|
+
continue;
|
|
43355
|
+
}
|
|
43356
|
+
await handleTurnLifecycleEvent({
|
|
43357
|
+
...event,
|
|
43358
|
+
sources: groupedSources
|
|
43359
|
+
});
|
|
43360
|
+
} catch (error) {
|
|
43361
|
+
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);
|
|
43362
|
+
}
|
|
43363
|
+
}
|
|
43364
|
+
}
|
|
42870
43365
|
setMessageHandler(handler) {
|
|
42871
43366
|
this.messageHandler = handler;
|
|
42872
43367
|
}
|
|
@@ -42985,11 +43480,20 @@ class ChannelRegistry {
|
|
|
42985
43480
|
if (!config)
|
|
42986
43481
|
return;
|
|
42987
43482
|
if (msg.channel === "slack" && config.channel === "slack") {
|
|
42988
|
-
const
|
|
42989
|
-
if (!
|
|
43483
|
+
const slackResult = await this.ensureSlackRoute(adapter, msg, config);
|
|
43484
|
+
if (!slackResult) {
|
|
42990
43485
|
return;
|
|
42991
43486
|
}
|
|
42992
|
-
|
|
43487
|
+
const preparedMessage = adapter.prepareInboundMessage ? await adapter.prepareInboundMessage(msg, {
|
|
43488
|
+
isFirstRouteTurn: slackResult.isFirstRouteTurn
|
|
43489
|
+
}) : msg;
|
|
43490
|
+
this.deliverOrBuffer({
|
|
43491
|
+
route: slackResult.route,
|
|
43492
|
+
content: formatChannelNotification(preparedMessage),
|
|
43493
|
+
turnSources: [
|
|
43494
|
+
buildChannelTurnSource(slackResult.route, preparedMessage)
|
|
43495
|
+
]
|
|
43496
|
+
});
|
|
42993
43497
|
return;
|
|
42994
43498
|
}
|
|
42995
43499
|
if (config.dmPolicy === "allowlist") {
|
|
@@ -43021,7 +43525,11 @@ class ChannelRegistry {
|
|
|
43021
43525
|
return;
|
|
43022
43526
|
}
|
|
43023
43527
|
const content = formatChannelNotification(msg);
|
|
43024
|
-
this.deliverOrBuffer(
|
|
43528
|
+
this.deliverOrBuffer({
|
|
43529
|
+
route,
|
|
43530
|
+
content,
|
|
43531
|
+
turnSources: [buildChannelTurnSource(route, msg)]
|
|
43532
|
+
});
|
|
43025
43533
|
}
|
|
43026
43534
|
async createConversationForAgent(agentId, summary) {
|
|
43027
43535
|
const client = await getClient();
|
|
@@ -43071,7 +43579,10 @@ class ChannelRegistry {
|
|
|
43071
43579
|
route = getRoute(msg.channel, msg.chatId, accountId, routeThreadId);
|
|
43072
43580
|
}
|
|
43073
43581
|
if (route) {
|
|
43074
|
-
return
|
|
43582
|
+
return {
|
|
43583
|
+
route,
|
|
43584
|
+
isFirstRouteTurn: false
|
|
43585
|
+
};
|
|
43075
43586
|
}
|
|
43076
43587
|
if (msg.chatType === "channel" && !msg.isMention) {
|
|
43077
43588
|
return null;
|
|
@@ -43092,14 +43603,17 @@ class ChannelRegistry {
|
|
|
43092
43603
|
type: "targets_updated",
|
|
43093
43604
|
channelId: msg.channel
|
|
43094
43605
|
});
|
|
43095
|
-
return
|
|
43606
|
+
return {
|
|
43607
|
+
route: await this.createSlackRoute(config, msg),
|
|
43608
|
+
isFirstRouteTurn: true
|
|
43609
|
+
};
|
|
43096
43610
|
}
|
|
43097
|
-
deliverOrBuffer(
|
|
43611
|
+
deliverOrBuffer(delivery) {
|
|
43098
43612
|
if (this.isReady()) {
|
|
43099
|
-
this.messageHandler?.(
|
|
43613
|
+
this.messageHandler?.(delivery);
|
|
43100
43614
|
return;
|
|
43101
43615
|
}
|
|
43102
|
-
this.buffer.push(
|
|
43616
|
+
this.buffer.push(delivery);
|
|
43103
43617
|
}
|
|
43104
43618
|
flushBuffer() {
|
|
43105
43619
|
if (!this.messageHandler)
|
|
@@ -43107,7 +43621,7 @@ class ChannelRegistry {
|
|
|
43107
43621
|
while (this.buffer.length > 0) {
|
|
43108
43622
|
const item = this.buffer.shift();
|
|
43109
43623
|
if (item) {
|
|
43110
|
-
this.messageHandler(item
|
|
43624
|
+
this.messageHandler(item);
|
|
43111
43625
|
}
|
|
43112
43626
|
}
|
|
43113
43627
|
}
|
|
@@ -45617,10 +46131,12 @@ var exports_memoryFilesystem = {};
|
|
|
45617
46131
|
__export(exports_memoryFilesystem, {
|
|
45618
46132
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree,
|
|
45619
46133
|
labelFromRelativePath: () => labelFromRelativePath,
|
|
46134
|
+
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer,
|
|
45620
46135
|
isLettaCloud: () => isLettaCloud,
|
|
45621
46136
|
getMemorySystemDir: () => getMemorySystemDir,
|
|
45622
46137
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot,
|
|
45623
46138
|
ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs,
|
|
46139
|
+
ensureLocalMemfsCheckout: () => ensureLocalMemfsCheckout,
|
|
45624
46140
|
enableMemfsIfCloud: () => enableMemfsIfCloud,
|
|
45625
46141
|
applyMemfsFlags: () => applyMemfsFlags,
|
|
45626
46142
|
MEMORY_TREE_MAX_LINES: () => MEMORY_TREE_MAX_LINES,
|
|
@@ -45650,6 +46166,23 @@ function ensureMemoryFilesystemDirs(agentId, homeDir = homedir10()) {
|
|
|
45650
46166
|
mkdirSync13(systemDir, { recursive: true });
|
|
45651
46167
|
}
|
|
45652
46168
|
}
|
|
46169
|
+
async function isMemfsEnabledOnServer(agentId) {
|
|
46170
|
+
const { getClient: getClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
46171
|
+
const client = await getClient3();
|
|
46172
|
+
const agent = await client.agents.retrieve(agentId);
|
|
46173
|
+
const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
46174
|
+
const enabled = agent.tags?.includes(GIT_MEMORY_ENABLED_TAG2) ?? false;
|
|
46175
|
+
const { settingsManager: settingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
46176
|
+
settingsManager2.setMemfsEnabled(agentId, enabled);
|
|
46177
|
+
return enabled;
|
|
46178
|
+
}
|
|
46179
|
+
async function ensureLocalMemfsCheckout(agentId) {
|
|
46180
|
+
const { isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
46181
|
+
if (isGitRepo2(agentId)) {
|
|
46182
|
+
return;
|
|
46183
|
+
}
|
|
46184
|
+
await cloneMemoryRepo2(agentId);
|
|
46185
|
+
}
|
|
45653
46186
|
function labelFromRelativePath(relativePath) {
|
|
45654
46187
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
45655
46188
|
return normalized.replace(/\.md$/, "");
|
|
@@ -49895,6 +50428,19 @@ function resolveLettaInvocation(env3 = process.env, argv = process.argv, execPat
|
|
|
49895
50428
|
}
|
|
49896
50429
|
const scriptPath = argv[1] || "";
|
|
49897
50430
|
if (scriptPath && isDevLettaEntryScript(scriptPath)) {
|
|
50431
|
+
const runtimeName = path4.basename(execPath).toLowerCase();
|
|
50432
|
+
if (runtimeName.includes("bun")) {
|
|
50433
|
+
return {
|
|
50434
|
+
command: execPath,
|
|
50435
|
+
args: [
|
|
50436
|
+
"--loader:.md=text",
|
|
50437
|
+
"--loader:.mdx=text",
|
|
50438
|
+
"--loader:.txt=text",
|
|
50439
|
+
"run",
|
|
50440
|
+
scriptPath
|
|
50441
|
+
]
|
|
50442
|
+
};
|
|
50443
|
+
}
|
|
49898
50444
|
return { command: execPath, args: [scriptPath] };
|
|
49899
50445
|
}
|
|
49900
50446
|
return null;
|
|
@@ -85382,7 +85928,7 @@ __export(exports_diff, {
|
|
|
85382
85928
|
ADV_DIFF_IGNORE_WHITESPACE: () => ADV_DIFF_IGNORE_WHITESPACE,
|
|
85383
85929
|
ADV_DIFF_CONTEXT_LINES: () => ADV_DIFF_CONTEXT_LINES
|
|
85384
85930
|
});
|
|
85385
|
-
import { basename as
|
|
85931
|
+
import { basename as basename8 } from "node:path";
|
|
85386
85932
|
function readFileOrNull(p) {
|
|
85387
85933
|
try {
|
|
85388
85934
|
return __require("node:fs").readFileSync(p, "utf-8");
|
|
@@ -85406,7 +85952,7 @@ function applyAllOccurrences(content, oldStr, newStr) {
|
|
|
85406
85952
|
return { ok: true, out: content.split(oldStr).join(newStr) };
|
|
85407
85953
|
}
|
|
85408
85954
|
function computeAdvancedDiff(input, opts) {
|
|
85409
|
-
const fileName =
|
|
85955
|
+
const fileName = basename8(input.filePath || "");
|
|
85410
85956
|
const fileContent = opts?.oldStrOverride !== undefined ? opts.oldStrOverride : readFileOrNull(input.filePath);
|
|
85411
85957
|
if (fileContent === null && input.kind !== "write") {
|
|
85412
85958
|
return { mode: "fallback", reason: "File not readable" };
|
|
@@ -85472,7 +86018,7 @@ function computeAdvancedDiff(input, opts) {
|
|
|
85472
86018
|
return { mode: "advanced", fileName, oldStr, newStr, hunks };
|
|
85473
86019
|
}
|
|
85474
86020
|
function parsePatchToAdvancedDiff(patchLines, filePath) {
|
|
85475
|
-
const fileName =
|
|
86021
|
+
const fileName = basename8(filePath);
|
|
85476
86022
|
const hunks = [];
|
|
85477
86023
|
let currentHunk = null;
|
|
85478
86024
|
let oldLine = 1;
|
|
@@ -85753,8 +86299,8 @@ function isFormatterSegment(tokens) {
|
|
|
85753
86299
|
}
|
|
85754
86300
|
}
|
|
85755
86301
|
function isShellExecutor2(token) {
|
|
85756
|
-
const
|
|
85757
|
-
return ["bash", "sh", "zsh", "dash", "ksh"].includes(
|
|
86302
|
+
const basename9 = token.split("/").pop() ?? token;
|
|
86303
|
+
return ["bash", "sh", "zsh", "dash", "ksh"].includes(basename9.toLowerCase());
|
|
85758
86304
|
}
|
|
85759
86305
|
function normalizeRawCommand(command) {
|
|
85760
86306
|
if (Array.isArray(command)) {
|
|
@@ -86463,7 +87009,7 @@ var init_formatArgsDisplay = __esm(async () => {
|
|
|
86463
87009
|
});
|
|
86464
87010
|
|
|
86465
87011
|
// src/helpers/diffPreview.ts
|
|
86466
|
-
import path21, { basename as
|
|
87012
|
+
import path21, { basename as basename9 } from "node:path";
|
|
86467
87013
|
function parseHunkLinePrefix(raw) {
|
|
86468
87014
|
if (raw.length === 0) {
|
|
86469
87015
|
return { type: "context", content: "" };
|
|
@@ -86569,7 +87115,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86569
87115
|
filePath: resolvedFilePath,
|
|
86570
87116
|
content: toolArgs.content || ""
|
|
86571
87117
|
});
|
|
86572
|
-
previews.push(toDiffPreview(result,
|
|
87118
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86573
87119
|
}
|
|
86574
87120
|
} else if (isFileEditTool2(toolName)) {
|
|
86575
87121
|
const filePath = toolArgs.file_path;
|
|
@@ -86581,7 +87127,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86581
87127
|
filePath: resolvedFilePath,
|
|
86582
87128
|
edits: toolArgs.edits
|
|
86583
87129
|
});
|
|
86584
|
-
previews.push(toDiffPreview(result,
|
|
87130
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86585
87131
|
} else {
|
|
86586
87132
|
const result = computeAdvancedDiff2({
|
|
86587
87133
|
kind: "edit",
|
|
@@ -86590,7 +87136,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86590
87136
|
newString: toolArgs.new_string || "",
|
|
86591
87137
|
replaceAll: toolArgs.replace_all
|
|
86592
87138
|
});
|
|
86593
|
-
previews.push(toDiffPreview(result,
|
|
87139
|
+
previews.push(toDiffPreview(result, basename9(filePath)));
|
|
86594
87140
|
}
|
|
86595
87141
|
}
|
|
86596
87142
|
} else if (isPatchTool2(toolName) && toolArgs.input) {
|
|
@@ -86599,7 +87145,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86599
87145
|
if (op.kind === "add" || op.kind === "update") {
|
|
86600
87146
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
86601
87147
|
if (result) {
|
|
86602
|
-
previews.push(toDiffPreview(result,
|
|
87148
|
+
previews.push(toDiffPreview(result, basename9(op.path)));
|
|
86603
87149
|
}
|
|
86604
87150
|
}
|
|
86605
87151
|
}
|
|
@@ -86609,7 +87155,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
86609
87155
|
if (op.kind === "add" || op.kind === "update") {
|
|
86610
87156
|
const result = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
86611
87157
|
if (result) {
|
|
86612
|
-
previews.push(toDiffPreview(result,
|
|
87158
|
+
previews.push(toDiffPreview(result, basename9(op.path)));
|
|
86613
87159
|
}
|
|
86614
87160
|
}
|
|
86615
87161
|
}
|
|
@@ -89703,6 +90249,65 @@ function mergeDequeuedBatchContent(items) {
|
|
|
89703
90249
|
normalizeUserContent: (content) => content
|
|
89704
90250
|
});
|
|
89705
90251
|
}
|
|
90252
|
+
function getChannelTurnSourceKey(source) {
|
|
90253
|
+
return [
|
|
90254
|
+
source.channel,
|
|
90255
|
+
source.accountId ?? "",
|
|
90256
|
+
source.chatId,
|
|
90257
|
+
source.messageId ?? "",
|
|
90258
|
+
source.threadId ?? "",
|
|
90259
|
+
source.agentId,
|
|
90260
|
+
source.conversationId
|
|
90261
|
+
].join(":");
|
|
90262
|
+
}
|
|
90263
|
+
function collectBatchChannelTurnSources(runtime, batch) {
|
|
90264
|
+
const seen = new Set;
|
|
90265
|
+
const sources = [];
|
|
90266
|
+
for (const item of batch.items) {
|
|
90267
|
+
const template = runtime.queuedMessagesByItemId.get(item.id);
|
|
90268
|
+
for (const source of template?.channelTurnSources ?? []) {
|
|
90269
|
+
const key = getChannelTurnSourceKey(source);
|
|
90270
|
+
if (seen.has(key)) {
|
|
90271
|
+
continue;
|
|
90272
|
+
}
|
|
90273
|
+
seen.add(key);
|
|
90274
|
+
sources.push(source);
|
|
90275
|
+
}
|
|
90276
|
+
}
|
|
90277
|
+
return sources.length > 0 ? sources : undefined;
|
|
90278
|
+
}
|
|
90279
|
+
async function dispatchChannelTurnLifecycleEvent(event) {
|
|
90280
|
+
if (event.sources.length === 0) {
|
|
90281
|
+
return;
|
|
90282
|
+
}
|
|
90283
|
+
const registry = getChannelRegistry();
|
|
90284
|
+
if (!registry) {
|
|
90285
|
+
return;
|
|
90286
|
+
}
|
|
90287
|
+
if (event.type === "processing") {
|
|
90288
|
+
await registry.dispatchTurnLifecycleEvent(event);
|
|
90289
|
+
return;
|
|
90290
|
+
}
|
|
90291
|
+
await registry.dispatchTurnLifecycleEvent({
|
|
90292
|
+
type: "finished",
|
|
90293
|
+
batchId: event.batchId,
|
|
90294
|
+
sources: event.sources,
|
|
90295
|
+
outcome: event.outcome,
|
|
90296
|
+
...event.error ? { error: event.error } : {}
|
|
90297
|
+
});
|
|
90298
|
+
}
|
|
90299
|
+
function mapTurnLifecycleOutcome(lastStopReason, didThrow) {
|
|
90300
|
+
if (didThrow) {
|
|
90301
|
+
return "error";
|
|
90302
|
+
}
|
|
90303
|
+
if (lastStopReason === "cancelled") {
|
|
90304
|
+
return "cancelled";
|
|
90305
|
+
}
|
|
90306
|
+
if (lastStopReason && lastStopReason !== "end_turn") {
|
|
90307
|
+
return "error";
|
|
90308
|
+
}
|
|
90309
|
+
return "completed";
|
|
90310
|
+
}
|
|
89706
90311
|
function isBase64ImageContentPart(part) {
|
|
89707
90312
|
if (!part || typeof part !== "object") {
|
|
89708
90313
|
return false;
|
|
@@ -89762,6 +90367,7 @@ function getPrimaryQueueMessageItem(items) {
|
|
|
89762
90367
|
return null;
|
|
89763
90368
|
}
|
|
89764
90369
|
function buildQueuedTurnMessage(runtime, batch) {
|
|
90370
|
+
const channelTurnSources = collectBatchChannelTurnSources(runtime, batch);
|
|
89765
90371
|
const primaryItem = getPrimaryQueueMessageItem(batch.items);
|
|
89766
90372
|
if (!primaryItem) {
|
|
89767
90373
|
for (const item of batch.items) {
|
|
@@ -89776,6 +90382,7 @@ function buildQueuedTurnMessage(runtime, batch) {
|
|
|
89776
90382
|
type: "message",
|
|
89777
90383
|
agentId: scopeItem?.agentId ?? runtime.agentId ?? undefined,
|
|
89778
90384
|
conversationId: scopeItem?.conversationId ?? runtime.conversationId,
|
|
90385
|
+
...channelTurnSources ? { channelTurnSources } : {},
|
|
89779
90386
|
messages: [
|
|
89780
90387
|
{
|
|
89781
90388
|
role: "user",
|
|
@@ -89808,6 +90415,7 @@ function buildQueuedTurnMessage(runtime, batch) {
|
|
|
89808
90415
|
messages[firstMessageIndex] = mergedFirstMessage;
|
|
89809
90416
|
return {
|
|
89810
90417
|
...template,
|
|
90418
|
+
...channelTurnSources ? { channelTurnSources } : {},
|
|
89811
90419
|
messages
|
|
89812
90420
|
};
|
|
89813
90421
|
}
|
|
@@ -89888,13 +90496,39 @@ async function drainQueuedMessages(runtime, socket, opts, processQueuedTurn) {
|
|
|
89888
90496
|
return;
|
|
89889
90497
|
}
|
|
89890
90498
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
90499
|
+
const channelTurnSources = queuedTurn.channelTurnSources ?? [];
|
|
89891
90500
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
89892
90501
|
const preTurnStatus = getListenerStatus(runtime.listener) === "processing" ? "processing" : "receiving";
|
|
89893
90502
|
if (opts.connectionId && runtime.listener.lastEmittedStatus !== preTurnStatus) {
|
|
89894
90503
|
runtime.listener.lastEmittedStatus = preTurnStatus;
|
|
89895
90504
|
opts.onStatusChange?.(preTurnStatus, opts.connectionId);
|
|
89896
90505
|
}
|
|
89897
|
-
|
|
90506
|
+
if (channelTurnSources.length > 0) {
|
|
90507
|
+
await dispatchChannelTurnLifecycleEvent({
|
|
90508
|
+
type: "processing",
|
|
90509
|
+
batchId: dequeuedBatch.batchId,
|
|
90510
|
+
sources: channelTurnSources
|
|
90511
|
+
});
|
|
90512
|
+
}
|
|
90513
|
+
let turnError;
|
|
90514
|
+
let didThrow = false;
|
|
90515
|
+
try {
|
|
90516
|
+
await processQueuedTurn(queuedTurn, dequeuedBatch);
|
|
90517
|
+
} catch (error) {
|
|
90518
|
+
didThrow = true;
|
|
90519
|
+
turnError = error instanceof Error ? error.message : String(error);
|
|
90520
|
+
throw error;
|
|
90521
|
+
} finally {
|
|
90522
|
+
if (channelTurnSources.length > 0) {
|
|
90523
|
+
await dispatchChannelTurnLifecycleEvent({
|
|
90524
|
+
type: "finished",
|
|
90525
|
+
batchId: dequeuedBatch.batchId,
|
|
90526
|
+
sources: channelTurnSources,
|
|
90527
|
+
outcome: mapTurnLifecycleOutcome(runtime.lastStopReason, didThrow),
|
|
90528
|
+
...turnError ? { error: turnError } : {}
|
|
90529
|
+
});
|
|
90530
|
+
}
|
|
90531
|
+
}
|
|
89898
90532
|
emitListenerStatus(runtime.listener, opts.onStatusChange, opts.connectionId);
|
|
89899
90533
|
evictConversationRuntimeIfIdle(runtime);
|
|
89900
90534
|
}
|
|
@@ -89927,6 +90561,7 @@ function scheduleQueuePump(runtime, socket, opts, processQueuedTurn) {
|
|
|
89927
90561
|
});
|
|
89928
90562
|
}
|
|
89929
90563
|
var init_queue = __esm(async () => {
|
|
90564
|
+
init_registry();
|
|
89930
90565
|
init_queueRuntime();
|
|
89931
90566
|
init_errorReporting();
|
|
89932
90567
|
init_runtime3();
|
|
@@ -91033,7 +91668,7 @@ function scanMemoryFilesystem(memoryRoot) {
|
|
|
91033
91668
|
} catch {
|
|
91034
91669
|
return;
|
|
91035
91670
|
}
|
|
91036
|
-
const relativePath = relative12(memoryRoot, fullPath);
|
|
91671
|
+
const relativePath = relative12(memoryRoot, fullPath).replace(/\\/g, "/");
|
|
91037
91672
|
const isLast = index === sorted.length - 1;
|
|
91038
91673
|
nodes.push({
|
|
91039
91674
|
name: isDir ? `${name}/` : name,
|
|
@@ -91406,6 +92041,165 @@ function emitChannelTargetsUpdated(socket, channelId) {
|
|
|
91406
92041
|
channel_id: channelId
|
|
91407
92042
|
}, "listener_channels_send_failed", "listener_channels_command");
|
|
91408
92043
|
}
|
|
92044
|
+
async function handleListMemoryCommand(parsed, socket, overrides = {}) {
|
|
92045
|
+
try {
|
|
92046
|
+
const {
|
|
92047
|
+
ensureLocalMemfsCheckout: actualEnsureLocalMemfsCheckout,
|
|
92048
|
+
getMemoryFilesystemRoot: actualGetMemoryFilesystemRoot,
|
|
92049
|
+
isMemfsEnabledOnServer: actualIsMemfsEnabledOnServer
|
|
92050
|
+
} = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
|
|
92051
|
+
const ensureLocalMemfsCheckout2 = overrides.ensureLocalMemfsCheckout ?? actualEnsureLocalMemfsCheckout;
|
|
92052
|
+
const getMemoryFilesystemRoot2 = overrides.getMemoryFilesystemRoot ?? actualGetMemoryFilesystemRoot;
|
|
92053
|
+
const isMemfsEnabledOnServer2 = overrides.isMemfsEnabledOnServer ?? actualIsMemfsEnabledOnServer;
|
|
92054
|
+
const { scanMemoryFilesystem: scanMemoryFilesystem2, getFileNodes: getFileNodes2, readFileContent: readFileContent2 } = await Promise.resolve().then(() => (init_memoryScanner(), exports_memoryScanner));
|
|
92055
|
+
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => exports_frontmatter);
|
|
92056
|
+
const { existsSync: existsSync26 } = await import("node:fs");
|
|
92057
|
+
const { join: join31, posix: posix2 } = await import("node:path");
|
|
92058
|
+
const memoryRoot = getMemoryFilesystemRoot2(parsed.agent_id);
|
|
92059
|
+
let memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
|
|
92060
|
+
const memfsEnabled = memfsInitialized ? true : await isMemfsEnabledOnServer2(parsed.agent_id);
|
|
92061
|
+
if (!memfsEnabled) {
|
|
92062
|
+
safeSocketSend(socket, {
|
|
92063
|
+
type: "list_memory_response",
|
|
92064
|
+
request_id: parsed.request_id,
|
|
92065
|
+
entries: [],
|
|
92066
|
+
done: true,
|
|
92067
|
+
total: 0,
|
|
92068
|
+
success: true,
|
|
92069
|
+
memfs_enabled: false,
|
|
92070
|
+
memfs_initialized: false
|
|
92071
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92072
|
+
return true;
|
|
92073
|
+
}
|
|
92074
|
+
if (!memfsInitialized) {
|
|
92075
|
+
await ensureLocalMemfsCheckout2(parsed.agent_id);
|
|
92076
|
+
memfsInitialized = existsSync26(join31(memoryRoot, ".git"));
|
|
92077
|
+
}
|
|
92078
|
+
if (!memfsInitialized) {
|
|
92079
|
+
throw new Error("MemFS is enabled, but the local memory checkout could not be initialized.");
|
|
92080
|
+
}
|
|
92081
|
+
const treeNodes = scanMemoryFilesystem2(memoryRoot);
|
|
92082
|
+
const fileNodes = getFileNodes2(treeNodes).filter((n) => n.name.endsWith(".md"));
|
|
92083
|
+
const includeReferences = parsed.include_references === true;
|
|
92084
|
+
const allPaths = new Set(fileNodes.map((node) => node.relativePath));
|
|
92085
|
+
const normalizeMemoryReference = (rawReference, sourcePath) => {
|
|
92086
|
+
let target = rawReference.trim();
|
|
92087
|
+
if (!target) {
|
|
92088
|
+
return null;
|
|
92089
|
+
}
|
|
92090
|
+
if (target.startsWith("http://") || target.startsWith("https://") || target.startsWith("mailto:")) {
|
|
92091
|
+
return null;
|
|
92092
|
+
}
|
|
92093
|
+
target = target.replace(/^<|>$/g, "");
|
|
92094
|
+
target = target.split("#")[0] ?? "";
|
|
92095
|
+
target = target.split("?")[0] ?? "";
|
|
92096
|
+
target = target.trim().replace(/\\/g, "/");
|
|
92097
|
+
if (!target || target.startsWith("#")) {
|
|
92098
|
+
return null;
|
|
92099
|
+
}
|
|
92100
|
+
if (target.includes("|")) {
|
|
92101
|
+
target = target.split("|")[0] ?? "";
|
|
92102
|
+
}
|
|
92103
|
+
if (!target) {
|
|
92104
|
+
return null;
|
|
92105
|
+
}
|
|
92106
|
+
const sourceDir = posix2.dirname(sourcePath.replace(/\\/g, "/"));
|
|
92107
|
+
const candidate = target.startsWith("./") || target.startsWith("../") ? posix2.normalize(posix2.join(sourceDir, target)) : posix2.normalize(target.startsWith("/") ? target.slice(1) : target);
|
|
92108
|
+
if (!candidate || candidate.startsWith("../") || candidate === "." || candidate === "..") {
|
|
92109
|
+
return null;
|
|
92110
|
+
}
|
|
92111
|
+
const withExtension = candidate.endsWith(".md") ? candidate : `${candidate}.md`;
|
|
92112
|
+
const candidates = new Set([withExtension]);
|
|
92113
|
+
const isExplicitRelative = target.startsWith("./") || target.startsWith("../");
|
|
92114
|
+
if (!isExplicitRelative && !target.startsWith("/") && sourceDir && sourceDir !== ".") {
|
|
92115
|
+
candidates.add(posix2.normalize(posix2.join(sourceDir, withExtension)));
|
|
92116
|
+
}
|
|
92117
|
+
if (!withExtension.startsWith("system/")) {
|
|
92118
|
+
candidates.add(posix2.normalize(`system/${withExtension}`));
|
|
92119
|
+
}
|
|
92120
|
+
for (const resolved of candidates) {
|
|
92121
|
+
if (allPaths.has(resolved)) {
|
|
92122
|
+
return resolved;
|
|
92123
|
+
}
|
|
92124
|
+
}
|
|
92125
|
+
return null;
|
|
92126
|
+
};
|
|
92127
|
+
const extractMemoryReferences = (body, sourcePath) => {
|
|
92128
|
+
if (!body.includes("[[")) {
|
|
92129
|
+
return [];
|
|
92130
|
+
}
|
|
92131
|
+
const refs = new Set;
|
|
92132
|
+
for (const wikiMatch of body.matchAll(WIKI_LINK_REGEX)) {
|
|
92133
|
+
const rawTarget = wikiMatch[1];
|
|
92134
|
+
if (!rawTarget)
|
|
92135
|
+
continue;
|
|
92136
|
+
const normalized = normalizeMemoryReference(rawTarget, sourcePath);
|
|
92137
|
+
if (normalized && normalized !== sourcePath) {
|
|
92138
|
+
refs.add(normalized);
|
|
92139
|
+
}
|
|
92140
|
+
}
|
|
92141
|
+
return [...refs];
|
|
92142
|
+
};
|
|
92143
|
+
const CHUNK_SIZE = 5;
|
|
92144
|
+
const total = fileNodes.length;
|
|
92145
|
+
for (let i = 0;i < total; i += CHUNK_SIZE) {
|
|
92146
|
+
const chunk = fileNodes.slice(i, i + CHUNK_SIZE);
|
|
92147
|
+
const entries = chunk.map((node) => {
|
|
92148
|
+
const raw = readFileContent2(node.fullPath);
|
|
92149
|
+
const { frontmatter, body } = parseFrontmatter2(raw);
|
|
92150
|
+
const desc = frontmatter.description;
|
|
92151
|
+
return {
|
|
92152
|
+
relative_path: node.relativePath,
|
|
92153
|
+
is_system: node.relativePath.startsWith("system/") || node.relativePath.startsWith("system\\"),
|
|
92154
|
+
description: typeof desc === "string" ? desc : null,
|
|
92155
|
+
content: body,
|
|
92156
|
+
size: body.length,
|
|
92157
|
+
...includeReferences ? {
|
|
92158
|
+
references: extractMemoryReferences(body, node.relativePath)
|
|
92159
|
+
} : {}
|
|
92160
|
+
};
|
|
92161
|
+
});
|
|
92162
|
+
const done = i + CHUNK_SIZE >= total;
|
|
92163
|
+
const sent = safeSocketSend(socket, {
|
|
92164
|
+
type: "list_memory_response",
|
|
92165
|
+
request_id: parsed.request_id,
|
|
92166
|
+
entries,
|
|
92167
|
+
done,
|
|
92168
|
+
total,
|
|
92169
|
+
success: true,
|
|
92170
|
+
memfs_enabled: true,
|
|
92171
|
+
memfs_initialized: true
|
|
92172
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92173
|
+
if (!sent) {
|
|
92174
|
+
return true;
|
|
92175
|
+
}
|
|
92176
|
+
}
|
|
92177
|
+
if (total === 0) {
|
|
92178
|
+
safeSocketSend(socket, {
|
|
92179
|
+
type: "list_memory_response",
|
|
92180
|
+
request_id: parsed.request_id,
|
|
92181
|
+
entries: [],
|
|
92182
|
+
done: true,
|
|
92183
|
+
total: 0,
|
|
92184
|
+
success: true,
|
|
92185
|
+
memfs_enabled: true,
|
|
92186
|
+
memfs_initialized: true
|
|
92187
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92188
|
+
}
|
|
92189
|
+
} catch (err) {
|
|
92190
|
+
trackListenerError("listener_list_memory_failed", err, "listener_memory_browser");
|
|
92191
|
+
safeSocketSend(socket, {
|
|
92192
|
+
type: "list_memory_response",
|
|
92193
|
+
request_id: parsed.request_id,
|
|
92194
|
+
entries: [],
|
|
92195
|
+
done: true,
|
|
92196
|
+
total: 0,
|
|
92197
|
+
success: false,
|
|
92198
|
+
error: err instanceof Error ? err.message : "Failed to list memory"
|
|
92199
|
+
}, "listener_list_memory_send_failed", "listener_list_memory");
|
|
92200
|
+
}
|
|
92201
|
+
return true;
|
|
92202
|
+
}
|
|
91409
92203
|
async function handleCronCommand(parsed, socket) {
|
|
91410
92204
|
if (parsed.type === "cron_list") {
|
|
91411
92205
|
try {
|
|
@@ -92259,7 +93053,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
92259
93053
|
symlinkSync,
|
|
92260
93054
|
unlinkSync: unlinkSync8
|
|
92261
93055
|
} = await import("node:fs");
|
|
92262
|
-
const { basename:
|
|
93056
|
+
const { basename: basename10, join: join31 } = await import("node:path");
|
|
92263
93057
|
const lettaHome = process.env.LETTA_HOME || join31(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
|
|
92264
93058
|
const globalSkillsDir = join31(lettaHome, "skills");
|
|
92265
93059
|
if (parsed.type === "skill_enable") {
|
|
@@ -92283,7 +93077,7 @@ async function handleSkillCommand(parsed, socket) {
|
|
|
92283
93077
|
}, "listener_skill_send_failed", "listener_skill_command");
|
|
92284
93078
|
return true;
|
|
92285
93079
|
}
|
|
92286
|
-
const linkName =
|
|
93080
|
+
const linkName = basename10(parsed.skill_path);
|
|
92287
93081
|
const linkPath = join31(globalSkillsDir, linkName);
|
|
92288
93082
|
mkdirSync19(globalSkillsDir, { recursive: true });
|
|
92289
93083
|
if (existsSync26(linkPath)) {
|
|
@@ -92495,12 +93289,21 @@ function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
|
|
|
92495
93289
|
const registry = getChannelRegistry();
|
|
92496
93290
|
if (!registry)
|
|
92497
93291
|
return;
|
|
92498
|
-
registry.setMessageHandler((
|
|
92499
|
-
const rawRuntime = getOrCreateConversationRuntime(listener, route.agentId, route.conversationId);
|
|
93292
|
+
registry.setMessageHandler((delivery) => {
|
|
93293
|
+
const rawRuntime = getOrCreateConversationRuntime(listener, delivery.route.agentId, delivery.route.conversationId);
|
|
92500
93294
|
if (!rawRuntime)
|
|
92501
93295
|
return;
|
|
92502
93296
|
const conversationRuntime = ensureConversationQueueRuntime(listener, rawRuntime);
|
|
92503
|
-
enqueueChannelTurn(conversationRuntime, route,
|
|
93297
|
+
const enqueuedItem = enqueueChannelTurn(conversationRuntime, delivery.route, delivery.content, delivery.turnSources);
|
|
93298
|
+
if (!enqueuedItem) {
|
|
93299
|
+
return;
|
|
93300
|
+
}
|
|
93301
|
+
for (const turnSource of delivery.turnSources ?? []) {
|
|
93302
|
+
registry.dispatchTurnLifecycleEvent({
|
|
93303
|
+
type: "queued",
|
|
93304
|
+
source: turnSource
|
|
93305
|
+
});
|
|
93306
|
+
}
|
|
92504
93307
|
scheduleQueuePump(conversationRuntime, socket, opts, processQueuedTurn);
|
|
92505
93308
|
});
|
|
92506
93309
|
registry.setEventHandler((event) => {
|
|
@@ -92534,7 +93337,7 @@ function stampInboundUserMessageOtids(incoming) {
|
|
|
92534
93337
|
messages
|
|
92535
93338
|
};
|
|
92536
93339
|
}
|
|
92537
|
-
function enqueueChannelTurn(runtime, route, messageContent) {
|
|
93340
|
+
function enqueueChannelTurn(runtime, route, messageContent, turnSources) {
|
|
92538
93341
|
const clientMessageId = `cm-channel-${crypto.randomUUID()}`;
|
|
92539
93342
|
const enqueuedItem = runtime.queueRuntime.enqueue({
|
|
92540
93343
|
kind: "message",
|
|
@@ -92551,6 +93354,7 @@ function enqueueChannelTurn(runtime, route, messageContent) {
|
|
|
92551
93354
|
type: "message",
|
|
92552
93355
|
agentId: route.agentId,
|
|
92553
93356
|
conversationId: route.conversationId,
|
|
93357
|
+
...turnSources?.length ? { channelTurnSources: turnSources } : {},
|
|
92554
93358
|
messages: [
|
|
92555
93359
|
{
|
|
92556
93360
|
role: "user",
|
|
@@ -93509,144 +94313,7 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
93509
94313
|
}
|
|
93510
94314
|
if (isListMemoryCommand(parsed)) {
|
|
93511
94315
|
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
|
-
}
|
|
94316
|
+
await handleListMemoryCommand(parsed, socket);
|
|
93650
94317
|
});
|
|
93651
94318
|
return;
|
|
93652
94319
|
}
|
|
@@ -94324,6 +94991,7 @@ var init_client4 = __esm(async () => {
|
|
|
94324
94991
|
handleAbortMessageInput,
|
|
94325
94992
|
handleChangeDeviceStateInput,
|
|
94326
94993
|
handleCronCommand,
|
|
94994
|
+
handleListMemoryCommand,
|
|
94327
94995
|
isDetachedChannelsCommand,
|
|
94328
94996
|
handleChannelsProtocolCommand,
|
|
94329
94997
|
handleSkillCommand,
|
|
@@ -115408,16 +116076,16 @@ function clipStyledSpans(spans, maxColumns) {
|
|
|
115408
116076
|
return { spans: clipped, clipped: false };
|
|
115409
116077
|
}
|
|
115410
116078
|
function languageFromPath(filePath) {
|
|
115411
|
-
const
|
|
115412
|
-
const lower =
|
|
116079
|
+
const basename10 = filePath.split("/").pop() ?? filePath;
|
|
116080
|
+
const lower = basename10.toLowerCase();
|
|
115413
116081
|
if (lower === "makefile")
|
|
115414
116082
|
return "makefile";
|
|
115415
116083
|
if (lower === "dockerfile")
|
|
115416
116084
|
return "dockerfile";
|
|
115417
|
-
const dotIdx =
|
|
116085
|
+
const dotIdx = basename10.lastIndexOf(".");
|
|
115418
116086
|
if (dotIdx < 0)
|
|
115419
116087
|
return;
|
|
115420
|
-
const ext3 =
|
|
116088
|
+
const ext3 = basename10.slice(dotIdx + 1).toLowerCase();
|
|
115421
116089
|
return EXT_TO_LANG[ext3];
|
|
115422
116090
|
}
|
|
115423
116091
|
function colorForClassName(className, palette) {
|
|
@@ -121829,7 +122497,7 @@ var init_pasteRegistry = __esm(() => {
|
|
|
121829
122497
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
121830
122498
|
import { existsSync as existsSync34, readFileSync as readFileSync20, statSync as statSync10, unlinkSync as unlinkSync10 } from "node:fs";
|
|
121831
122499
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
121832
|
-
import { basename as
|
|
122500
|
+
import { basename as basename10, extname as extname8, isAbsolute as isAbsolute20, join as join42, resolve as resolve29 } from "node:path";
|
|
121833
122501
|
function countLines2(text) {
|
|
121834
122502
|
return (text.match(/\r\n|\r|\n/g) || []).length + 1;
|
|
121835
122503
|
}
|
|
@@ -121886,7 +122554,7 @@ function translatePasteForImages(paste) {
|
|
|
121886
122554
|
const id = allocateImage({
|
|
121887
122555
|
data: b64,
|
|
121888
122556
|
mediaType: mt,
|
|
121889
|
-
filename:
|
|
122557
|
+
filename: basename10(filePath)
|
|
121890
122558
|
});
|
|
121891
122559
|
s = `[Image #${id}]`;
|
|
121892
122560
|
}
|
|
@@ -123493,7 +124161,7 @@ __export(exports_custom, {
|
|
|
123493
124161
|
});
|
|
123494
124162
|
import { existsSync as existsSync36 } from "node:fs";
|
|
123495
124163
|
import { readdir as readdir10, readFile as readFile14 } from "node:fs/promises";
|
|
123496
|
-
import { basename as
|
|
124164
|
+
import { basename as basename11, dirname as dirname17, join as join44 } from "node:path";
|
|
123497
124165
|
async function getCustomCommands() {
|
|
123498
124166
|
if (cachedCommands !== null) {
|
|
123499
124167
|
return cachedCommands;
|
|
@@ -123553,7 +124221,7 @@ async function findCommandFiles(currentPath, rootPath, commands2, source2) {
|
|
|
123553
124221
|
async function parseCommandFile(filePath, rootPath, source2) {
|
|
123554
124222
|
const content = await readFile14(filePath, "utf-8");
|
|
123555
124223
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
123556
|
-
const id =
|
|
124224
|
+
const id = basename11(filePath, ".md");
|
|
123557
124225
|
const relativePath = dirname17(filePath).slice(rootPath.length);
|
|
123558
124226
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
123559
124227
|
let description = getStringField(frontmatter, "description");
|
|
@@ -143554,6 +144222,10 @@ function App2({
|
|
|
143554
144222
|
import_react104.useEffect(() => {
|
|
143555
144223
|
conversationIdRef.current = conversationId;
|
|
143556
144224
|
}, [conversationId]);
|
|
144225
|
+
const setConversationIdAndRef = import_react104.useCallback((nextConversationId) => {
|
|
144226
|
+
conversationIdRef.current = nextConversationId;
|
|
144227
|
+
setConversationId3(nextConversationId);
|
|
144228
|
+
}, []);
|
|
143557
144229
|
const pendingTranscriptStartLineIndexRef = import_react104.useRef(null);
|
|
143558
144230
|
const lastRunIdRef = import_react104.useRef(null);
|
|
143559
144231
|
const resumeKey = useSuspend();
|
|
@@ -143577,10 +144249,9 @@ function App2({
|
|
|
143577
144249
|
import_react104.useEffect(() => {
|
|
143578
144250
|
if (initialConversationId !== prevInitialConversationIdRef.current) {
|
|
143579
144251
|
prevInitialConversationIdRef.current = initialConversationId;
|
|
143580
|
-
|
|
143581
|
-
setConversationId3(initialConversationId);
|
|
144252
|
+
setConversationIdAndRef(initialConversationId);
|
|
143582
144253
|
}
|
|
143583
|
-
}, [initialConversationId]);
|
|
144254
|
+
}, [initialConversationId, setConversationIdAndRef]);
|
|
143584
144255
|
import_react104.useEffect(() => {
|
|
143585
144256
|
if (agentId) {
|
|
143586
144257
|
setCurrentAgentId(agentId);
|
|
@@ -147071,7 +147742,7 @@ ${feedback}
|
|
|
147071
147742
|
const client = await getClient();
|
|
147072
147743
|
const resumeData = await getResumeData2(client, agentState, conversationId2);
|
|
147073
147744
|
await maybeCarryOverActiveConversationModel(conversationId2);
|
|
147074
|
-
|
|
147745
|
+
setConversationIdAndRef(conversationId2);
|
|
147075
147746
|
pendingConversationSwitchRef.current = {
|
|
147076
147747
|
origin: "fork",
|
|
147077
147748
|
conversationId: conversationId2,
|
|
@@ -147136,6 +147807,7 @@ ${feedback}
|
|
|
147136
147807
|
runEndHooks,
|
|
147137
147808
|
maybeCarryOverActiveConversationModel,
|
|
147138
147809
|
resetBootstrapReminderState,
|
|
147810
|
+
setConversationIdAndRef,
|
|
147139
147811
|
setCommandRunning,
|
|
147140
147812
|
setStreaming,
|
|
147141
147813
|
recoverRestoredPendingApprovals,
|
|
@@ -147188,7 +147860,7 @@ ${feedback}
|
|
|
147188
147860
|
setLlmConfig(agent.llm_config);
|
|
147189
147861
|
const agentModelHandle = getPreferredAgentModelHandle2(agent);
|
|
147190
147862
|
setCurrentModelHandle(agentModelHandle);
|
|
147191
|
-
|
|
147863
|
+
setConversationIdAndRef(targetConversationId);
|
|
147192
147864
|
resetBootstrapReminderState();
|
|
147193
147865
|
{
|
|
147194
147866
|
const { getModelDisplayName: getModelDisplayName3 } = await Promise.resolve().then(() => (init_model2(), exports_model2));
|
|
@@ -147241,7 +147913,8 @@ ${feedback}
|
|
|
147241
147913
|
resetDeferredToolCallCommits,
|
|
147242
147914
|
resetTrajectoryBases,
|
|
147243
147915
|
resetBootstrapReminderState,
|
|
147244
|
-
resetPendingReasoningCycle
|
|
147916
|
+
resetPendingReasoningCycle,
|
|
147917
|
+
setConversationIdAndRef
|
|
147245
147918
|
]);
|
|
147246
147919
|
const handleCreateNewAgent = import_react104.useCallback(async (name) => {
|
|
147247
147920
|
setActiveOverlay(null);
|
|
@@ -147309,7 +147982,7 @@ ${feedback}
|
|
|
147309
147982
|
setLlmConfig(agent.llm_config);
|
|
147310
147983
|
const agentModelHandle = getPreferredAgentModelHandle2(agent);
|
|
147311
147984
|
setCurrentModelHandle(agentModelHandle);
|
|
147312
|
-
|
|
147985
|
+
setConversationIdAndRef(targetConversationId);
|
|
147313
147986
|
pendingConversationSwitchRef.current = {
|
|
147314
147987
|
origin: "agent-switch",
|
|
147315
147988
|
conversationId: targetConversationId,
|
|
@@ -147343,7 +148016,8 @@ ${feedback}
|
|
|
147343
148016
|
setCommandRunning,
|
|
147344
148017
|
resetDeferredToolCallCommits,
|
|
147345
148018
|
resetTrajectoryBases,
|
|
147346
|
-
resetBootstrapReminderState
|
|
148019
|
+
resetBootstrapReminderState,
|
|
148020
|
+
setConversationIdAndRef
|
|
147347
148021
|
]);
|
|
147348
148022
|
const handleBashSubmit = import_react104.useCallback(async (command) => {
|
|
147349
148023
|
if (bashRunning)
|
|
@@ -148284,7 +148958,7 @@ Type your task to begin the loop.`, true);
|
|
|
148284
148958
|
hasSetConversationSummaryRef.current = true;
|
|
148285
148959
|
}
|
|
148286
148960
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
148287
|
-
|
|
148961
|
+
setConversationIdAndRef(conversation.id);
|
|
148288
148962
|
pendingConversationSwitchRef.current = {
|
|
148289
148963
|
origin: "new",
|
|
148290
148964
|
conversationId: conversation.id,
|
|
@@ -148329,7 +149003,7 @@ Type your task to begin the loop.`, true);
|
|
|
148329
149003
|
hasSetConversationSummaryRef.current = true;
|
|
148330
149004
|
}
|
|
148331
149005
|
await maybeCarryOverActiveConversationModel(forked.id);
|
|
148332
|
-
|
|
149006
|
+
setConversationIdAndRef(forked.id);
|
|
148333
149007
|
pendingConversationSwitchRef.current = {
|
|
148334
149008
|
origin: "fork",
|
|
148335
149009
|
conversationId: forked.id,
|
|
@@ -148383,7 +149057,7 @@ Type your task to begin the loop.`, true);
|
|
|
148383
149057
|
isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
|
|
148384
149058
|
});
|
|
148385
149059
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
148386
|
-
|
|
149060
|
+
setConversationIdAndRef(conversation.id);
|
|
148387
149061
|
pendingConversationSwitchRef.current = {
|
|
148388
149062
|
origin: "clear",
|
|
148389
149063
|
conversationId: conversation.id,
|
|
@@ -148634,7 +149308,7 @@ Type your task to begin the loop.`, true);
|
|
|
148634
149308
|
if (agentState) {
|
|
148635
149309
|
const client = await getClient();
|
|
148636
149310
|
const resumeData = await getResumeData2(client, agentState, targetConvId);
|
|
148637
|
-
|
|
149311
|
+
setConversationIdAndRef(targetConvId);
|
|
148638
149312
|
pendingConversationSwitchRef.current = {
|
|
148639
149313
|
origin: "resume-direct",
|
|
148640
149314
|
conversationId: targetConvId,
|
|
@@ -149569,7 +150243,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
149569
150243
|
name: agentName,
|
|
149570
150244
|
description: agentDescription,
|
|
149571
150245
|
lastRunAt: agentLastRunAt,
|
|
149572
|
-
conversationId
|
|
150246
|
+
conversationId: conversationIdRef.current
|
|
149573
150247
|
},
|
|
149574
150248
|
state: sharedReminderStateRef.current,
|
|
149575
150249
|
sessionContextReminderEnabled,
|
|
@@ -150022,6 +150696,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
150022
150696
|
agentName,
|
|
150023
150697
|
agentDescription,
|
|
150024
150698
|
agentLastRunAt,
|
|
150699
|
+
conversationId,
|
|
150025
150700
|
commandRunner,
|
|
150026
150701
|
handleExit,
|
|
150027
150702
|
isExecutingTool,
|
|
@@ -150040,7 +150715,8 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
150040
150715
|
resetTrajectoryBases,
|
|
150041
150716
|
sessionContextReminderEnabled,
|
|
150042
150717
|
appendTaskNotificationEvents,
|
|
150043
|
-
maybeCarryOverActiveConversationModel
|
|
150718
|
+
maybeCarryOverActiveConversationModel,
|
|
150719
|
+
setConversationIdAndRef
|
|
150044
150720
|
]);
|
|
150045
150721
|
const onSubmitRef = import_react104.useRef(onSubmit);
|
|
150046
150722
|
import_react104.useEffect(() => {
|
|
@@ -151040,7 +151716,7 @@ ${guidance}`);
|
|
|
151040
151716
|
const client = await getClient();
|
|
151041
151717
|
if (agentState) {
|
|
151042
151718
|
const resumeData = await getResumeData2(client, agentState, action.conversationId);
|
|
151043
|
-
|
|
151719
|
+
setConversationIdAndRef(action.conversationId);
|
|
151044
151720
|
pendingConversationSwitchRef.current = {
|
|
151045
151721
|
origin: "resume-selector",
|
|
151046
151722
|
conversationId: action.conversationId,
|
|
@@ -151093,7 +151769,8 @@ ${guidance}`);
|
|
|
151093
151769
|
commandRunner.getHandle,
|
|
151094
151770
|
commandRunner.start,
|
|
151095
151771
|
recoverRestoredPendingApprovals,
|
|
151096
|
-
resetBootstrapReminderState
|
|
151772
|
+
resetBootstrapReminderState,
|
|
151773
|
+
setConversationIdAndRef
|
|
151097
151774
|
]);
|
|
151098
151775
|
const handleFeedbackSubmit = import_react104.useCallback(async (message) => {
|
|
151099
151776
|
const overlayCommand = consumeOverlayCommand("feedback");
|
|
@@ -152351,7 +153028,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152351
153028
|
if (agentState) {
|
|
152352
153029
|
const client = await getClient();
|
|
152353
153030
|
const resumeData = await getResumeData2(client, agentState, convId);
|
|
152354
|
-
|
|
153031
|
+
setConversationIdAndRef(convId);
|
|
152355
153032
|
pendingConversationSwitchRef.current = {
|
|
152356
153033
|
origin: "resume-selector",
|
|
152357
153034
|
conversationId: convId,
|
|
@@ -152463,7 +153140,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152463
153140
|
isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
|
|
152464
153141
|
});
|
|
152465
153142
|
await maybeCarryOverActiveConversationModel(conversation.id);
|
|
152466
|
-
|
|
153143
|
+
setConversationIdAndRef(conversation.id);
|
|
152467
153144
|
settingsManager.persistSession(agentId, conversation.id);
|
|
152468
153145
|
const currentAgentName = agentState?.name || "Unnamed Agent";
|
|
152469
153146
|
const shortConvId = conversation.id.slice(0, 20);
|
|
@@ -152547,7 +153224,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
|
|
|
152547
153224
|
if (agentState) {
|
|
152548
153225
|
const client = await getClient();
|
|
152549
153226
|
const resumeData = await getResumeData2(client, agentState, actualTargetConv);
|
|
152550
|
-
|
|
153227
|
+
setConversationIdAndRef(actualTargetConv);
|
|
152551
153228
|
pendingConversationSwitchRef.current = {
|
|
152552
153229
|
origin: "search",
|
|
152553
153230
|
conversationId: actualTargetConv,
|
|
@@ -153919,10 +154596,12 @@ var exports_memoryFilesystem2 = {};
|
|
|
153919
154596
|
__export(exports_memoryFilesystem2, {
|
|
153920
154597
|
renderMemoryFilesystemTree: () => renderMemoryFilesystemTree2,
|
|
153921
154598
|
labelFromRelativePath: () => labelFromRelativePath2,
|
|
154599
|
+
isMemfsEnabledOnServer: () => isMemfsEnabledOnServer2,
|
|
153922
154600
|
isLettaCloud: () => isLettaCloud2,
|
|
153923
154601
|
getMemorySystemDir: () => getMemorySystemDir2,
|
|
153924
154602
|
getMemoryFilesystemRoot: () => getMemoryFilesystemRoot2,
|
|
153925
154603
|
ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs2,
|
|
154604
|
+
ensureLocalMemfsCheckout: () => ensureLocalMemfsCheckout2,
|
|
153926
154605
|
enableMemfsIfCloud: () => enableMemfsIfCloud2,
|
|
153927
154606
|
applyMemfsFlags: () => applyMemfsFlags2,
|
|
153928
154607
|
MEMORY_TREE_MAX_LINES: () => MEMORY_TREE_MAX_LINES2,
|
|
@@ -153952,6 +154631,23 @@ function ensureMemoryFilesystemDirs2(agentId, homeDir = homedir41()) {
|
|
|
153952
154631
|
mkdirSync30(systemDir, { recursive: true });
|
|
153953
154632
|
}
|
|
153954
154633
|
}
|
|
154634
|
+
async function isMemfsEnabledOnServer2(agentId) {
|
|
154635
|
+
const { getClient: getClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
154636
|
+
const client = await getClient3();
|
|
154637
|
+
const agent = await client.agents.retrieve(agentId);
|
|
154638
|
+
const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
154639
|
+
const enabled = agent.tags?.includes(GIT_MEMORY_ENABLED_TAG2) ?? false;
|
|
154640
|
+
const { settingsManager: settingsManager3 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
154641
|
+
settingsManager3.setMemfsEnabled(agentId, enabled);
|
|
154642
|
+
return enabled;
|
|
154643
|
+
}
|
|
154644
|
+
async function ensureLocalMemfsCheckout2(agentId) {
|
|
154645
|
+
const { isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
|
|
154646
|
+
if (isGitRepo2(agentId)) {
|
|
154647
|
+
return;
|
|
154648
|
+
}
|
|
154649
|
+
await cloneMemoryRepo2(agentId);
|
|
154650
|
+
}
|
|
153955
154651
|
function labelFromRelativePath2(relativePath) {
|
|
153956
154652
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
153957
154653
|
return normalized.replace(/\.md$/, "");
|
|
@@ -163181,4 +163877,4 @@ Error during initialization: ${message}`);
|
|
|
163181
163877
|
}
|
|
163182
163878
|
main();
|
|
163183
163879
|
|
|
163184
|
-
//# debugId=
|
|
163880
|
+
//# debugId=E826850D234138B664756E2164756E21
|