@letta-ai/letta-code 0.28.4 → 0.28.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/dist/agent-presets.js +3 -1
- package/dist/agent-presets.js.map +3 -3
- package/dist/app-server-client.js +26 -4
- package/dist/app-server-client.js.map +3 -3
- package/dist/types/agent/agent-tags.d.ts +2 -0
- package/dist/types/agent/agent-tags.d.ts.map +1 -1
- package/dist/types/agent-presets.d.ts +1 -1
- package/dist/types/agent-presets.d.ts.map +1 -1
- package/dist/types/app-server-client.d.ts +11 -0
- package/dist/types/app-server-client.d.ts.map +1 -1
- package/dist/types/types/protocol_v2.d.ts +10 -1
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/letta.js +1537 -966
- package/package.json +1 -1
- package/scripts/isolated-unit-tests.json +10 -0
- package/scripts/source-file-size-baseline.json +7 -7
- package/skills/creating-mods/references/ui.md +2 -2
package/letta.js
CHANGED
|
@@ -3138,6 +3138,29 @@ var init_letta_client = __esm(() => {
|
|
|
3138
3138
|
init_error();
|
|
3139
3139
|
});
|
|
3140
3140
|
|
|
3141
|
+
// src/auth/oauth-refresh.ts
|
|
3142
|
+
async function refreshAccessTokenSingleFlight(refreshToken, deviceId, deviceName, refresh = refreshAccessToken) {
|
|
3143
|
+
const refreshKey = `${refreshToken}\x00${deviceId}`;
|
|
3144
|
+
const existing = inFlightRefreshes.get(refreshKey);
|
|
3145
|
+
if (existing) {
|
|
3146
|
+
return await existing;
|
|
3147
|
+
}
|
|
3148
|
+
const pending = refresh(refreshToken, deviceId, deviceName);
|
|
3149
|
+
inFlightRefreshes.set(refreshKey, pending);
|
|
3150
|
+
try {
|
|
3151
|
+
return await pending;
|
|
3152
|
+
} finally {
|
|
3153
|
+
if (inFlightRefreshes.get(refreshKey) === pending) {
|
|
3154
|
+
inFlightRefreshes.delete(refreshKey);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
var inFlightRefreshes;
|
|
3159
|
+
var init_oauth_refresh = __esm(() => {
|
|
3160
|
+
init_oauth();
|
|
3161
|
+
inFlightRefreshes = new Map;
|
|
3162
|
+
});
|
|
3163
|
+
|
|
3141
3164
|
// src/agent/agent-id.ts
|
|
3142
3165
|
function isLocalAgentId(agentId) {
|
|
3143
3166
|
return agentId.startsWith("agent-local-");
|
|
@@ -3846,14 +3869,13 @@ class SettingsManager {
|
|
|
3846
3869
|
}
|
|
3847
3870
|
async getSettingsWithSecureTokens() {
|
|
3848
3871
|
const baseSettings = this.getSettings();
|
|
3849
|
-
|
|
3872
|
+
const secureTokens = { ...this.secureTokensCache };
|
|
3850
3873
|
if (!getRuntimeContext()) {
|
|
3851
3874
|
const secretsAvailable2 = await this.isKeychainAvailable();
|
|
3852
3875
|
if (secretsAvailable2) {
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
};
|
|
3876
|
+
const storedTokens = await this.getSecureTokens();
|
|
3877
|
+
secureTokens.apiKey = storedTokens.apiKey ?? secureTokens.apiKey;
|
|
3878
|
+
secureTokens.refreshToken = storedTokens.refreshToken ?? secureTokens.refreshToken;
|
|
3857
3879
|
}
|
|
3858
3880
|
}
|
|
3859
3881
|
const fallbackRefreshToken = !secureTokens.refreshToken && baseSettings.refreshToken ? baseSettings.refreshToken : secureTokens.refreshToken;
|
|
@@ -4815,7 +4837,7 @@ var package_default;
|
|
|
4815
4837
|
var init_package = __esm(() => {
|
|
4816
4838
|
package_default = {
|
|
4817
4839
|
name: "@letta-ai/letta-code",
|
|
4818
|
-
version: "0.28.
|
|
4840
|
+
version: "0.28.6",
|
|
4819
4841
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
4820
4842
|
type: "module",
|
|
4821
4843
|
packageManager: "bun@1.3.0",
|
|
@@ -5113,7 +5135,7 @@ async function getClient() {
|
|
|
5113
5135
|
try {
|
|
5114
5136
|
const deviceId = settingsManager.getOrCreateDeviceId();
|
|
5115
5137
|
const deviceName = hostname();
|
|
5116
|
-
const tokens = await
|
|
5138
|
+
const tokens = await refreshAccessTokenSingleFlight(settings.refreshToken, deviceId, deviceName);
|
|
5117
5139
|
settingsManager.updateSettings({
|
|
5118
5140
|
env: { LETTA_API_KEY: tokens.access_token },
|
|
5119
5141
|
refreshToken: tokens.refresh_token || settings.refreshToken,
|
|
@@ -5176,6 +5198,7 @@ var SDK_DIAGNOSTIC_MAX_LEN = 400, SDK_DIAGNOSTIC_MAX_LINES = 4, lastSDKDiagnosti
|
|
|
5176
5198
|
var init_client2 = __esm(() => {
|
|
5177
5199
|
init_letta_client();
|
|
5178
5200
|
init_oauth();
|
|
5201
|
+
init_oauth_refresh();
|
|
5179
5202
|
init_settings_manager();
|
|
5180
5203
|
init_error_reporting();
|
|
5181
5204
|
init_debug();
|
|
@@ -5855,6 +5878,7 @@ __export(exports_oauth, {
|
|
|
5855
5878
|
requestDeviceCode: () => requestDeviceCode,
|
|
5856
5879
|
refreshAccessToken: () => refreshAccessToken,
|
|
5857
5880
|
pollForToken: () => pollForToken,
|
|
5881
|
+
OAuthRefreshError: () => OAuthRefreshError,
|
|
5858
5882
|
OAUTH_CONFIG: () => OAUTH_CONFIG,
|
|
5859
5883
|
LETTA_CLOUD_API_URL: () => LETTA_CLOUD_API_URL
|
|
5860
5884
|
});
|
|
@@ -6035,11 +6059,22 @@ async function refreshAccessToken(refreshToken, deviceId, deviceName) {
|
|
|
6035
6059
|
});
|
|
6036
6060
|
if (!response.ok) {
|
|
6037
6061
|
const error = await response.json();
|
|
6038
|
-
throw new
|
|
6062
|
+
throw new OAuthRefreshError(`Failed to refresh access token from ${authHost}: ${error.error_description || error.error}`, {
|
|
6063
|
+
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
6064
|
+
status: response.status,
|
|
6065
|
+
oauthCode: error.error
|
|
6066
|
+
});
|
|
6039
6067
|
}
|
|
6040
6068
|
return await response.json();
|
|
6041
6069
|
} catch (error) {
|
|
6042
|
-
|
|
6070
|
+
if (error instanceof OAuthRefreshError) {
|
|
6071
|
+
throw error;
|
|
6072
|
+
}
|
|
6073
|
+
const actionError = toOAuthActionError("refresh access token", error);
|
|
6074
|
+
throw new OAuthRefreshError(actionError.message, {
|
|
6075
|
+
retryable: true,
|
|
6076
|
+
cause: error
|
|
6077
|
+
});
|
|
6043
6078
|
}
|
|
6044
6079
|
}
|
|
6045
6080
|
async function revokeToken(refreshToken) {
|
|
@@ -6125,7 +6160,7 @@ function classifyCredentialValidationError(error) {
|
|
|
6125
6160
|
}
|
|
6126
6161
|
return { ok: false, reason: "unknown", message };
|
|
6127
6162
|
}
|
|
6128
|
-
var LETTA_CLOUD_API_URL = "https://api.letta.com", OAUTH_CONFIG;
|
|
6163
|
+
var LETTA_CLOUD_API_URL = "https://api.letta.com", OAUTH_CONFIG, OAuthRefreshError;
|
|
6129
6164
|
var init_oauth = __esm(() => {
|
|
6130
6165
|
init_letta_client();
|
|
6131
6166
|
init_error();
|
|
@@ -6136,6 +6171,18 @@ var init_oauth = __esm(() => {
|
|
|
6136
6171
|
authBaseUrl: "https://app.letta.com",
|
|
6137
6172
|
apiBaseUrl: LETTA_CLOUD_API_URL
|
|
6138
6173
|
};
|
|
6174
|
+
OAuthRefreshError = class OAuthRefreshError extends Error {
|
|
6175
|
+
retryable;
|
|
6176
|
+
status;
|
|
6177
|
+
oauthCode;
|
|
6178
|
+
constructor(message, options) {
|
|
6179
|
+
super(message, { cause: options.cause });
|
|
6180
|
+
this.name = "OAuthRefreshError";
|
|
6181
|
+
this.retryable = options.retryable;
|
|
6182
|
+
this.status = options.status;
|
|
6183
|
+
this.oauthCode = options.oauthCode;
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6139
6186
|
});
|
|
6140
6187
|
|
|
6141
6188
|
// src/backend/backend-mode.ts
|
|
@@ -6157,6 +6204,7 @@ var init_backend_mode = __esm(() => {
|
|
|
6157
6204
|
var exports_agent_tags = {};
|
|
6158
6205
|
__export(exports_agent_tags, {
|
|
6159
6206
|
buildCreatedAgentTags: () => buildCreatedAgentTags,
|
|
6207
|
+
ONBOARDING_ORIGIN_TAG: () => ONBOARDING_ORIGIN_TAG,
|
|
6160
6208
|
LETTA_CODE_SUBAGENT_TAG: () => LETTA_CODE_SUBAGENT_TAG,
|
|
6161
6209
|
LETTA_CODE_ORIGIN_TAG: () => LETTA_CODE_ORIGIN_TAG,
|
|
6162
6210
|
GIT_MEMORY_ENABLED_TAG: () => GIT_MEMORY_ENABLED_TAG
|
|
@@ -6174,7 +6222,7 @@ function buildCreatedAgentTags(options = {}) {
|
|
|
6174
6222
|
}
|
|
6175
6223
|
return Array.from(new Set(tags));
|
|
6176
6224
|
}
|
|
6177
|
-
var LETTA_CODE_ORIGIN_TAG = "origin:letta-code", LETTA_CODE_SUBAGENT_TAG = "role:subagent", GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
|
|
6225
|
+
var LETTA_CODE_ORIGIN_TAG = "origin:letta-code", ONBOARDING_ORIGIN_TAG = "origin:onboarding", LETTA_CODE_SUBAGENT_TAG = "role:subagent", GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
|
|
6178
6226
|
|
|
6179
6227
|
// src/utils/text-files.ts
|
|
6180
6228
|
import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
@@ -168362,238 +168410,91 @@ var init_approval_controller = __esm(async () => {
|
|
|
168362
168410
|
await init_presentation();
|
|
168363
168411
|
});
|
|
168364
168412
|
|
|
168365
|
-
// src/channels/slack/
|
|
168366
|
-
import {
|
|
168367
|
-
import {
|
|
168368
|
-
|
|
168369
|
-
|
|
168370
|
-
|
|
168371
|
-
|
|
168372
|
-
case ".jpg":
|
|
168373
|
-
case ".jpeg":
|
|
168374
|
-
return "image/jpeg";
|
|
168375
|
-
case ".gif":
|
|
168376
|
-
return "image/gif";
|
|
168377
|
-
case ".webp":
|
|
168378
|
-
return "image/webp";
|
|
168379
|
-
case ".pdf":
|
|
168380
|
-
return "application/pdf";
|
|
168381
|
-
case ".txt":
|
|
168382
|
-
return "text/plain";
|
|
168383
|
-
case ".md":
|
|
168384
|
-
return "text/markdown";
|
|
168385
|
-
default:
|
|
168386
|
-
return;
|
|
168387
|
-
}
|
|
168388
|
-
}
|
|
168389
|
-
async function uploadSlackFile(slackClient, msg) {
|
|
168390
|
-
if (!msg.mediaPath) {
|
|
168391
|
-
throw new Error("mediaPath is required for Slack file uploads.");
|
|
168392
|
-
}
|
|
168393
|
-
const buffer = await readFile4(msg.mediaPath);
|
|
168394
|
-
const uploadFileName = msg.fileName ?? basename7(msg.mediaPath);
|
|
168395
|
-
const uploadTitle = msg.title ?? uploadFileName;
|
|
168396
|
-
const uploadMimeType = resolveUploadMimeType(uploadFileName);
|
|
168397
|
-
const uploadUrlResp = await slackClient.files.getUploadURLExternal({
|
|
168398
|
-
filename: uploadFileName,
|
|
168399
|
-
length: buffer.length
|
|
168400
|
-
});
|
|
168401
|
-
if (!uploadUrlResp.ok || !uploadUrlResp.upload_url || !uploadUrlResp.file_id) {
|
|
168402
|
-
throw new Error(`Failed to get Slack upload URL: ${uploadUrlResp.error ?? "unknown error"}`);
|
|
168403
|
-
}
|
|
168404
|
-
const uploadResp = await fetch(uploadUrlResp.upload_url, {
|
|
168405
|
-
method: "POST",
|
|
168406
|
-
...uploadMimeType ? { headers: { "Content-Type": uploadMimeType } } : {},
|
|
168407
|
-
body: buffer
|
|
168408
|
-
});
|
|
168409
|
-
if (!uploadResp.ok) {
|
|
168410
|
-
throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
|
|
168411
|
-
}
|
|
168412
|
-
const threadTs = resolveSlackOutboundThreadTs({
|
|
168413
|
-
chatId: msg.chatId,
|
|
168414
|
-
threadId: msg.threadId,
|
|
168415
|
-
replyToMessageId: msg.replyToMessageId
|
|
168416
|
-
});
|
|
168417
|
-
const completeResp = await slackClient.files.completeUploadExternal({
|
|
168418
|
-
files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
|
|
168419
|
-
channel_id: msg.chatId,
|
|
168420
|
-
...msg.text.trim() ? { initial_comment: msg.text } : {},
|
|
168421
|
-
...threadTs ? { thread_ts: threadTs } : {}
|
|
168422
|
-
});
|
|
168423
|
-
if (!completeResp.ok) {
|
|
168424
|
-
throw new Error(`Failed to complete Slack upload: ${completeResp.error ?? "unknown error"}`);
|
|
168425
|
-
}
|
|
168426
|
-
return { messageId: uploadUrlResp.file_id };
|
|
168427
|
-
}
|
|
168428
|
-
var init_file_upload = __esm(() => {
|
|
168429
|
-
init_utils5();
|
|
168430
|
-
});
|
|
168431
|
-
|
|
168432
|
-
// src/channels/slack/inbound-debounce.ts
|
|
168433
|
-
function buildSlackDebounceKey(rawMessage, accountId) {
|
|
168434
|
-
const senderId = rawMessage.user ?? rawMessage.bot_id ?? null;
|
|
168435
|
-
if (!senderId)
|
|
168436
|
-
return null;
|
|
168437
|
-
const messageTs = rawMessage.ts ?? rawMessage.event_ts;
|
|
168438
|
-
const isDm = rawMessage.channel.startsWith("D");
|
|
168439
|
-
const scope = rawMessage.thread_ts ? `${rawMessage.channel}:${rawMessage.thread_ts}` : rawMessage.parent_user_id && messageTs ? `${rawMessage.channel}:maybe-thread:${messageTs}` : messageTs && !isDm ? `${rawMessage.channel}:${messageTs}` : rawMessage.channel;
|
|
168440
|
-
return `slack:${accountId}:${scope}:${senderId}`;
|
|
168441
|
-
}
|
|
168442
|
-
function buildTopLevelSlackConversationKey(rawMessage, accountId) {
|
|
168443
|
-
if (rawMessage.thread_ts || rawMessage.parent_user_id)
|
|
168444
|
-
return null;
|
|
168445
|
-
if (rawMessage.channel.startsWith("D"))
|
|
168446
|
-
return null;
|
|
168447
|
-
const senderId = rawMessage.user ?? rawMessage.bot_id;
|
|
168448
|
-
return senderId ? `slack:${accountId}:${rawMessage.channel}:${senderId}` : null;
|
|
168449
|
-
}
|
|
168450
|
-
function resolveSlackInboundDebounceMs(config3) {
|
|
168451
|
-
const raw = process.env.LETTA_SLACK_INBOUND_DEBOUNCE_MS;
|
|
168452
|
-
if (typeof raw === "string" && raw.trim() !== "") {
|
|
168453
|
-
const envOverride = Number(raw);
|
|
168454
|
-
if (Number.isFinite(envOverride) && envOverride >= 0) {
|
|
168455
|
-
return Math.trunc(envOverride);
|
|
168456
|
-
}
|
|
168457
|
-
}
|
|
168458
|
-
const fromConfig = config3.inboundDebounceMs;
|
|
168459
|
-
return typeof fromConfig === "number" && Number.isFinite(fromConfig) && fromConfig >= 0 ? Math.trunc(fromConfig) : 0;
|
|
168413
|
+
// src/channels/slack/attachment-stream.ts
|
|
168414
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
168415
|
+
import { mkdir as mkdir4, open as open2, rename, rm as rm2 } from "node:fs/promises";
|
|
168416
|
+
import { join as join12 } from "node:path";
|
|
168417
|
+
function sanitizeFileName(name) {
|
|
168418
|
+
const normalized = name.trim().replace(/[^\w.-]+/g, "_");
|
|
168419
|
+
return normalized.length > 0 ? normalized : "attachment";
|
|
168460
168420
|
}
|
|
168461
|
-
function
|
|
168462
|
-
const
|
|
168463
|
-
|
|
168464
|
-
const
|
|
168465
|
-
const
|
|
168466
|
-
const
|
|
168467
|
-
|
|
168468
|
-
|
|
168469
|
-
|
|
168470
|
-
|
|
168471
|
-
|
|
168472
|
-
|
|
168473
|
-
if (
|
|
168474
|
-
|
|
168475
|
-
}
|
|
168476
|
-
}
|
|
168477
|
-
function dedupeEntries(entries) {
|
|
168478
|
-
const indexByMessageKey = new Map;
|
|
168479
|
-
const deduped = [];
|
|
168480
|
-
for (const entry of entries) {
|
|
168481
|
-
const messageId = entry.inbound.messageId;
|
|
168482
|
-
const messageKey = isNonEmptyString2(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
|
|
168483
|
-
if (!messageKey) {
|
|
168484
|
-
deduped.push(entry);
|
|
168485
|
-
continue;
|
|
168421
|
+
async function saveSlackAttachmentStream(params) {
|
|
168422
|
+
const inboundDir = join12(getChannelDir("slack"), "inbound", sanitizeFileName(params.accountId));
|
|
168423
|
+
await mkdir4(inboundDir, { recursive: true });
|
|
168424
|
+
const filePath = join12(inboundDir, `${Date.now()}-${randomUUID8()}-${sanitizeFileName(params.fileName)}`);
|
|
168425
|
+
const temporaryPath = `${filePath}.partial`;
|
|
168426
|
+
const fileHandle = await open2(temporaryPath, "wx");
|
|
168427
|
+
const reader = params.body.getReader();
|
|
168428
|
+
let sizeBytes = 0;
|
|
168429
|
+
let completed = false;
|
|
168430
|
+
try {
|
|
168431
|
+
while (true) {
|
|
168432
|
+
const { done, value } = await reader.read();
|
|
168433
|
+
if (done) {
|
|
168434
|
+
break;
|
|
168486
168435
|
}
|
|
168487
|
-
|
|
168488
|
-
if (existingIndex === undefined) {
|
|
168489
|
-
indexByMessageKey.set(messageKey, deduped.length);
|
|
168490
|
-
deduped.push(entry);
|
|
168436
|
+
if (!value?.byteLength) {
|
|
168491
168437
|
continue;
|
|
168492
168438
|
}
|
|
168493
|
-
|
|
168494
|
-
if (
|
|
168495
|
-
|
|
168439
|
+
sizeBytes += value.byteLength;
|
|
168440
|
+
if (params.maxBytes !== undefined && sizeBytes > params.maxBytes) {
|
|
168441
|
+
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment exceeds automatic download limit (${params.maxBytes} bytes).`);
|
|
168496
168442
|
}
|
|
168497
|
-
|
|
168498
|
-
|
|
168499
|
-
|
|
168500
|
-
|
|
168501
|
-
|
|
168502
|
-
buildKey: ({ raw }) => buildSlackDebounceKey(raw, config3.accountId),
|
|
168503
|
-
shouldDebounce: ({ inbound }) => !inbound.attachments?.length && !inbound.reaction,
|
|
168504
|
-
onFlush: async (entries) => {
|
|
168505
|
-
const dedupedEntries = dedupeEntries(entries);
|
|
168506
|
-
const last = dedupedEntries[dedupedEntries.length - 1];
|
|
168507
|
-
if (!last)
|
|
168508
|
-
return;
|
|
168509
|
-
const flushedKey = buildSlackDebounceKey(last.raw, config3.accountId);
|
|
168510
|
-
const conversationKey = buildTopLevelSlackConversationKey(last.raw, config3.accountId);
|
|
168511
|
-
if (flushedKey && conversationKey) {
|
|
168512
|
-
const pending = pendingTopLevelKeys.get(conversationKey);
|
|
168513
|
-
pending?.delete(flushedKey);
|
|
168514
|
-
if (pending?.size === 0)
|
|
168515
|
-
pendingTopLevelKeys.delete(conversationKey);
|
|
168516
|
-
}
|
|
168517
|
-
if (isNonEmptyString2(last.inbound.messageId)) {
|
|
168518
|
-
const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
|
|
168519
|
-
pruneAppMentionMaps(Date.now());
|
|
168520
|
-
if (last.opts.source === "app_mention") {
|
|
168521
|
-
appMentionDispatchedKeys.set(seenKey, Date.now() + APP_MENTION_RETRY_TTL_MS);
|
|
168522
|
-
} else if (appMentionDispatchedKeys.has(seenKey)) {
|
|
168523
|
-
appMentionDispatchedKeys.delete(seenKey);
|
|
168524
|
-
appMentionRetryKeys.delete(seenKey);
|
|
168525
|
-
return;
|
|
168443
|
+
let offset = 0;
|
|
168444
|
+
while (offset < value.byteLength) {
|
|
168445
|
+
const { bytesWritten } = await fileHandle.write(value, offset, value.byteLength - offset);
|
|
168446
|
+
if (bytesWritten <= 0) {
|
|
168447
|
+
throw new Error("Slack attachment write made no progress.");
|
|
168526
168448
|
}
|
|
168527
|
-
|
|
168449
|
+
offset += bytesWritten;
|
|
168528
168450
|
}
|
|
168529
|
-
|
|
168530
|
-
|
|
168451
|
+
}
|
|
168452
|
+
completed = true;
|
|
168453
|
+
} finally {
|
|
168454
|
+
if (!completed) {
|
|
168455
|
+
await reader.cancel().catch(() => {
|
|
168531
168456
|
return;
|
|
168532
|
-
|
|
168533
|
-
`);
|
|
168534
|
-
try {
|
|
168535
|
-
await onMessage({
|
|
168536
|
-
...last.inbound,
|
|
168537
|
-
text,
|
|
168538
|
-
isMention: dedupedEntries.some((entry) => entry.opts.wasMentioned || entry.inbound.isMention === true)
|
|
168539
|
-
});
|
|
168540
|
-
} catch (error54) {
|
|
168541
|
-
console.error("[Slack] Error handling debounced inbound message:", error54);
|
|
168542
|
-
}
|
|
168543
|
-
},
|
|
168544
|
-
onError: (error54) => {
|
|
168545
|
-
console.error("[Slack] Inbound debounce flush failed:", error54 instanceof Error ? error54.message : error54);
|
|
168457
|
+
});
|
|
168546
168458
|
}
|
|
168547
|
-
|
|
168548
|
-
|
|
168549
|
-
|
|
168550
|
-
|
|
168551
|
-
|
|
168552
|
-
|
|
168553
|
-
|
|
168554
|
-
|
|
168555
|
-
|
|
168556
|
-
|
|
168557
|
-
} catch {}
|
|
168558
|
-
}
|
|
168559
|
-
}
|
|
168560
|
-
if (canDebounce && debounceKey && conversationKey) {
|
|
168561
|
-
const pending = pendingTopLevelKeys.get(conversationKey) ?? new Set;
|
|
168562
|
-
pending.add(debounceKey);
|
|
168563
|
-
pendingTopLevelKeys.set(conversationKey, pending);
|
|
168564
|
-
}
|
|
168565
|
-
await debouncer.enqueue(entry);
|
|
168566
|
-
},
|
|
168567
|
-
rememberAppMentionRetry(seenKey) {
|
|
168568
|
-
const now = Date.now();
|
|
168569
|
-
pruneAppMentionMaps(now);
|
|
168570
|
-
appMentionRetryKeys.set(seenKey, now + APP_MENTION_RETRY_TTL_MS);
|
|
168571
|
-
},
|
|
168572
|
-
consumeAppMentionRetry(seenKey) {
|
|
168573
|
-
pruneAppMentionMaps(Date.now());
|
|
168574
|
-
if (!appMentionRetryKeys.has(seenKey))
|
|
168575
|
-
return false;
|
|
168576
|
-
appMentionRetryKeys.delete(seenKey);
|
|
168577
|
-
return true;
|
|
168578
|
-
},
|
|
168579
|
-
clear() {
|
|
168580
|
-
pendingTopLevelKeys.clear();
|
|
168581
|
-
appMentionRetryKeys.clear();
|
|
168582
|
-
appMentionDispatchedKeys.clear();
|
|
168459
|
+
try {
|
|
168460
|
+
reader.releaseLock();
|
|
168461
|
+
} catch {}
|
|
168462
|
+
await fileHandle.close().catch(() => {
|
|
168463
|
+
return;
|
|
168464
|
+
});
|
|
168465
|
+
if (!completed) {
|
|
168466
|
+
await rm2(temporaryPath, { force: true }).catch(() => {
|
|
168467
|
+
return;
|
|
168468
|
+
});
|
|
168583
168469
|
}
|
|
168584
|
-
}
|
|
168470
|
+
}
|
|
168471
|
+
try {
|
|
168472
|
+
await rename(temporaryPath, filePath);
|
|
168473
|
+
} catch (error54) {
|
|
168474
|
+
await rm2(temporaryPath, { force: true }).catch(() => {
|
|
168475
|
+
return;
|
|
168476
|
+
});
|
|
168477
|
+
throw error54;
|
|
168478
|
+
}
|
|
168479
|
+
return { localPath: filePath, sizeBytes };
|
|
168585
168480
|
}
|
|
168586
|
-
var
|
|
168587
|
-
var
|
|
168588
|
-
|
|
168481
|
+
var SlackAttachmentDownloadError;
|
|
168482
|
+
var init_attachment_stream = __esm(() => {
|
|
168483
|
+
init_config2();
|
|
168484
|
+
SlackAttachmentDownloadError = class SlackAttachmentDownloadError extends Error {
|
|
168485
|
+
reason;
|
|
168486
|
+
constructor(reason, message) {
|
|
168487
|
+
super(message);
|
|
168488
|
+
this.reason = reason;
|
|
168489
|
+
this.name = "SlackAttachmentDownloadError";
|
|
168490
|
+
}
|
|
168491
|
+
};
|
|
168589
168492
|
});
|
|
168590
168493
|
|
|
168591
168494
|
// src/channels/slack/media.ts
|
|
168592
|
-
import {
|
|
168593
|
-
|
|
168594
|
-
|
|
168595
|
-
async function mapSlackThreadMessage(message, attachmentOptions) {
|
|
168596
|
-
const attachments = await resolveSlackMessageAttachments(message, attachmentOptions);
|
|
168495
|
+
import { basename as basename7, extname as extname3 } from "node:path";
|
|
168496
|
+
async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId) {
|
|
168497
|
+
const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
|
|
168597
168498
|
return {
|
|
168598
168499
|
text: resolveSlackThreadMessageText(message),
|
|
168599
168500
|
userId: isNonEmptyString3(message.user) ? message.user : undefined,
|
|
@@ -168694,10 +168595,6 @@ function assertSlackFileUrl(rawUrl) {
|
|
|
168694
168595
|
}
|
|
168695
168596
|
return parsed;
|
|
168696
168597
|
}
|
|
168697
|
-
function sanitizeFileName(name) {
|
|
168698
|
-
const normalized = name.trim().replace(/[^\w.-]+/g, "_");
|
|
168699
|
-
return normalized.length > 0 ? normalized : "attachment";
|
|
168700
|
-
}
|
|
168701
168598
|
function extensionForMimeType2(mimeType) {
|
|
168702
168599
|
switch (mimeType?.toLowerCase()) {
|
|
168703
168600
|
case "image/png":
|
|
@@ -168735,7 +168632,7 @@ function resolveMimeType(name, fallback) {
|
|
|
168735
168632
|
if (fallback) {
|
|
168736
168633
|
return fallback;
|
|
168737
168634
|
}
|
|
168738
|
-
switch (
|
|
168635
|
+
switch (extname3(name).toLowerCase()) {
|
|
168739
168636
|
case ".png":
|
|
168740
168637
|
return "image/png";
|
|
168741
168638
|
case ".jpg":
|
|
@@ -168811,51 +168708,93 @@ async function fetchWithSlackAuth(url2, token) {
|
|
|
168811
168708
|
}
|
|
168812
168709
|
return fetch(resolved.href, { redirect: "follow" });
|
|
168813
168710
|
}
|
|
168814
|
-
|
|
168815
|
-
const
|
|
168816
|
-
|
|
168817
|
-
|
|
168818
|
-
|
|
168819
|
-
|
|
168711
|
+
function resolveSlackAttachmentFileName(params) {
|
|
168712
|
+
const hintedName = params.file.name ?? (params.url ? basename7(new URL(params.url).pathname) : undefined) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
|
|
168713
|
+
return extname3(hintedName) || !params.mimeType ? hintedName : `${hintedName}${extensionForMimeType2(params.mimeType)}`;
|
|
168714
|
+
}
|
|
168715
|
+
function resolveSlackAttachmentMimeType(params) {
|
|
168716
|
+
const preferredMimeType = params.responseMimeType && !isGenericSlackMimeType(params.responseMimeType) ? params.responseMimeType : params.file.mimetype && !isGenericSlackMimeType(params.file.mimetype) ? params.file.mimetype : undefined;
|
|
168717
|
+
return resolveMimeType(params.fileName, preferredMimeType);
|
|
168718
|
+
}
|
|
168719
|
+
function createUndownloadedSlackAttachment(params) {
|
|
168720
|
+
const fileName = resolveSlackAttachmentFileName({ file: params.file });
|
|
168721
|
+
const mimeType = resolveSlackAttachmentMimeType({
|
|
168722
|
+
file: params.file,
|
|
168723
|
+
fileName
|
|
168724
|
+
});
|
|
168725
|
+
return {
|
|
168726
|
+
id: params.file.id,
|
|
168727
|
+
name: fileName,
|
|
168728
|
+
mimeType,
|
|
168729
|
+
sizeBytes: params.file.size,
|
|
168730
|
+
kind: resolveAttachmentKind(mimeType),
|
|
168731
|
+
sourceMessageId: params.sourceMessageId,
|
|
168732
|
+
...params.sourceThreadId ? { sourceThreadId: params.sourceThreadId } : {},
|
|
168733
|
+
downloadReason: params.reason,
|
|
168734
|
+
...params.reason === "exceeds_auto_download_limit" ? { autoDownloadLimitBytes: MAX_SLACK_ATTACHMENT_BYTES } : {}
|
|
168735
|
+
};
|
|
168820
168736
|
}
|
|
168821
|
-
async function
|
|
168737
|
+
async function materializeSlackAttachment(params) {
|
|
168738
|
+
if (params.maxBytes !== undefined && typeof params.file.size === "number" && params.file.size > params.maxBytes) {
|
|
168739
|
+
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${params.file.size} bytes; automatic download limit is ${params.maxBytes} bytes.`);
|
|
168740
|
+
}
|
|
168822
168741
|
const url2 = params.file.url_private_download ?? params.file.url_private;
|
|
168823
168742
|
if (!url2) {
|
|
168824
|
-
|
|
168743
|
+
throw new SlackAttachmentDownloadError("missing_download_url", "Slack attachment does not include a private download URL.");
|
|
168825
168744
|
}
|
|
168826
|
-
const response = await fetchWithSlackAuth(url2, params.token)
|
|
168745
|
+
const response = await fetchWithSlackAuth(url2, params.token).catch((error54) => {
|
|
168746
|
+
throw new SlackAttachmentDownloadError("download_failed", error54 instanceof Error ? error54.message : "Slack attachment fetch failed.");
|
|
168747
|
+
});
|
|
168827
168748
|
if (!response.ok) {
|
|
168828
|
-
|
|
168749
|
+
throw new SlackAttachmentDownloadError("download_failed", `Slack attachment fetch failed with HTTP ${response.status}.`);
|
|
168829
168750
|
}
|
|
168830
|
-
const
|
|
168831
|
-
|
|
168832
|
-
|
|
168751
|
+
const contentLengthHeader = response.headers.get("content-length");
|
|
168752
|
+
const contentLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
|
|
168753
|
+
if (params.maxBytes !== undefined && contentLength !== undefined && Number.isFinite(contentLength) && contentLength > params.maxBytes) {
|
|
168754
|
+
await response.body?.cancel().catch(() => {
|
|
168755
|
+
return;
|
|
168756
|
+
});
|
|
168757
|
+
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${contentLength} bytes; automatic download limit is ${params.maxBytes} bytes.`);
|
|
168833
168758
|
}
|
|
168834
|
-
const buffer = Buffer.from(arrayBuffer);
|
|
168835
|
-
const hintedName = params.file.name ?? basename8(new URL(url2).pathname) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
|
|
168836
168759
|
const responseMimeType = response.headers.get("content-type")?.split(";")[0]?.trim() || undefined;
|
|
168837
|
-
const
|
|
168838
|
-
|
|
168839
|
-
|
|
168840
|
-
|
|
168841
|
-
const
|
|
168760
|
+
const hintedName = resolveSlackAttachmentFileName({
|
|
168761
|
+
file: params.file,
|
|
168762
|
+
url: url2
|
|
168763
|
+
});
|
|
168764
|
+
const mimeType = resolveSlackAttachmentMimeType({
|
|
168765
|
+
file: params.file,
|
|
168766
|
+
fileName: hintedName,
|
|
168767
|
+
responseMimeType
|
|
168768
|
+
});
|
|
168769
|
+
const fileName = resolveSlackAttachmentFileName({
|
|
168770
|
+
file: params.file,
|
|
168771
|
+
url: url2,
|
|
168772
|
+
mimeType
|
|
168773
|
+
});
|
|
168774
|
+
if (!response.body) {
|
|
168775
|
+
throw new SlackAttachmentDownloadError("download_failed", "Slack attachment response did not include a body.");
|
|
168776
|
+
}
|
|
168777
|
+
const saved = await saveSlackAttachmentStream({
|
|
168842
168778
|
accountId: params.accountId,
|
|
168843
168779
|
fileName,
|
|
168844
|
-
|
|
168780
|
+
body: response.body,
|
|
168781
|
+
maxBytes: params.maxBytes
|
|
168845
168782
|
});
|
|
168846
168783
|
const kind = resolveAttachmentKind(mimeType);
|
|
168847
168784
|
const attachment = {
|
|
168848
168785
|
id: params.file.id,
|
|
168849
168786
|
name: fileName,
|
|
168850
168787
|
mimeType,
|
|
168851
|
-
sizeBytes:
|
|
168788
|
+
sizeBytes: saved.sizeBytes,
|
|
168852
168789
|
kind,
|
|
168853
|
-
localPath
|
|
168790
|
+
localPath: saved.localPath,
|
|
168791
|
+
sourceMessageId: params.sourceMessageId,
|
|
168792
|
+
...params.sourceThreadId ? { sourceThreadId: params.sourceThreadId } : {}
|
|
168854
168793
|
};
|
|
168855
168794
|
if (kind === "audio" && params.transcribeVoice) {
|
|
168856
168795
|
const { isTranscriptionConfigured: isTranscriptionConfigured2, transcribeAudioFile: transcribeAudioFile2 } = await Promise.resolve().then(() => (init_transcription(), exports_transcription));
|
|
168857
168796
|
if (isTranscriptionConfigured2()) {
|
|
168858
|
-
const result = await transcribeAudioFile2(localPath);
|
|
168797
|
+
const result = await transcribeAudioFile2(saved.localPath);
|
|
168859
168798
|
if (result.success && result.text) {
|
|
168860
168799
|
attachment.transcription = result.text;
|
|
168861
168800
|
} else if (result.error) {
|
|
@@ -168906,13 +168845,28 @@ async function resolveSlackFilesAsAttachments(params) {
|
|
|
168906
168845
|
if (params.files.length === 0) {
|
|
168907
168846
|
return [];
|
|
168908
168847
|
}
|
|
168909
|
-
const resolved = await Promise.all(params.files.map((file3) =>
|
|
168910
|
-
|
|
168911
|
-
|
|
168912
|
-
|
|
168913
|
-
|
|
168914
|
-
|
|
168915
|
-
|
|
168848
|
+
const resolved = await Promise.all(params.files.map(async (file3) => {
|
|
168849
|
+
try {
|
|
168850
|
+
return await materializeSlackAttachment({
|
|
168851
|
+
accountId: params.accountId,
|
|
168852
|
+
token: params.token,
|
|
168853
|
+
file: file3,
|
|
168854
|
+
sourceMessageId: params.sourceMessageId,
|
|
168855
|
+
sourceThreadId: params.sourceThreadId,
|
|
168856
|
+
maxBytes: MAX_SLACK_ATTACHMENT_BYTES,
|
|
168857
|
+
transcribeVoice: params.transcribeVoice
|
|
168858
|
+
});
|
|
168859
|
+
} catch (error54) {
|
|
168860
|
+
const reason = error54 instanceof SlackAttachmentDownloadError ? error54.reason : "download_failed";
|
|
168861
|
+
return createUndownloadedSlackAttachment({
|
|
168862
|
+
file: file3,
|
|
168863
|
+
sourceMessageId: params.sourceMessageId,
|
|
168864
|
+
sourceThreadId: params.sourceThreadId,
|
|
168865
|
+
reason
|
|
168866
|
+
});
|
|
168867
|
+
}
|
|
168868
|
+
}));
|
|
168869
|
+
return resolved;
|
|
168916
168870
|
}
|
|
168917
168871
|
function resolveSlackThreadAttachmentOptions(params) {
|
|
168918
168872
|
if (!isNonEmptyString3(params.accountId) || !isNonEmptyString3(params.token)) {
|
|
@@ -168933,7 +168887,7 @@ function hasSlackThreadMessageContent(message, attachmentOptions) {
|
|
|
168933
168887
|
function hasHydratedSlackThreadMessageContent(message) {
|
|
168934
168888
|
return message.text.length > 0 || Boolean(message.attachments?.length);
|
|
168935
168889
|
}
|
|
168936
|
-
async function resolveSlackMessageAttachments(message, attachmentOptions) {
|
|
168890
|
+
async function resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId) {
|
|
168937
168891
|
if (!attachmentOptions) {
|
|
168938
168892
|
return [];
|
|
168939
168893
|
}
|
|
@@ -168941,14 +168895,19 @@ async function resolveSlackMessageAttachments(message, attachmentOptions) {
|
|
|
168941
168895
|
accountId: attachmentOptions.accountId,
|
|
168942
168896
|
token: attachmentOptions.token,
|
|
168943
168897
|
files: collectSlackFiles(message),
|
|
168898
|
+
sourceMessageId: message.ts,
|
|
168899
|
+
sourceThreadId: sourceThreadId ?? (isNonEmptyString3(message.thread_ts) ? message.thread_ts : null),
|
|
168944
168900
|
transcribeVoice: attachmentOptions.transcribeVoice
|
|
168945
168901
|
});
|
|
168946
168902
|
}
|
|
168947
168903
|
async function resolveSlackInboundAttachments(params) {
|
|
168904
|
+
const rawEvent = asRecord4(params.rawEvent);
|
|
168948
168905
|
return resolveSlackFilesAsAttachments({
|
|
168949
168906
|
accountId: params.accountId,
|
|
168950
168907
|
token: params.token,
|
|
168951
168908
|
files: collectSlackFiles(params.rawEvent),
|
|
168909
|
+
sourceMessageId: isNonEmptyString3(rawEvent?.ts) ? rawEvent.ts : undefined,
|
|
168910
|
+
sourceThreadId: isNonEmptyString3(rawEvent?.thread_ts) ? rawEvent.thread_ts : null,
|
|
168952
168911
|
transcribeVoice: params.transcribeVoice
|
|
168953
168912
|
});
|
|
168954
168913
|
}
|
|
@@ -168970,7 +168929,7 @@ async function resolveSlackCurrentMessageAttachments(params) {
|
|
|
168970
168929
|
});
|
|
168971
168930
|
const message = (response.messages ?? []).find((entry) => entry.ts === params.messageTs);
|
|
168972
168931
|
if (message) {
|
|
168973
|
-
return resolveSlackMessageAttachments(message, attachmentOptions);
|
|
168932
|
+
return resolveSlackMessageAttachments(message, attachmentOptions, params.threadTs);
|
|
168974
168933
|
}
|
|
168975
168934
|
const nextCursor = response.response_metadata?.next_cursor;
|
|
168976
168935
|
cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
|
|
@@ -168996,7 +168955,7 @@ async function resolveSlackThreadStarter(params) {
|
|
|
168996
168955
|
if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
|
|
168997
168956
|
return null;
|
|
168998
168957
|
}
|
|
168999
|
-
const mapped3 = await mapSlackThreadMessage(message, attachmentOptions);
|
|
168958
|
+
const mapped3 = await mapSlackThreadMessage(message, attachmentOptions, params.threadTs);
|
|
169000
168959
|
return hasHydratedSlackThreadMessageContent(mapped3) ? mapped3 : null;
|
|
169001
168960
|
} catch {
|
|
169002
168961
|
return null;
|
|
@@ -169041,7 +169000,7 @@ async function resolveSlackThreadHistory(params) {
|
|
|
169041
169000
|
const nextCursor = response.response_metadata?.next_cursor;
|
|
169042
169001
|
cursor = typeof nextCursor === "string" && nextCursor.trim().length > 0 ? nextCursor.trim() : undefined;
|
|
169043
169002
|
} while (cursor);
|
|
169044
|
-
const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions)));
|
|
169003
|
+
const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions, params.threadTs)));
|
|
169045
169004
|
return mapped3.filter(hasHydratedSlackThreadMessageContent);
|
|
169046
169005
|
} catch {
|
|
169047
169006
|
return [];
|
|
@@ -169075,7 +169034,7 @@ async function resolveSlackChannelHistory(params) {
|
|
|
169075
169034
|
}
|
|
169076
169035
|
var MAX_SLACK_ATTACHMENTS = 8, MAX_SLACK_ATTACHMENT_BYTES, ALLOWED_SLACK_HOST_SUFFIXES;
|
|
169077
169036
|
var init_media2 = __esm(() => {
|
|
169078
|
-
|
|
169037
|
+
init_attachment_stream();
|
|
169079
169038
|
MAX_SLACK_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
169080
169039
|
ALLOWED_SLACK_HOST_SUFFIXES = [
|
|
169081
169040
|
"slack.com",
|
|
@@ -169084,6 +169043,286 @@ var init_media2 = __esm(() => {
|
|
|
169084
169043
|
];
|
|
169085
169044
|
});
|
|
169086
169045
|
|
|
169046
|
+
// src/channels/slack/attachment-download.ts
|
|
169047
|
+
function isNonEmptyString4(value) {
|
|
169048
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
169049
|
+
}
|
|
169050
|
+
async function resolveCanonicalSlackMessage(params) {
|
|
169051
|
+
if (isNonEmptyString4(params.threadTs)) {
|
|
169052
|
+
let cursor;
|
|
169053
|
+
do {
|
|
169054
|
+
const response2 = await params.client.conversations.replies({
|
|
169055
|
+
channel: params.channelId,
|
|
169056
|
+
ts: params.threadTs,
|
|
169057
|
+
limit: 200,
|
|
169058
|
+
inclusive: true,
|
|
169059
|
+
...cursor ? { cursor } : {}
|
|
169060
|
+
});
|
|
169061
|
+
const message = (response2.messages ?? []).find((entry) => entry.ts === params.messageTs);
|
|
169062
|
+
if (message) {
|
|
169063
|
+
return message;
|
|
169064
|
+
}
|
|
169065
|
+
const nextCursor = response2.response_metadata?.next_cursor;
|
|
169066
|
+
cursor = isNonEmptyString4(nextCursor) ? nextCursor.trim() : undefined;
|
|
169067
|
+
} while (cursor);
|
|
169068
|
+
return null;
|
|
169069
|
+
}
|
|
169070
|
+
const response = await params.client.conversations.history({
|
|
169071
|
+
channel: params.channelId,
|
|
169072
|
+
oldest: params.messageTs,
|
|
169073
|
+
latest: params.messageTs,
|
|
169074
|
+
inclusive: true,
|
|
169075
|
+
limit: 1
|
|
169076
|
+
});
|
|
169077
|
+
return (response.messages ?? []).find((entry) => entry.ts === params.messageTs) ?? null;
|
|
169078
|
+
}
|
|
169079
|
+
async function downloadSlackAttachmentById(params) {
|
|
169080
|
+
const message = await resolveCanonicalSlackMessage(params);
|
|
169081
|
+
if (!message) {
|
|
169082
|
+
throw new Error(`Slack message ${params.messageTs} was not found in chat ${params.channelId}.`);
|
|
169083
|
+
}
|
|
169084
|
+
const file3 = collectSlackFiles(message).find((entry) => entry.id === params.attachmentId);
|
|
169085
|
+
if (!file3) {
|
|
169086
|
+
throw new Error(`Slack attachment ${params.attachmentId} is not attached to message ${params.messageTs}.`);
|
|
169087
|
+
}
|
|
169088
|
+
return await materializeSlackAttachment({
|
|
169089
|
+
accountId: params.accountId,
|
|
169090
|
+
token: params.token,
|
|
169091
|
+
file: file3,
|
|
169092
|
+
sourceMessageId: params.messageTs,
|
|
169093
|
+
sourceThreadId: params.threadTs ?? null
|
|
169094
|
+
});
|
|
169095
|
+
}
|
|
169096
|
+
var init_attachment_download = __esm(() => {
|
|
169097
|
+
init_media2();
|
|
169098
|
+
});
|
|
169099
|
+
|
|
169100
|
+
// src/channels/slack/file-upload.ts
|
|
169101
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
169102
|
+
import { basename as basename8, extname as extname4 } from "node:path";
|
|
169103
|
+
function resolveUploadMimeType(filePath) {
|
|
169104
|
+
switch (extname4(filePath).toLowerCase()) {
|
|
169105
|
+
case ".png":
|
|
169106
|
+
return "image/png";
|
|
169107
|
+
case ".jpg":
|
|
169108
|
+
case ".jpeg":
|
|
169109
|
+
return "image/jpeg";
|
|
169110
|
+
case ".gif":
|
|
169111
|
+
return "image/gif";
|
|
169112
|
+
case ".webp":
|
|
169113
|
+
return "image/webp";
|
|
169114
|
+
case ".pdf":
|
|
169115
|
+
return "application/pdf";
|
|
169116
|
+
case ".txt":
|
|
169117
|
+
return "text/plain";
|
|
169118
|
+
case ".md":
|
|
169119
|
+
return "text/markdown";
|
|
169120
|
+
default:
|
|
169121
|
+
return;
|
|
169122
|
+
}
|
|
169123
|
+
}
|
|
169124
|
+
async function uploadSlackFile(slackClient, msg) {
|
|
169125
|
+
if (!msg.mediaPath) {
|
|
169126
|
+
throw new Error("mediaPath is required for Slack file uploads.");
|
|
169127
|
+
}
|
|
169128
|
+
const buffer = await readFile4(msg.mediaPath);
|
|
169129
|
+
const uploadFileName = msg.fileName ?? basename8(msg.mediaPath);
|
|
169130
|
+
const uploadTitle = msg.title ?? uploadFileName;
|
|
169131
|
+
const uploadMimeType = resolveUploadMimeType(uploadFileName);
|
|
169132
|
+
const uploadUrlResp = await slackClient.files.getUploadURLExternal({
|
|
169133
|
+
filename: uploadFileName,
|
|
169134
|
+
length: buffer.length
|
|
169135
|
+
});
|
|
169136
|
+
if (!uploadUrlResp.ok || !uploadUrlResp.upload_url || !uploadUrlResp.file_id) {
|
|
169137
|
+
throw new Error(`Failed to get Slack upload URL: ${uploadUrlResp.error ?? "unknown error"}`);
|
|
169138
|
+
}
|
|
169139
|
+
const uploadResp = await fetch(uploadUrlResp.upload_url, {
|
|
169140
|
+
method: "POST",
|
|
169141
|
+
...uploadMimeType ? { headers: { "Content-Type": uploadMimeType } } : {},
|
|
169142
|
+
body: buffer
|
|
169143
|
+
});
|
|
169144
|
+
if (!uploadResp.ok) {
|
|
169145
|
+
throw new Error(`Failed to upload Slack file: HTTP ${uploadResp.status}`);
|
|
169146
|
+
}
|
|
169147
|
+
const threadTs = resolveSlackOutboundThreadTs({
|
|
169148
|
+
chatId: msg.chatId,
|
|
169149
|
+
threadId: msg.threadId,
|
|
169150
|
+
replyToMessageId: msg.replyToMessageId
|
|
169151
|
+
});
|
|
169152
|
+
const completeResp = await slackClient.files.completeUploadExternal({
|
|
169153
|
+
files: [{ id: uploadUrlResp.file_id, title: uploadTitle }],
|
|
169154
|
+
channel_id: msg.chatId,
|
|
169155
|
+
...msg.text.trim() ? { initial_comment: msg.text } : {},
|
|
169156
|
+
...threadTs ? { thread_ts: threadTs } : {}
|
|
169157
|
+
});
|
|
169158
|
+
if (!completeResp.ok) {
|
|
169159
|
+
throw new Error(`Failed to complete Slack upload: ${completeResp.error ?? "unknown error"}`);
|
|
169160
|
+
}
|
|
169161
|
+
return { messageId: uploadUrlResp.file_id };
|
|
169162
|
+
}
|
|
169163
|
+
var init_file_upload = __esm(() => {
|
|
169164
|
+
init_utils5();
|
|
169165
|
+
});
|
|
169166
|
+
|
|
169167
|
+
// src/channels/slack/inbound-debounce.ts
|
|
169168
|
+
function buildSlackDebounceKey(rawMessage, accountId) {
|
|
169169
|
+
const senderId = rawMessage.user ?? rawMessage.bot_id ?? null;
|
|
169170
|
+
if (!senderId)
|
|
169171
|
+
return null;
|
|
169172
|
+
const messageTs = rawMessage.ts ?? rawMessage.event_ts;
|
|
169173
|
+
const isDm = rawMessage.channel.startsWith("D");
|
|
169174
|
+
const scope = rawMessage.thread_ts ? `${rawMessage.channel}:${rawMessage.thread_ts}` : rawMessage.parent_user_id && messageTs ? `${rawMessage.channel}:maybe-thread:${messageTs}` : messageTs && !isDm ? `${rawMessage.channel}:${messageTs}` : rawMessage.channel;
|
|
169175
|
+
return `slack:${accountId}:${scope}:${senderId}`;
|
|
169176
|
+
}
|
|
169177
|
+
function buildTopLevelSlackConversationKey(rawMessage, accountId) {
|
|
169178
|
+
if (rawMessage.thread_ts || rawMessage.parent_user_id)
|
|
169179
|
+
return null;
|
|
169180
|
+
if (rawMessage.channel.startsWith("D"))
|
|
169181
|
+
return null;
|
|
169182
|
+
const senderId = rawMessage.user ?? rawMessage.bot_id;
|
|
169183
|
+
return senderId ? `slack:${accountId}:${rawMessage.channel}:${senderId}` : null;
|
|
169184
|
+
}
|
|
169185
|
+
function resolveSlackInboundDebounceMs(config3) {
|
|
169186
|
+
const raw = process.env.LETTA_SLACK_INBOUND_DEBOUNCE_MS;
|
|
169187
|
+
if (typeof raw === "string" && raw.trim() !== "") {
|
|
169188
|
+
const envOverride = Number(raw);
|
|
169189
|
+
if (Number.isFinite(envOverride) && envOverride >= 0) {
|
|
169190
|
+
return Math.trunc(envOverride);
|
|
169191
|
+
}
|
|
169192
|
+
}
|
|
169193
|
+
const fromConfig = config3.inboundDebounceMs;
|
|
169194
|
+
return typeof fromConfig === "number" && Number.isFinite(fromConfig) && fromConfig >= 0 ? Math.trunc(fromConfig) : 0;
|
|
169195
|
+
}
|
|
169196
|
+
function createSlackInboundDebounceController(params) {
|
|
169197
|
+
const { config: config3 } = params;
|
|
169198
|
+
const debounceMs = resolveSlackInboundDebounceMs(config3);
|
|
169199
|
+
const pendingTopLevelKeys = new Map;
|
|
169200
|
+
const appMentionRetryKeys = new Map;
|
|
169201
|
+
const appMentionDispatchedKeys = new Map;
|
|
169202
|
+
function pruneAppMentionMaps(now) {
|
|
169203
|
+
for (const [key, expiresAt] of appMentionRetryKeys) {
|
|
169204
|
+
if (expiresAt <= now)
|
|
169205
|
+
appMentionRetryKeys.delete(key);
|
|
169206
|
+
}
|
|
169207
|
+
for (const [key, expiresAt] of appMentionDispatchedKeys) {
|
|
169208
|
+
if (expiresAt <= now)
|
|
169209
|
+
appMentionDispatchedKeys.delete(key);
|
|
169210
|
+
}
|
|
169211
|
+
}
|
|
169212
|
+
function dedupeEntries(entries) {
|
|
169213
|
+
const indexByMessageKey = new Map;
|
|
169214
|
+
const deduped = [];
|
|
169215
|
+
for (const entry of entries) {
|
|
169216
|
+
const messageId = entry.inbound.messageId;
|
|
169217
|
+
const messageKey = isNonEmptyString2(messageId) ? `${entry.inbound.chatId}:${messageId}` : null;
|
|
169218
|
+
if (!messageKey) {
|
|
169219
|
+
deduped.push(entry);
|
|
169220
|
+
continue;
|
|
169221
|
+
}
|
|
169222
|
+
const existingIndex = indexByMessageKey.get(messageKey);
|
|
169223
|
+
if (existingIndex === undefined) {
|
|
169224
|
+
indexByMessageKey.set(messageKey, deduped.length);
|
|
169225
|
+
deduped.push(entry);
|
|
169226
|
+
continue;
|
|
169227
|
+
}
|
|
169228
|
+
const current = deduped[existingIndex];
|
|
169229
|
+
if (current && current.opts.source !== "app_mention" && current.inbound.isMention !== true) {
|
|
169230
|
+
deduped[existingIndex] = entry;
|
|
169231
|
+
}
|
|
169232
|
+
}
|
|
169233
|
+
return deduped;
|
|
169234
|
+
}
|
|
169235
|
+
const debouncer = createInboundDebouncer({
|
|
169236
|
+
debounceMs,
|
|
169237
|
+
buildKey: ({ raw }) => buildSlackDebounceKey(raw, config3.accountId),
|
|
169238
|
+
shouldDebounce: ({ inbound }) => !inbound.attachments?.length && !inbound.reaction,
|
|
169239
|
+
onFlush: async (entries) => {
|
|
169240
|
+
const dedupedEntries = dedupeEntries(entries);
|
|
169241
|
+
const last = dedupedEntries[dedupedEntries.length - 1];
|
|
169242
|
+
if (!last)
|
|
169243
|
+
return;
|
|
169244
|
+
const flushedKey = buildSlackDebounceKey(last.raw, config3.accountId);
|
|
169245
|
+
const conversationKey = buildTopLevelSlackConversationKey(last.raw, config3.accountId);
|
|
169246
|
+
if (flushedKey && conversationKey) {
|
|
169247
|
+
const pending = pendingTopLevelKeys.get(conversationKey);
|
|
169248
|
+
pending?.delete(flushedKey);
|
|
169249
|
+
if (pending?.size === 0)
|
|
169250
|
+
pendingTopLevelKeys.delete(conversationKey);
|
|
169251
|
+
}
|
|
169252
|
+
if (isNonEmptyString2(last.inbound.messageId)) {
|
|
169253
|
+
const seenKey = `${last.inbound.chatId}:${last.inbound.messageId}`;
|
|
169254
|
+
pruneAppMentionMaps(Date.now());
|
|
169255
|
+
if (last.opts.source === "app_mention") {
|
|
169256
|
+
appMentionDispatchedKeys.set(seenKey, Date.now() + APP_MENTION_RETRY_TTL_MS);
|
|
169257
|
+
} else if (appMentionDispatchedKeys.has(seenKey)) {
|
|
169258
|
+
appMentionDispatchedKeys.delete(seenKey);
|
|
169259
|
+
appMentionRetryKeys.delete(seenKey);
|
|
169260
|
+
return;
|
|
169261
|
+
}
|
|
169262
|
+
appMentionRetryKeys.delete(seenKey);
|
|
169263
|
+
}
|
|
169264
|
+
const onMessage = params.getOnMessage();
|
|
169265
|
+
if (!onMessage)
|
|
169266
|
+
return;
|
|
169267
|
+
const text = dedupedEntries.length === 1 ? last.inbound.text : dedupedEntries.map((entry) => entry.inbound.text).filter(Boolean).join(`
|
|
169268
|
+
`);
|
|
169269
|
+
try {
|
|
169270
|
+
await onMessage({
|
|
169271
|
+
...last.inbound,
|
|
169272
|
+
text,
|
|
169273
|
+
isMention: dedupedEntries.some((entry) => entry.opts.wasMentioned || entry.inbound.isMention === true)
|
|
169274
|
+
});
|
|
169275
|
+
} catch (error54) {
|
|
169276
|
+
console.error("[Slack] Error handling debounced inbound message:", error54);
|
|
169277
|
+
}
|
|
169278
|
+
},
|
|
169279
|
+
onError: (error54) => {
|
|
169280
|
+
console.error("[Slack] Inbound debounce flush failed:", error54 instanceof Error ? error54.message : error54);
|
|
169281
|
+
}
|
|
169282
|
+
});
|
|
169283
|
+
return {
|
|
169284
|
+
async dispatch(entry) {
|
|
169285
|
+
const debounceKey = buildSlackDebounceKey(entry.raw, config3.accountId);
|
|
169286
|
+
const conversationKey = buildTopLevelSlackConversationKey(entry.raw, config3.accountId);
|
|
169287
|
+
const canDebounce = debounceMs > 0 && !entry.inbound.attachments?.length && !entry.inbound.reaction && Boolean(debounceKey);
|
|
169288
|
+
if (!canDebounce && conversationKey) {
|
|
169289
|
+
for (const pendingKey of Array.from(pendingTopLevelKeys.get(conversationKey) ?? [])) {
|
|
169290
|
+
try {
|
|
169291
|
+
await debouncer.flushKey(pendingKey);
|
|
169292
|
+
} catch {}
|
|
169293
|
+
}
|
|
169294
|
+
}
|
|
169295
|
+
if (canDebounce && debounceKey && conversationKey) {
|
|
169296
|
+
const pending = pendingTopLevelKeys.get(conversationKey) ?? new Set;
|
|
169297
|
+
pending.add(debounceKey);
|
|
169298
|
+
pendingTopLevelKeys.set(conversationKey, pending);
|
|
169299
|
+
}
|
|
169300
|
+
await debouncer.enqueue(entry);
|
|
169301
|
+
},
|
|
169302
|
+
rememberAppMentionRetry(seenKey) {
|
|
169303
|
+
const now = Date.now();
|
|
169304
|
+
pruneAppMentionMaps(now);
|
|
169305
|
+
appMentionRetryKeys.set(seenKey, now + APP_MENTION_RETRY_TTL_MS);
|
|
169306
|
+
},
|
|
169307
|
+
consumeAppMentionRetry(seenKey) {
|
|
169308
|
+
pruneAppMentionMaps(Date.now());
|
|
169309
|
+
if (!appMentionRetryKeys.has(seenKey))
|
|
169310
|
+
return false;
|
|
169311
|
+
appMentionRetryKeys.delete(seenKey);
|
|
169312
|
+
return true;
|
|
169313
|
+
},
|
|
169314
|
+
clear() {
|
|
169315
|
+
pendingTopLevelKeys.clear();
|
|
169316
|
+
appMentionRetryKeys.clear();
|
|
169317
|
+
appMentionDispatchedKeys.clear();
|
|
169318
|
+
}
|
|
169319
|
+
};
|
|
169320
|
+
}
|
|
169321
|
+
var APP_MENTION_RETRY_TTL_MS = 60000;
|
|
169322
|
+
var init_inbound_debounce = __esm(() => {
|
|
169323
|
+
init_utils5();
|
|
169324
|
+
});
|
|
169325
|
+
|
|
169087
169326
|
// src/channels/slack/ingress-controller.ts
|
|
169088
169327
|
function createSlackIngressController(params) {
|
|
169089
169328
|
const { config: config3 } = params;
|
|
@@ -169816,6 +170055,18 @@ function createSlackAdapter(config3) {
|
|
|
169816
170055
|
throw error54;
|
|
169817
170056
|
}
|
|
169818
170057
|
}
|
|
170058
|
+
async function downloadAttachment(params) {
|
|
170059
|
+
const slackApp = await ensureApp();
|
|
170060
|
+
return await downloadSlackAttachmentById({
|
|
170061
|
+
accountId: config3.accountId,
|
|
170062
|
+
token: config3.botToken,
|
|
170063
|
+
attachmentId: params.attachmentId,
|
|
170064
|
+
channelId: params.chatId,
|
|
170065
|
+
threadTs: params.threadId,
|
|
170066
|
+
messageTs: params.messageId,
|
|
170067
|
+
client: slackApp.client
|
|
170068
|
+
});
|
|
170069
|
+
}
|
|
169819
170070
|
async function sendLifecycleErrorReply(source2, errorText) {
|
|
169820
170071
|
const threadTs = resolveSlackSourceThreadTs(source2);
|
|
169821
170072
|
const text = formatSlackLifecycleErrorMessage(errorText);
|
|
@@ -170018,6 +170269,7 @@ function createSlackAdapter(config3) {
|
|
|
170018
170269
|
await Promise.all(status.getUniqueSources(event2.sources).map((source2) => status.activate(source2, SLACK_ASSISTANT_WORKING_STATUS, activity)));
|
|
170019
170270
|
},
|
|
170020
170271
|
sendMessage,
|
|
170272
|
+
downloadAttachment,
|
|
170021
170273
|
sendDirectReply,
|
|
170022
170274
|
handleControlRequestEvent,
|
|
170023
170275
|
prepareInboundMessage: (msg, options3) => prepareSlackInboundMessage({
|
|
@@ -170037,6 +170289,7 @@ var init_adapter3 = __esm(async () => {
|
|
|
170037
170289
|
init_model_picker_blocks();
|
|
170038
170290
|
init_error_reporting();
|
|
170039
170291
|
init_agent_thread_tracker();
|
|
170292
|
+
init_attachment_download();
|
|
170040
170293
|
init_file_upload();
|
|
170041
170294
|
init_inbound_debounce();
|
|
170042
170295
|
init_ingress_controller();
|
|
@@ -170427,13 +170680,47 @@ async function reactInSlack(ctx) {
|
|
|
170427
170680
|
});
|
|
170428
170681
|
return request.remove ? `Reaction removed on slack (message_id: ${result.messageId})` : `Reaction added on slack (message_id: ${result.messageId})`;
|
|
170429
170682
|
}
|
|
170683
|
+
async function downloadSlackFile(ctx) {
|
|
170684
|
+
const { request } = ctx;
|
|
170685
|
+
if (!request.attachmentId?.trim()) {
|
|
170686
|
+
return "Error: Slack download-file requires attachmentId.";
|
|
170687
|
+
}
|
|
170688
|
+
if (!request.messageId?.trim()) {
|
|
170689
|
+
return "Error: Slack download-file requires messageId from the attachment's Slack context.";
|
|
170690
|
+
}
|
|
170691
|
+
if (typeof ctx.adapter.downloadAttachment !== "function") {
|
|
170692
|
+
return "Error: Running Slack adapter does not support attachment downloads.";
|
|
170693
|
+
}
|
|
170694
|
+
const attachment = await ctx.adapter.downloadAttachment({
|
|
170695
|
+
attachmentId: request.attachmentId,
|
|
170696
|
+
chatId: request.chatId,
|
|
170697
|
+
threadId: request.threadId ?? null,
|
|
170698
|
+
messageId: request.messageId
|
|
170699
|
+
});
|
|
170700
|
+
if (!attachment.localPath) {
|
|
170701
|
+
return `Error: Slack attachment ${request.attachmentId} was not downloaded.`;
|
|
170702
|
+
}
|
|
170703
|
+
return `Slack attachment downloaded (local_path: ${attachment.localPath})`;
|
|
170704
|
+
}
|
|
170430
170705
|
var slackMessageActions;
|
|
170431
170706
|
var init_message_actions2 = __esm(() => {
|
|
170432
170707
|
init_target_resolution();
|
|
170433
170708
|
slackMessageActions = {
|
|
170434
170709
|
describeMessageTool() {
|
|
170435
170710
|
return {
|
|
170436
|
-
actions: ["send", "react", "upload-file"]
|
|
170711
|
+
actions: ["send", "react", "upload-file", "download-file"],
|
|
170712
|
+
schema: {
|
|
170713
|
+
properties: {
|
|
170714
|
+
attachmentId: {
|
|
170715
|
+
type: "string",
|
|
170716
|
+
description: "Slack attachment id for action='download-file'. Copy attachment_id from the channel notification."
|
|
170717
|
+
},
|
|
170718
|
+
messageId: {
|
|
170719
|
+
type: "string",
|
|
170720
|
+
description: "Target Slack message id for action='react', or the source message id containing attachmentId for action='download-file'."
|
|
170721
|
+
}
|
|
170722
|
+
}
|
|
170723
|
+
}
|
|
170437
170724
|
};
|
|
170438
170725
|
},
|
|
170439
170726
|
async resolveMessageTarget(params) {
|
|
@@ -170453,6 +170740,8 @@ var init_message_actions2 = __esm(() => {
|
|
|
170453
170740
|
return await sendSlackMessage(ctx);
|
|
170454
170741
|
case "react":
|
|
170455
170742
|
return await reactInSlack(ctx);
|
|
170743
|
+
case "download-file":
|
|
170744
|
+
return await downloadSlackFile(ctx);
|
|
170456
170745
|
default:
|
|
170457
170746
|
return `Error: Action "${ctx.request.action}" is not supported on slack.`;
|
|
170458
170747
|
}
|
|
@@ -170692,7 +170981,7 @@ function resolveDiscordChannelMode(channelId, parentChannelId, isThread, allowed
|
|
|
170692
170981
|
// src/channels/discord/media.ts
|
|
170693
170982
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
170694
170983
|
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
170695
|
-
import { writeFile as
|
|
170984
|
+
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
170696
170985
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
170697
170986
|
import { join as join13 } from "node:path";
|
|
170698
170987
|
function ensureAttachmentsDir() {
|
|
@@ -170756,7 +171045,7 @@ async function resolveDiscordInboundAttachments(params) {
|
|
|
170756
171045
|
console.warn(`[Discord] Skipping oversized attachment ${name}: ${buffer.byteLength} bytes`);
|
|
170757
171046
|
continue;
|
|
170758
171047
|
}
|
|
170759
|
-
await
|
|
171048
|
+
await writeFile6(localPath, buffer);
|
|
170760
171049
|
const entry = {
|
|
170761
171050
|
id: attachment.id,
|
|
170762
171051
|
name,
|
|
@@ -170862,7 +171151,7 @@ function formatDiscordDeliveryError(error54) {
|
|
|
170862
171151
|
}
|
|
170863
171152
|
|
|
170864
171153
|
// src/channels/discord/utils.ts
|
|
170865
|
-
function
|
|
171154
|
+
function isNonEmptyString5(value) {
|
|
170866
171155
|
return typeof value === "string" && value.length > 0;
|
|
170867
171156
|
}
|
|
170868
171157
|
function isDiscordTextChannel(channel) {
|
|
@@ -170929,7 +171218,7 @@ function shouldAutoThreadOnDiscordMention(account, channelId) {
|
|
|
170929
171218
|
return account.autoThreadOnMention ?? false;
|
|
170930
171219
|
}
|
|
170931
171220
|
function buildDiscordIngressMessageKey(accountId, messageId) {
|
|
170932
|
-
if (!
|
|
171221
|
+
if (!isNonEmptyString5(accountId) || !isNonEmptyString5(messageId)) {
|
|
170933
171222
|
return null;
|
|
170934
171223
|
}
|
|
170935
171224
|
return `${accountId}:${messageId}`;
|
|
@@ -171013,13 +171302,13 @@ function createDiscordAdapter(config3) {
|
|
|
171013
171302
|
return false;
|
|
171014
171303
|
}
|
|
171015
171304
|
function getLifecycleMessageKey(source2) {
|
|
171016
|
-
if (source2.channel !== "discord" || !
|
|
171305
|
+
if (source2.channel !== "discord" || !isNonEmptyString5(source2.chatId) || !isNonEmptyString5(source2.messageId)) {
|
|
171017
171306
|
return null;
|
|
171018
171307
|
}
|
|
171019
171308
|
return `${source2.chatId}:${source2.messageId}`;
|
|
171020
171309
|
}
|
|
171021
171310
|
function getLifecycleReplyKey(source2) {
|
|
171022
|
-
if (source2.channel !== "discord" || !
|
|
171311
|
+
if (source2.channel !== "discord" || !isNonEmptyString5(source2.chatId)) {
|
|
171023
171312
|
return null;
|
|
171024
171313
|
}
|
|
171025
171314
|
return [
|
|
@@ -171032,7 +171321,7 @@ function createDiscordAdapter(config3) {
|
|
|
171032
171321
|
if (source2.channel !== "discord")
|
|
171033
171322
|
return null;
|
|
171034
171323
|
const channelId = source2.threadId ?? source2.chatId;
|
|
171035
|
-
return
|
|
171324
|
+
return isNonEmptyString5(channelId) ? channelId : null;
|
|
171036
171325
|
}
|
|
171037
171326
|
function getTypingSourceKey(source2) {
|
|
171038
171327
|
const channelId = getTypingChannelId(source2);
|
|
@@ -171084,7 +171373,7 @@ function createDiscordAdapter(config3) {
|
|
|
171084
171373
|
return true;
|
|
171085
171374
|
}
|
|
171086
171375
|
async function sendLifecycleReaction(source2, emoji3, remove = false) {
|
|
171087
|
-
if (!client || !
|
|
171376
|
+
if (!client || !isNonEmptyString5(source2.messageId))
|
|
171088
171377
|
return;
|
|
171089
171378
|
try {
|
|
171090
171379
|
const channel = await client.channels.fetch(source2.chatId);
|
|
@@ -171623,7 +171912,7 @@ function createDiscordAdapter(config3) {
|
|
|
171623
171912
|
clearTypingForChannel(chatId);
|
|
171624
171913
|
},
|
|
171625
171914
|
async prepareInboundMessage(msg, options3) {
|
|
171626
|
-
if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !
|
|
171915
|
+
if (!options3?.isFirstRouteTurn || msg.channel !== "discord" || msg.chatType !== "channel" || !isNonEmptyString5(msg.threadId) || !client) {
|
|
171627
171916
|
return msg;
|
|
171628
171917
|
}
|
|
171629
171918
|
const starter = await resolveDiscordThreadStarter({
|
|
@@ -172044,7 +172333,7 @@ var WHATSAPP_PHONE_SUFFIX = "@s.whatsapp.net", WHATSAPP_LID_SUFFIX = "@lid", WHA
|
|
|
172044
172333
|
|
|
172045
172334
|
// src/channels/whatsapp/media.ts
|
|
172046
172335
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
172047
|
-
import { mkdir as mkdir5, writeFile as
|
|
172336
|
+
import { mkdir as mkdir5, writeFile as writeFile7 } from "node:fs/promises";
|
|
172048
172337
|
import { basename as basename10, extname as extname5, join as join14 } from "node:path";
|
|
172049
172338
|
function unwrapWhatsAppMessageContent(message) {
|
|
172050
172339
|
if (!message || typeof message !== "object")
|
|
@@ -172226,7 +172515,7 @@ async function collectWhatsAppAttachments(params) {
|
|
|
172226
172515
|
if (!buffer) {
|
|
172227
172516
|
return { attachments: [attachment] };
|
|
172228
172517
|
}
|
|
172229
|
-
await
|
|
172518
|
+
await writeFile7(localPath, buffer);
|
|
172230
172519
|
attachment.localPath = localPath;
|
|
172231
172520
|
if (isVoice && params.transcribeVoice) {
|
|
172232
172521
|
const result = await transcribeAudioFile(localPath);
|
|
@@ -176039,7 +176328,7 @@ function isLocalAgentId2(agentId) {
|
|
|
176039
176328
|
return isLocalAgentId(agentId);
|
|
176040
176329
|
}
|
|
176041
176330
|
function buildChatUrl(agentId, options3) {
|
|
176042
|
-
const base2 = `${
|
|
176331
|
+
const base2 = `${CHAT_BASE}/chat/${agentId}`;
|
|
176043
176332
|
const params = new URLSearchParams;
|
|
176044
176333
|
if (options3?.view) {
|
|
176045
176334
|
params.set("view", options3.view);
|
|
@@ -176066,11 +176355,16 @@ function buildAgentTerminalLink(agentId, options3, label = agentId) {
|
|
|
176066
176355
|
const url2 = buildChatUrl(agentId, options3);
|
|
176067
176356
|
return `\x1B]8;;${url2}\x1B\\${label}\x1B]8;;\x1B\\`;
|
|
176068
176357
|
}
|
|
176069
|
-
function
|
|
176070
|
-
return `${
|
|
176358
|
+
function buildChatWebUrl(path5) {
|
|
176359
|
+
return `${CHAT_BASE}${path5}`;
|
|
176360
|
+
}
|
|
176361
|
+
function buildPlatformUrl(path5) {
|
|
176362
|
+
return `${PLATFORM_BASE}${path5}`;
|
|
176071
176363
|
}
|
|
176072
|
-
var
|
|
176073
|
-
var init_app_urls = () => {
|
|
176364
|
+
var CHAT_BASE = "https://chat.letta.com", PLATFORM_BASE = "https://platform.letta.com", LETTA_CHAT_API_KEYS_URL;
|
|
176365
|
+
var init_app_urls = __esm(() => {
|
|
176366
|
+
LETTA_CHAT_API_KEYS_URL = `${CHAT_BASE}/preferences/api-keys`;
|
|
176367
|
+
});
|
|
176074
176368
|
|
|
176075
176369
|
// src/channels/registry-presentation.ts
|
|
176076
176370
|
function channelDisplayName2(channelId) {
|
|
@@ -177257,14 +177551,19 @@ function escapeXmlText(text) {
|
|
|
177257
177551
|
function escapeXmlAttribute(text) {
|
|
177258
177552
|
return escapeXmlText(text).replace(/"/g, """).replace(/'/g, "'");
|
|
177259
177553
|
}
|
|
177554
|
+
function formatMebibytes(bytes) {
|
|
177555
|
+
const mebibytes = bytes / (1024 * 1024);
|
|
177556
|
+
const rounded = mebibytes >= 100 ? Math.round(mebibytes).toString() : mebibytes.toFixed(1);
|
|
177557
|
+
return `${rounded.replace(/\.0$/, "")} MiB`;
|
|
177558
|
+
}
|
|
177260
177559
|
function hasNotificationAttachmentPaths(msg) {
|
|
177261
|
-
if (msg.attachments?.
|
|
177560
|
+
if (msg.attachments?.some((attachment) => attachment.localPath)) {
|
|
177262
177561
|
return true;
|
|
177263
177562
|
}
|
|
177264
|
-
if (msg.threadContext?.starter?.attachments?.
|
|
177563
|
+
if (msg.threadContext?.starter?.attachments?.some((attachment) => attachment.localPath)) {
|
|
177265
177564
|
return true;
|
|
177266
177565
|
}
|
|
177267
|
-
return Boolean(msg.threadContext?.history?.some((entry) => entry.attachments?.
|
|
177566
|
+
return Boolean(msg.threadContext?.history?.some((entry) => entry.attachments?.some((attachment) => attachment.localPath)));
|
|
177268
177567
|
}
|
|
177269
177568
|
function buildChannelReminderText(msg) {
|
|
177270
177569
|
const localTime = escapeXmlText(getLocalTime());
|
|
@@ -177287,7 +177586,7 @@ function buildChannelReminderText(msg) {
|
|
|
177287
177586
|
lines.splice(lines.length - 2, 0, threadLine);
|
|
177288
177587
|
}
|
|
177289
177588
|
if (msg.channel === "slack") {
|
|
177290
|
-
lines.splice(lines.length - 2, 0, 'On Slack, MessageChannel also supports action="react" with emoji + messageId, and action="
|
|
177589
|
+
lines.splice(lines.length - 2, 0, 'On Slack, MessageChannel also supports action="react" with emoji + messageId, action="upload-file" with media, and action="download-file" with attachmentId + messageId.', 'For Slack requests that require nontrivial work or several tool calls, send a short MessageChannel action="send" acknowledgement before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.');
|
|
177291
177590
|
}
|
|
177292
177591
|
if (msg.channel === "telegram") {
|
|
177293
177592
|
lines.splice(lines.length - 2, 0, 'On Telegram, MessageChannel also supports action="react" with emoji + messageId, and action="upload-file" with media.');
|
|
@@ -177307,11 +177606,13 @@ function buildChannelReminderText(msg) {
|
|
|
177307
177606
|
return lines.join(`
|
|
177308
177607
|
`);
|
|
177309
177608
|
}
|
|
177310
|
-
function buildAttachmentXml(attachment) {
|
|
177311
|
-
const attrs = [
|
|
177312
|
-
|
|
177313
|
-
`local_path="${escapeXmlAttribute(attachment.localPath)}"`
|
|
177314
|
-
|
|
177609
|
+
function buildAttachmentXml(attachment, context3) {
|
|
177610
|
+
const attrs = [`kind="${escapeXmlAttribute(attachment.kind)}"`];
|
|
177611
|
+
if (attachment.localPath) {
|
|
177612
|
+
attrs.push(`local_path="${escapeXmlAttribute(attachment.localPath)}"`);
|
|
177613
|
+
} else {
|
|
177614
|
+
attrs.push('download_status="not_downloaded"');
|
|
177615
|
+
}
|
|
177315
177616
|
if (attachment.id) {
|
|
177316
177617
|
attrs.push(`attachment_id="${escapeXmlAttribute(attachment.id)}"`);
|
|
177317
177618
|
}
|
|
@@ -177324,6 +177625,19 @@ function buildAttachmentXml(attachment) {
|
|
|
177324
177625
|
if (typeof attachment.sizeBytes === "number") {
|
|
177325
177626
|
attrs.push(`size_bytes="${attachment.sizeBytes}"`);
|
|
177326
177627
|
}
|
|
177628
|
+
const sourceMessageId = attachment.sourceMessageId ?? context3.messageId;
|
|
177629
|
+
if (!attachment.localPath && sourceMessageId) {
|
|
177630
|
+
attrs.push(`source_message_id="${escapeXmlAttribute(sourceMessageId)}"`);
|
|
177631
|
+
}
|
|
177632
|
+
if (!attachment.localPath && attachment.sourceThreadId) {
|
|
177633
|
+
attrs.push(`source_thread_id="${escapeXmlAttribute(attachment.sourceThreadId)}"`);
|
|
177634
|
+
}
|
|
177635
|
+
if (attachment.downloadReason) {
|
|
177636
|
+
attrs.push(`download_reason="${escapeXmlAttribute(attachment.downloadReason)}"`);
|
|
177637
|
+
}
|
|
177638
|
+
if (typeof attachment.autoDownloadLimitBytes === "number") {
|
|
177639
|
+
attrs.push(`auto_download_limit_bytes="${attachment.autoDownloadLimitBytes}"`);
|
|
177640
|
+
}
|
|
177327
177641
|
const children = [];
|
|
177328
177642
|
if (attachment.transcription) {
|
|
177329
177643
|
children.push(`<attempted_transcription>${escapeXmlText(attachment.transcription)}</attempted_transcription>`);
|
|
@@ -177331,6 +177645,17 @@ function buildAttachmentXml(attachment) {
|
|
|
177331
177645
|
if (attachment.transcriptionError) {
|
|
177332
177646
|
children.push(`<attempted_transcription_error>${escapeXmlText(attachment.transcriptionError)}</attempted_transcription_error>`);
|
|
177333
177647
|
}
|
|
177648
|
+
if (!attachment.localPath && context3.channel === "slack" && attachment.id && sourceMessageId) {
|
|
177649
|
+
const accountArg = context3.accountId ? `, accountId="${escapeXmlAttribute(context3.accountId)}"` : "";
|
|
177650
|
+
const threadArg = attachment.sourceThreadId ? `, threadId="${escapeXmlAttribute(attachment.sourceThreadId)}"` : "";
|
|
177651
|
+
const action3 = `MessageChannel with action="download-file", channel="slack", chat_id="${escapeXmlAttribute(context3.chatId)}"${accountArg}${threadArg}, attachmentId="${escapeXmlAttribute(attachment.id)}", and messageId="${escapeXmlAttribute(sourceMessageId)}"`;
|
|
177652
|
+
if (attachment.downloadReason === "exceeds_auto_download_limit") {
|
|
177653
|
+
const sizeNote = typeof attachment.sizeBytes === "number" ? `This file is ${formatMebibytes(attachment.sizeBytes)}${typeof attachment.autoDownloadLimitBytes === "number" ? `, above the ${formatMebibytes(attachment.autoDownloadLimitBytes)} automatic download limit` : ""}. ` : "";
|
|
177654
|
+
children.push(`<download-instruction>${sizeNote}Call ${action3}. The tool downloads the file into the same Slack inbound attachment directory and returns its local_path. Do not ask the sender to reattach it.</download-instruction>`);
|
|
177655
|
+
} else {
|
|
177656
|
+
children.push(`<download-retry>Automatic download did not complete. Call ${action3} to retry. The action may return a precise error if Slack still cannot provide the file.</download-retry>`);
|
|
177657
|
+
}
|
|
177658
|
+
}
|
|
177334
177659
|
if (children.length > 0) {
|
|
177335
177660
|
return `<attachment ${attrs.join(" ")}>
|
|
177336
177661
|
${children.join(`
|
|
@@ -177380,7 +177705,7 @@ ${escapeXmlText(replyContext.text)}
|
|
|
177380
177705
|
}
|
|
177381
177706
|
return `<reply-context${attrString} />`;
|
|
177382
177707
|
}
|
|
177383
|
-
function buildThreadContextEntryXml(tagName, entry) {
|
|
177708
|
+
function buildThreadContextEntryXml(tagName, entry, context3) {
|
|
177384
177709
|
const attrs = [];
|
|
177385
177710
|
if (entry.senderId) {
|
|
177386
177711
|
attrs.push(`sender_id="${escapeXmlAttribute(entry.senderId)}"`);
|
|
@@ -177394,7 +177719,10 @@ function buildThreadContextEntryXml(tagName, entry) {
|
|
|
177394
177719
|
const attrString = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
177395
177720
|
const body = [
|
|
177396
177721
|
...entry.text ? [escapeXmlText(entry.text)] : [],
|
|
177397
|
-
...(entry.attachments ?? []).map(buildAttachmentXml
|
|
177722
|
+
...(entry.attachments ?? []).map((attachment) => buildAttachmentXml(attachment, {
|
|
177723
|
+
...context3,
|
|
177724
|
+
messageId: entry.messageId
|
|
177725
|
+
}))
|
|
177398
177726
|
].join(`
|
|
177399
177727
|
`);
|
|
177400
177728
|
return `<${tagName}${attrString}>
|
|
@@ -177408,13 +177736,21 @@ function buildThreadContextXml(msg) {
|
|
|
177408
177736
|
}
|
|
177409
177737
|
const parts = [];
|
|
177410
177738
|
if (threadContext.starter) {
|
|
177411
|
-
parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter
|
|
177739
|
+
parts.push(buildThreadContextEntryXml("thread-starter", threadContext.starter, {
|
|
177740
|
+
channel: msg.channel,
|
|
177741
|
+
accountId: msg.accountId,
|
|
177742
|
+
chatId: msg.chatId
|
|
177743
|
+
}));
|
|
177412
177744
|
}
|
|
177413
177745
|
const historyEntries = threadContext.history ?? [];
|
|
177414
177746
|
if (historyEntries.length > 0) {
|
|
177415
177747
|
parts.push([
|
|
177416
177748
|
"<thread-history>",
|
|
177417
|
-
...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry
|
|
177749
|
+
...historyEntries.map((entry) => buildThreadContextEntryXml("thread-message", entry, {
|
|
177750
|
+
channel: msg.channel,
|
|
177751
|
+
accountId: msg.accountId,
|
|
177752
|
+
chatId: msg.chatId
|
|
177753
|
+
})),
|
|
177418
177754
|
"</thread-history>"
|
|
177419
177755
|
].join(`
|
|
177420
177756
|
`));
|
|
@@ -177449,7 +177785,12 @@ function buildChannelNotificationXml(msg) {
|
|
|
177449
177785
|
const reactionXml = buildReactionXml(msg);
|
|
177450
177786
|
const replyContextXml = buildReplyContextXml(msg);
|
|
177451
177787
|
const threadContextXml = buildThreadContextXml(msg);
|
|
177452
|
-
const attachmentXml = (msg.attachments ?? []).map(buildAttachmentXml
|
|
177788
|
+
const attachmentXml = (msg.attachments ?? []).map((attachment) => buildAttachmentXml(attachment, {
|
|
177789
|
+
channel: msg.channel,
|
|
177790
|
+
accountId: msg.accountId,
|
|
177791
|
+
chatId: msg.chatId,
|
|
177792
|
+
messageId: msg.messageId
|
|
177793
|
+
}));
|
|
177453
177794
|
const body = [
|
|
177454
177795
|
threadContextXml,
|
|
177455
177796
|
replyContextXml,
|
|
@@ -179705,7 +180046,10 @@ This tool is currently scoped to a routed external channel turn. Plain assistant
|
|
|
179705
180046
|
const slackWorkAcknowledgement = discovery.activeChannels.includes("slack") ? `
|
|
179706
180047
|
|
|
179707
180048
|
For Slack requests that require nontrivial work or several tool calls, send one short MessageChannel call with action="send" before starting other tools. This gives the Slack user verbal acknowledgement and a View in web link. Do not do this for no-ops, reaction-only responses, or simple no-tool answers.` : "";
|
|
179708
|
-
|
|
180049
|
+
const slackAttachmentDownload = discovery.activeChannels.includes("slack") ? `
|
|
180050
|
+
|
|
180051
|
+
Slack attachments that exceed the automatic download limit include an exact recovery instruction. Use action="download-file" with channel, chat_id, attachmentId, and messageId from that instruction. The action saves the file in the normal Slack inbound attachment directory and returns its local_path.` : "";
|
|
180052
|
+
return `${description}${scopedReplyContract}${slackWorkAcknowledgement}${slackAttachmentDownload}
|
|
179709
180053
|
|
|
179710
180054
|
Currently active channels: ${channelList}. Available actions across the active channels: ${actionList}. The JSON schema reflects the currently active channel plugins.`;
|
|
179711
180055
|
}
|
|
@@ -183403,7 +183747,7 @@ var init_apply_patch = __esm(() => {
|
|
|
183403
183747
|
});
|
|
183404
183748
|
|
|
183405
183749
|
// src/tools/impl/artifact-files.ts
|
|
183406
|
-
import { mkdir as mkdir6, readFile as
|
|
183750
|
+
import { mkdir as mkdir6, readFile as readFile5, stat as stat3, writeFile as writeFile8 } from "node:fs/promises";
|
|
183407
183751
|
import { homedir as homedir9 } from "node:os";
|
|
183408
183752
|
import { dirname as dirname7, isAbsolute as isAbsolute5, join as join19, relative as relative2, resolve as resolve8 } from "node:path";
|
|
183409
183753
|
function assertArtifactsExperimentEnabled(toolName) {
|
|
@@ -183461,7 +183805,7 @@ async function read_artifact_file(args) {
|
|
|
183461
183805
|
if (stats.size > MAX_READ_FILE_BYTES) {
|
|
183462
183806
|
throw new Error(`read_artifact_file: file is too large to read (${stats.size} bytes)`);
|
|
183463
183807
|
}
|
|
183464
|
-
const buffer = await
|
|
183808
|
+
const buffer = await readFile5(absolutePath);
|
|
183465
183809
|
return {
|
|
183466
183810
|
path: relativePath,
|
|
183467
183811
|
content: buffer.toString(encoding),
|
|
@@ -183475,7 +183819,7 @@ async function write_artifact_file(args) {
|
|
|
183475
183819
|
const encoding = getEncoding(args.encoding);
|
|
183476
183820
|
const buffer = Buffer.from(args.content, encoding);
|
|
183477
183821
|
await mkdir6(dirname7(absolutePath), { recursive: true });
|
|
183478
|
-
await
|
|
183822
|
+
await writeFile8(absolutePath, buffer);
|
|
183479
183823
|
return {
|
|
183480
183824
|
path: relativePath,
|
|
183481
183825
|
bytes: buffer.byteLength,
|
|
@@ -184164,6 +184508,9 @@ class TurnLifecycle {
|
|
|
184164
184508
|
get activeRunId() {
|
|
184165
184509
|
return this.#state.kind === "active" ? this.#state.runId : null;
|
|
184166
184510
|
}
|
|
184511
|
+
get executingToolCallIds() {
|
|
184512
|
+
return this.#state.kind === "active" || this.#state.kind === "cancelling" ? this.#state.executingToolCallIds : [];
|
|
184513
|
+
}
|
|
184167
184514
|
get lastStopReason() {
|
|
184168
184515
|
return this.#lastStopReason;
|
|
184169
184516
|
}
|
|
@@ -187318,7 +187665,7 @@ var init_worktree_lock = __esm(() => {
|
|
|
187318
187665
|
|
|
187319
187666
|
// src/websocket/listener/remote-settings.ts
|
|
187320
187667
|
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
|
|
187321
|
-
import { mkdir as mkdir7, writeFile as
|
|
187668
|
+
import { mkdir as mkdir7, writeFile as writeFile9 } from "node:fs/promises";
|
|
187322
187669
|
import { homedir as homedir16 } from "node:os";
|
|
187323
187670
|
import path12 from "node:path";
|
|
187324
187671
|
function getRemoteSettingsPath() {
|
|
@@ -187362,7 +187709,7 @@ function saveRemoteSettings(updates) {
|
|
|
187362
187709
|
};
|
|
187363
187710
|
const snapshot = _cache;
|
|
187364
187711
|
const settingsPath = getRemoteSettingsPath();
|
|
187365
|
-
mkdir7(path12.dirname(settingsPath), { recursive: true }).then(() =>
|
|
187712
|
+
mkdir7(path12.dirname(settingsPath), { recursive: true }).then(() => writeFile9(settingsPath, JSON.stringify(snapshot, null, 2))).catch(() => {});
|
|
187366
187713
|
}
|
|
187367
187714
|
function loadLegacyCwdCache() {
|
|
187368
187715
|
try {
|
|
@@ -188157,7 +188504,7 @@ var require_filesystem = __commonJS((exports, module3) => {
|
|
|
188157
188504
|
fs5.close(fd, () => {});
|
|
188158
188505
|
return buffer.subarray(0, bytesRead);
|
|
188159
188506
|
};
|
|
188160
|
-
var
|
|
188507
|
+
var readFile6 = (path13) => new Promise((resolve13, reject) => {
|
|
188161
188508
|
fs5.open(path13, "r", (err, fd) => {
|
|
188162
188509
|
if (err) {
|
|
188163
188510
|
reject(err);
|
|
@@ -188174,7 +188521,7 @@ var require_filesystem = __commonJS((exports, module3) => {
|
|
|
188174
188521
|
LDD_PATH,
|
|
188175
188522
|
SELF_PATH,
|
|
188176
188523
|
readFileSync: readFileSync19,
|
|
188177
|
-
readFile:
|
|
188524
|
+
readFile: readFile6
|
|
188178
188525
|
};
|
|
188179
188526
|
});
|
|
188180
188527
|
|
|
@@ -188216,7 +188563,7 @@ var require_elf = __commonJS((exports, module3) => {
|
|
|
188216
188563
|
var require_detect_libc = __commonJS((exports, module3) => {
|
|
188217
188564
|
var childProcess = __require("child_process");
|
|
188218
188565
|
var { isLinux, getReport } = require_process();
|
|
188219
|
-
var { LDD_PATH, SELF_PATH, readFile:
|
|
188566
|
+
var { LDD_PATH, SELF_PATH, readFile: readFile6, readFileSync: readFileSync19 } = require_filesystem();
|
|
188220
188567
|
var { interpreterPath } = require_elf();
|
|
188221
188568
|
var cachedFamilyInterpreter;
|
|
188222
188569
|
var cachedFamilyFilesystem;
|
|
@@ -188296,7 +188643,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
|
|
|
188296
188643
|
}
|
|
188297
188644
|
cachedFamilyFilesystem = null;
|
|
188298
188645
|
try {
|
|
188299
|
-
const lddContent = await
|
|
188646
|
+
const lddContent = await readFile6(LDD_PATH);
|
|
188300
188647
|
cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
|
|
188301
188648
|
} catch (e2) {}
|
|
188302
188649
|
return cachedFamilyFilesystem;
|
|
@@ -188318,7 +188665,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
|
|
|
188318
188665
|
}
|
|
188319
188666
|
cachedFamilyInterpreter = null;
|
|
188320
188667
|
try {
|
|
188321
|
-
const selfContent = await
|
|
188668
|
+
const selfContent = await readFile6(SELF_PATH);
|
|
188322
188669
|
const path13 = interpreterPath(selfContent);
|
|
188323
188670
|
cachedFamilyInterpreter = familyFromInterpreterPath(path13);
|
|
188324
188671
|
} catch (e2) {}
|
|
@@ -188378,7 +188725,7 @@ var require_detect_libc = __commonJS((exports, module3) => {
|
|
|
188378
188725
|
}
|
|
188379
188726
|
cachedVersionFilesystem = null;
|
|
188380
188727
|
try {
|
|
188381
|
-
const lddContent = await
|
|
188728
|
+
const lddContent = await readFile6(LDD_PATH);
|
|
188382
188729
|
const versionMatch = lddContent.match(RE_GLIBC_VERSION);
|
|
188383
188730
|
if (versionMatch) {
|
|
188384
188731
|
cachedVersionFilesystem = versionMatch[1];
|
|
@@ -194572,7 +194919,7 @@ __export(exports_image_resize_sips, {
|
|
|
194572
194919
|
convertHeicToJpegWithSips: () => convertHeicToJpegWithSips
|
|
194573
194920
|
});
|
|
194574
194921
|
import { execFile as execFile2 } from "node:child_process";
|
|
194575
|
-
import { mkdtemp, readFile as
|
|
194922
|
+
import { mkdtemp, readFile as readFile6, rm as rm3, writeFile as writeFile10 } from "node:fs/promises";
|
|
194576
194923
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
194577
194924
|
import { join as join29 } from "node:path";
|
|
194578
194925
|
function execFileAsync2(file3, args) {
|
|
@@ -194591,7 +194938,7 @@ async function convertHeicToJpegWithSips(buffer) {
|
|
|
194591
194938
|
const inputPath = join29(workDir, "input.heic");
|
|
194592
194939
|
const outputPath = join29(workDir, "output.jpg");
|
|
194593
194940
|
try {
|
|
194594
|
-
await
|
|
194941
|
+
await writeFile10(inputPath, buffer);
|
|
194595
194942
|
await execFileAsync2("/usr/bin/sips", [
|
|
194596
194943
|
"-s",
|
|
194597
194944
|
"format",
|
|
@@ -194603,9 +194950,9 @@ async function convertHeicToJpegWithSips(buffer) {
|
|
|
194603
194950
|
"--out",
|
|
194604
194951
|
outputPath
|
|
194605
194952
|
]);
|
|
194606
|
-
return Buffer.from(await
|
|
194953
|
+
return Buffer.from(await readFile6(outputPath));
|
|
194607
194954
|
} finally {
|
|
194608
|
-
await
|
|
194955
|
+
await rm3(workDir, { recursive: true, force: true });
|
|
194609
194956
|
}
|
|
194610
194957
|
}
|
|
194611
194958
|
var init_image_resize_sips = () => {};
|
|
@@ -194685,13 +195032,40 @@ async function normalizeMessageContentImages(content, resize = resizeImageIfNeed
|
|
|
194685
195032
|
const filteredParts = normalizedParts.filter((part) => part !== null);
|
|
194686
195033
|
return didChange ? filteredParts : content;
|
|
194687
195034
|
}
|
|
194688
|
-
async function
|
|
195035
|
+
async function normalizeApprovalImages(message, resize, failureMode) {
|
|
195036
|
+
if (!Array.isArray(message.approvals)) {
|
|
195037
|
+
return message;
|
|
195038
|
+
}
|
|
194689
195039
|
let didChange = false;
|
|
195040
|
+
const approvals = await Promise.all(message.approvals.map(async (approval) => {
|
|
195041
|
+
if (!("tool_return" in approval)) {
|
|
195042
|
+
return approval;
|
|
195043
|
+
}
|
|
195044
|
+
const toolReturn = await normalizeMessageContentImages(approval.tool_return, resize, failureMode);
|
|
195045
|
+
if (toolReturn === approval.tool_return) {
|
|
195046
|
+
return approval;
|
|
195047
|
+
}
|
|
195048
|
+
didChange = true;
|
|
195049
|
+
return {
|
|
195050
|
+
...approval,
|
|
195051
|
+
tool_return: toolReturn
|
|
195052
|
+
};
|
|
195053
|
+
}));
|
|
195054
|
+
return didChange ? { ...message, approvals } : message;
|
|
195055
|
+
}
|
|
195056
|
+
async function normalizeMessageImageParts(messages, options3 = {}) {
|
|
195057
|
+
let didChange = false;
|
|
195058
|
+
const resize = options3.resize ?? resizeImageIfNeeded3;
|
|
194690
195059
|
const normalizedMessages = await Promise.all(messages.map(async (message) => {
|
|
195060
|
+
const failureMode = getImageFailureMode(message, options3.failureModesByMessageOtid);
|
|
194691
195061
|
if (!("content" in message)) {
|
|
194692
|
-
|
|
195062
|
+
const normalizedApproval = await normalizeApprovalImages(message, resize, failureMode);
|
|
195063
|
+
if (normalizedApproval !== message) {
|
|
195064
|
+
didChange = true;
|
|
195065
|
+
}
|
|
195066
|
+
return normalizedApproval;
|
|
194693
195067
|
}
|
|
194694
|
-
const normalizedContent = await normalizeMessageContentImages(message.content, resize);
|
|
195068
|
+
const normalizedContent = await normalizeMessageContentImages(message.content, resize, failureMode);
|
|
194695
195069
|
if (normalizedContent !== message.content) {
|
|
194696
195070
|
didChange = true;
|
|
194697
195071
|
return {
|
|
@@ -194703,18 +195077,51 @@ async function normalizeMessageImageParts(messages, resize = resizeImageIfNeeded
|
|
|
194703
195077
|
}));
|
|
194704
195078
|
return didChange ? normalizedMessages : messages;
|
|
194705
195079
|
}
|
|
195080
|
+
function getImageFailureMode(message, failureModesByMessageOtid) {
|
|
195081
|
+
if (!failureModesByMessageOtid) {
|
|
195082
|
+
return "strict";
|
|
195083
|
+
}
|
|
195084
|
+
const otid = message.otid;
|
|
195085
|
+
return typeof otid === "string" ? failureModesByMessageOtid[otid] ?? "strict" : "strict";
|
|
195086
|
+
}
|
|
195087
|
+
function buildImageFailureModesByMessageOtid(messages, failureMode) {
|
|
195088
|
+
const entries = [];
|
|
195089
|
+
for (const message of messages) {
|
|
195090
|
+
if (!("content" in message)) {
|
|
195091
|
+
continue;
|
|
195092
|
+
}
|
|
195093
|
+
const otid = message.otid;
|
|
195094
|
+
if (typeof otid === "string" && otid.length > 0) {
|
|
195095
|
+
entries.push([otid, failureMode]);
|
|
195096
|
+
}
|
|
195097
|
+
}
|
|
195098
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
195099
|
+
}
|
|
195100
|
+
function mergeImageFailureModesByMessageOtid(...failureModes) {
|
|
195101
|
+
const presentModes = failureModes.filter((modes) => modes !== undefined);
|
|
195102
|
+
return presentModes.length > 0 ? Object.assign({}, ...presentModes) : undefined;
|
|
195103
|
+
}
|
|
194706
195104
|
function assertSupportedBase64ImageMediaTypes(messages) {
|
|
194707
195105
|
for (const message of messages) {
|
|
194708
|
-
if (
|
|
195106
|
+
if ("content" in message) {
|
|
195107
|
+
assertSupportedBase64ImageContent(message.content);
|
|
194709
195108
|
continue;
|
|
194710
195109
|
}
|
|
194711
|
-
for (const
|
|
194712
|
-
if (!
|
|
195110
|
+
for (const approval of message.approvals ?? []) {
|
|
195111
|
+
if (!("tool_return" in approval)) {
|
|
194713
195112
|
continue;
|
|
194714
195113
|
}
|
|
194715
|
-
|
|
194716
|
-
|
|
194717
|
-
|
|
195114
|
+
assertSupportedBase64ImageContent(approval.tool_return);
|
|
195115
|
+
}
|
|
195116
|
+
}
|
|
195117
|
+
}
|
|
195118
|
+
function assertSupportedBase64ImageContent(content) {
|
|
195119
|
+
if (typeof content === "string") {
|
|
195120
|
+
return;
|
|
195121
|
+
}
|
|
195122
|
+
for (const part of content) {
|
|
195123
|
+
if (isBase64ImageContentPart(part) && !isSupportedBase64ImageMediaType(part.source.media_type)) {
|
|
195124
|
+
throw new Error(`Unsupported base64 image media type after normalization: ${part.source.media_type}`);
|
|
194718
195125
|
}
|
|
194719
195126
|
}
|
|
194720
195127
|
}
|
|
@@ -194927,7 +195334,7 @@ __export(exports_skills2, {
|
|
|
194927
195334
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
|
|
194928
195335
|
});
|
|
194929
195336
|
import { existsSync as existsSync22 } from "node:fs";
|
|
194930
|
-
import { readdir as readdir3, readFile as
|
|
195337
|
+
import { readdir as readdir3, readFile as readFile7, realpath, stat as stat4 } from "node:fs/promises";
|
|
194931
195338
|
import { dirname as dirname12, join as join30 } from "node:path";
|
|
194932
195339
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
194933
195340
|
function getBundledSkillsPath() {
|
|
@@ -195099,7 +195506,7 @@ async function findSkillFiles(currentPath, rootPath, skills, errors7, source2, v
|
|
|
195099
195506
|
}
|
|
195100
195507
|
}
|
|
195101
195508
|
async function parseSkillFile(filePath, rootPath, source2) {
|
|
195102
|
-
const content = await
|
|
195509
|
+
const content = await readFile7(filePath, "utf-8");
|
|
195103
195510
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
195104
195511
|
const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
|
|
195105
195512
|
const relativePath = filePath.slice(normalizedRoot.length + 1);
|
|
@@ -195533,12 +195940,15 @@ function getStreamRequestContext(stream11) {
|
|
|
195533
195940
|
return streamRequestContexts.get(stream11);
|
|
195534
195941
|
}
|
|
195535
195942
|
function buildConversationMessagesCreateRequestBody(conversationId, messages, opts = { streamTokens: true, background: true }, clientTools, clientSkills = []) {
|
|
195943
|
+
return buildRequestBodyFromPreparedMessages(conversationId, normalizeOutgoingApprovalMessages(messages, opts.approvalNormalization), opts, clientTools, clientSkills);
|
|
195944
|
+
}
|
|
195945
|
+
function buildRequestBodyFromPreparedMessages(conversationId, messages, opts, clientTools, clientSkills) {
|
|
195536
195946
|
const isDefaultConversation = conversationId === "default";
|
|
195537
195947
|
if (isDefaultConversation && !opts.agentId) {
|
|
195538
195948
|
throw new Error("agentId is required in opts when using default conversation");
|
|
195539
195949
|
}
|
|
195540
195950
|
return {
|
|
195541
|
-
messages
|
|
195951
|
+
messages,
|
|
195542
195952
|
streaming: true,
|
|
195543
195953
|
stream_tokens: opts.streamTokens ?? true,
|
|
195544
195954
|
include_pings: true,
|
|
@@ -195560,7 +195970,10 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
|
|
|
195560
195970
|
}) {
|
|
195561
195971
|
const requestStartTime = isTimingsEnabled() ? performance.now() : undefined;
|
|
195562
195972
|
const requestStartedAtMs = Date.now();
|
|
195563
|
-
const
|
|
195973
|
+
const canonicalMessages = normalizeOutgoingApprovalMessages(messages, opts.approvalNormalization);
|
|
195974
|
+
const normalizedMessages = await normalizeMessageImageParts(canonicalMessages, {
|
|
195975
|
+
failureModesByMessageOtid: opts.imageFailureModesByMessageOtid
|
|
195976
|
+
});
|
|
195564
195977
|
assertSupportedBase64ImageMediaTypes(normalizedMessages);
|
|
195565
195978
|
const preparedToolContext = opts.preparedToolContext ? opts.preparedToolContext : await (async () => {
|
|
195566
195979
|
await waitForToolsetReady();
|
|
@@ -195579,7 +195992,7 @@ async function sendMessageStreamWithBackend(backend, conversationId, messages, o
|
|
|
195579
195992
|
const isApprovalContinuation = isApprovalContinuationRequest(normalizedMessages);
|
|
195580
195993
|
const canUsePreviousResponseState = isApprovalContinuation && opts.allowResponseStateReuse === true;
|
|
195581
195994
|
const previousResponseId = canUsePreviousResponseState ? responseStateIdsByScope.get(responseStateScope) : undefined;
|
|
195582
|
-
const requestBody =
|
|
195995
|
+
const requestBody = buildRequestBodyFromPreparedMessages(conversationId, normalizedMessages, opts, clientTools, clientSkills);
|
|
195583
195996
|
if (isDebugEnabled()) {
|
|
195584
195997
|
debugLog("agent-message", "sendMessageStream: conversationId=%s, agentId=%s", conversationId, opts.agentId ?? "(none)");
|
|
195585
195998
|
const formattedSkills = clientSkills.map((skill) => `${skill.name} (${skill.location})`);
|
|
@@ -198391,7 +198804,7 @@ var require_typescript = __commonJS((exports, module3) => {
|
|
|
198391
198804
|
walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
|
|
198392
198805
|
whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
|
|
198393
198806
|
writeCommentRange: () => writeCommentRange,
|
|
198394
|
-
writeFile: () =>
|
|
198807
|
+
writeFile: () => writeFile11,
|
|
198395
198808
|
writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
|
|
198396
198809
|
zipWith: () => zipWith
|
|
198397
198810
|
});
|
|
@@ -204183,7 +204596,7 @@ ${lanes.join(`
|
|
|
204183
204596
|
writeOutputIsTTY() {
|
|
204184
204597
|
return process.stdout.isTTY;
|
|
204185
204598
|
},
|
|
204186
|
-
readFile:
|
|
204599
|
+
readFile: readFile8,
|
|
204187
204600
|
writeFile: writeFile22,
|
|
204188
204601
|
watchFile: watchFile2,
|
|
204189
204602
|
watchDirectory,
|
|
@@ -204376,7 +204789,7 @@ ${lanes.join(`
|
|
|
204376
204789
|
function fsWatchWorker(fileOrDirectory, recursive, callback) {
|
|
204377
204790
|
return _fs.watch(fileOrDirectory, fsSupportsRecursiveFsWatch ? { persistent: true, recursive: !!recursive } : { persistent: true }, callback);
|
|
204378
204791
|
}
|
|
204379
|
-
function
|
|
204792
|
+
function readFile8(fileName, _encoding) {
|
|
204380
204793
|
let buffer;
|
|
204381
204794
|
try {
|
|
204382
204795
|
buffer = _fs.readFileSync(fileName);
|
|
@@ -215700,7 +216113,7 @@ ${lanes.join(`
|
|
|
215700
216113
|
sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
|
|
215701
216114
|
return combinePaths(newDirPath, sourceFilePath);
|
|
215702
216115
|
}
|
|
215703
|
-
function
|
|
216116
|
+
function writeFile11(host, diagnostics2, fileName, text, writeByteOrderMark, sourceFiles, data) {
|
|
215704
216117
|
host.writeFile(fileName, text, writeByteOrderMark, (hostErrorMessage) => {
|
|
215705
216118
|
diagnostics2.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
|
|
215706
216119
|
}, sourceFiles, data);
|
|
@@ -226153,8 +226566,8 @@ ${lanes.join(`
|
|
|
226153
226566
|
return;
|
|
226154
226567
|
}
|
|
226155
226568
|
function tryRenameExternalModule(factory2, moduleName, sourceFile) {
|
|
226156
|
-
const
|
|
226157
|
-
return
|
|
226569
|
+
const rename2 = sourceFile.renamedDependencies && sourceFile.renamedDependencies.get(moduleName.text);
|
|
226570
|
+
return rename2 ? factory2.createStringLiteral(rename2) : undefined;
|
|
226158
226571
|
}
|
|
226159
226572
|
function tryGetModuleNameFromFile(factory2, file3, host, options3) {
|
|
226160
226573
|
if (!file3) {
|
|
@@ -228683,8 +229096,8 @@ ${lanes.join(`
|
|
|
228683
229096
|
function isMissingList(arr) {
|
|
228684
229097
|
return !!arr.isMissingList;
|
|
228685
229098
|
}
|
|
228686
|
-
function parseBracketedList(kind, parseElement,
|
|
228687
|
-
if (parseExpected(
|
|
229099
|
+
function parseBracketedList(kind, parseElement, open3, close) {
|
|
229100
|
+
if (parseExpected(open3)) {
|
|
228688
229101
|
const result = parseDelimitedList(kind, parseElement);
|
|
228689
229102
|
parseExpected(close);
|
|
228690
229103
|
return result;
|
|
@@ -230389,12 +230802,12 @@ ${lanes.join(`
|
|
|
230389
230802
|
parseExpected(20);
|
|
230390
230803
|
return finishNode(factory2.createJsxSpreadAttribute(expression), pos);
|
|
230391
230804
|
}
|
|
230392
|
-
function parseJsxClosingElement(
|
|
230805
|
+
function parseJsxClosingElement(open3, inExpressionContext) {
|
|
230393
230806
|
const pos = getNodePos();
|
|
230394
230807
|
parseExpected(31);
|
|
230395
230808
|
const tagName = parseJsxElementName();
|
|
230396
230809
|
if (parseExpected(32, undefined, false)) {
|
|
230397
|
-
if (inExpressionContext || !tagNamesAreEquivalent(
|
|
230810
|
+
if (inExpressionContext || !tagNamesAreEquivalent(open3.tagName, tagName)) {
|
|
230398
230811
|
nextToken();
|
|
230399
230812
|
} else {
|
|
230400
230813
|
scanJsxText();
|
|
@@ -235323,7 +235736,7 @@ ${lanes.join(`
|
|
|
235323
235736
|
const possibleOption = getSpellingSuggestion(unknownOption, diagnostics2.optionDeclarations, getOptionName);
|
|
235324
235737
|
return possibleOption ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics2.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption);
|
|
235325
235738
|
}
|
|
235326
|
-
function parseCommandLineWorker(diagnostics2, commandLine,
|
|
235739
|
+
function parseCommandLineWorker(diagnostics2, commandLine, readFile8) {
|
|
235327
235740
|
const options3 = {};
|
|
235328
235741
|
let watchOptions;
|
|
235329
235742
|
const fileNames = [];
|
|
@@ -235361,7 +235774,7 @@ ${lanes.join(`
|
|
|
235361
235774
|
}
|
|
235362
235775
|
}
|
|
235363
235776
|
function parseResponseFile(fileName) {
|
|
235364
|
-
const text = tryReadFile(fileName,
|
|
235777
|
+
const text = tryReadFile(fileName, readFile8 || ((fileName2) => sys.readFile(fileName2)));
|
|
235365
235778
|
if (!isString(text)) {
|
|
235366
235779
|
errors7.push(text);
|
|
235367
235780
|
return;
|
|
@@ -235464,8 +235877,8 @@ ${lanes.join(`
|
|
|
235464
235877
|
unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1,
|
|
235465
235878
|
optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument
|
|
235466
235879
|
};
|
|
235467
|
-
function parseCommandLine(commandLine,
|
|
235468
|
-
return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine,
|
|
235880
|
+
function parseCommandLine(commandLine, readFile8) {
|
|
235881
|
+
return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile8);
|
|
235469
235882
|
}
|
|
235470
235883
|
function getOptionFromName(optionName, allowShort) {
|
|
235471
235884
|
return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort);
|
|
@@ -235533,8 +235946,8 @@ ${lanes.join(`
|
|
|
235533
235946
|
result.originalFileName = result.fileName;
|
|
235534
235947
|
return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd), undefined, extraFileExtensions, extendedConfigCache, watchOptionsToExtend);
|
|
235535
235948
|
}
|
|
235536
|
-
function readConfigFile(fileName,
|
|
235537
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
235949
|
+
function readConfigFile(fileName, readFile8) {
|
|
235950
|
+
const textOrDiagnostic = tryReadFile(fileName, readFile8);
|
|
235538
235951
|
return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
|
|
235539
235952
|
}
|
|
235540
235953
|
function parseConfigFileTextToJson(fileName, jsonText) {
|
|
@@ -235544,14 +235957,14 @@ ${lanes.join(`
|
|
|
235544
235957
|
error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined
|
|
235545
235958
|
};
|
|
235546
235959
|
}
|
|
235547
|
-
function readJsonConfigFile(fileName,
|
|
235548
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
235960
|
+
function readJsonConfigFile(fileName, readFile8) {
|
|
235961
|
+
const textOrDiagnostic = tryReadFile(fileName, readFile8);
|
|
235549
235962
|
return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] };
|
|
235550
235963
|
}
|
|
235551
|
-
function tryReadFile(fileName,
|
|
235964
|
+
function tryReadFile(fileName, readFile8) {
|
|
235552
235965
|
let text;
|
|
235553
235966
|
try {
|
|
235554
|
-
text =
|
|
235967
|
+
text = readFile8(fileName);
|
|
235555
235968
|
} catch (e2) {
|
|
235556
235969
|
return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e2.message);
|
|
235557
235970
|
}
|
|
@@ -298293,7 +298706,7 @@ ${lanes.join(`
|
|
|
298293
298706
|
return;
|
|
298294
298707
|
}
|
|
298295
298708
|
const buildInfo = host.getBuildInfo() || { version: version2 };
|
|
298296
|
-
|
|
298709
|
+
writeFile11(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), false, undefined, { buildInfo });
|
|
298297
298710
|
emittedFilesList == null || emittedFilesList.push(buildInfoPath);
|
|
298298
298711
|
}
|
|
298299
298712
|
function emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath) {
|
|
@@ -298452,14 +298865,14 @@ ${lanes.join(`
|
|
|
298452
298865
|
}
|
|
298453
298866
|
if (sourceMapFilePath) {
|
|
298454
298867
|
const sourceMap = sourceMapGenerator.toString();
|
|
298455
|
-
|
|
298868
|
+
writeFile11(host, emitterDiagnostics, sourceMapFilePath, sourceMap, false, sourceFiles);
|
|
298456
298869
|
}
|
|
298457
298870
|
} else {
|
|
298458
298871
|
writer.writeLine();
|
|
298459
298872
|
}
|
|
298460
298873
|
const text = writer.getText();
|
|
298461
298874
|
const data = { sourceMapUrlPos, diagnostics: transform22.diagnostics };
|
|
298462
|
-
|
|
298875
|
+
writeFile11(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, data);
|
|
298463
298876
|
writer.clear();
|
|
298464
298877
|
return !data.skippedDtsWrite;
|
|
298465
298878
|
}
|
|
@@ -302981,12 +303394,12 @@ ${lanes.join(`
|
|
|
302981
303394
|
function createCompilerHost(options3, setParentNodes) {
|
|
302982
303395
|
return createCompilerHostWorker(options3, setParentNodes);
|
|
302983
303396
|
}
|
|
302984
|
-
function createGetSourceFile(
|
|
303397
|
+
function createGetSourceFile(readFile8, setParentNodes) {
|
|
302985
303398
|
return (fileName, languageVersionOrOptions, onError) => {
|
|
302986
303399
|
let text;
|
|
302987
303400
|
try {
|
|
302988
303401
|
mark("beforeIORead");
|
|
302989
|
-
text =
|
|
303402
|
+
text = readFile8(fileName);
|
|
302990
303403
|
mark("afterIORead");
|
|
302991
303404
|
measure("I/O Read", "beforeIORead", "afterIORead");
|
|
302992
303405
|
} catch (e2) {
|
|
@@ -303777,7 +304190,7 @@ ${lanes.join(`
|
|
|
303777
304190
|
getRedirectFromOutput,
|
|
303778
304191
|
forEachResolvedProjectReference: forEachResolvedProjectReference2
|
|
303779
304192
|
});
|
|
303780
|
-
const
|
|
304193
|
+
const readFile8 = host.readFile.bind(host);
|
|
303781
304194
|
(_e = tracing) == null || _e.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
|
|
303782
304195
|
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options3);
|
|
303783
304196
|
(_f = tracing) == null || _f.pop();
|
|
@@ -303953,7 +304366,7 @@ ${lanes.join(`
|
|
|
303953
304366
|
shouldTransformImportCall,
|
|
303954
304367
|
emitBuildInfo,
|
|
303955
304368
|
fileExists,
|
|
303956
|
-
readFile:
|
|
304369
|
+
readFile: readFile8,
|
|
303957
304370
|
directoryExists,
|
|
303958
304371
|
getSymlinkCache,
|
|
303959
304372
|
realpath: (_o = host.realpath) == null ? undefined : _o.bind(host),
|
|
@@ -330254,11 +330667,11 @@ ${newComment.split(`
|
|
|
330254
330667
|
}
|
|
330255
330668
|
function convertNamedExport(sourceFile, assignment, changes, exports2) {
|
|
330256
330669
|
const { text } = assignment.left.name;
|
|
330257
|
-
const
|
|
330258
|
-
if (
|
|
330670
|
+
const rename2 = exports2.get(text);
|
|
330671
|
+
if (rename2 !== undefined) {
|
|
330259
330672
|
const newNodes = [
|
|
330260
|
-
makeConst(undefined,
|
|
330261
|
-
makeExportDeclaration([factory.createExportSpecifier(false,
|
|
330673
|
+
makeConst(undefined, rename2, assignment.right),
|
|
330674
|
+
makeExportDeclaration([factory.createExportSpecifier(false, rename2, text)])
|
|
330262
330675
|
];
|
|
330263
330676
|
changes.replaceNodeWithNodes(sourceFile, assignment.parent, newNodes);
|
|
330264
330677
|
} else {
|
|
@@ -346878,11 +347291,11 @@ ${content}
|
|
|
346878
347291
|
}
|
|
346879
347292
|
return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), "code");
|
|
346880
347293
|
}
|
|
346881
|
-
function spanForObjectOrArrayLiteral(node,
|
|
346882
|
-
return spanForNode(node, false, !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent),
|
|
347294
|
+
function spanForObjectOrArrayLiteral(node, open3 = 19) {
|
|
347295
|
+
return spanForNode(node, false, !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open3);
|
|
346883
347296
|
}
|
|
346884
|
-
function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true,
|
|
346885
|
-
const openToken = findChildOfKind(n,
|
|
347297
|
+
function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open3 = 19, close = open3 === 19 ? 20 : 24) {
|
|
347298
|
+
const openToken = findChildOfKind(n, open3, sourceFile);
|
|
346886
347299
|
const closeToken = findChildOfKind(n, close, sourceFile);
|
|
346887
347300
|
return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart);
|
|
346888
347301
|
}
|
|
@@ -349150,9 +349563,9 @@ ${options3.prefix}` : `
|
|
|
349150
349563
|
return end;
|
|
349151
349564
|
}
|
|
349152
349565
|
function getClassOrObjectBraceEnds(cls, sourceFile) {
|
|
349153
|
-
const
|
|
349566
|
+
const open3 = findChildOfKind(cls, 19, sourceFile);
|
|
349154
349567
|
const close = findChildOfKind(cls, 20, sourceFile);
|
|
349155
|
-
return [
|
|
349568
|
+
return [open3 == null ? undefined : open3.end, close == null ? undefined : close.end];
|
|
349156
349569
|
}
|
|
349157
349570
|
function getMembersOrProperties(node) {
|
|
349158
349571
|
return isObjectLiteralExpression(node) ? node.properties : node.members;
|
|
@@ -354391,7 +354804,7 @@ ${options3.prefix}` : `
|
|
|
354391
354804
|
walkUpParenthesizedTypesAndGetParentAndChild: () => walkUpParenthesizedTypesAndGetParentAndChild,
|
|
354392
354805
|
whitespaceOrMapCommentRegExp: () => whitespaceOrMapCommentRegExp,
|
|
354393
354806
|
writeCommentRange: () => writeCommentRange,
|
|
354394
|
-
writeFile: () =>
|
|
354807
|
+
writeFile: () => writeFile11,
|
|
354395
354808
|
writeFileEnsuringDirectories: () => writeFileEnsuringDirectories,
|
|
354396
354809
|
zipWith: () => zipWith
|
|
354397
354810
|
});
|
|
@@ -367596,7 +368009,8 @@ function buildLoopStatus(runtime, params) {
|
|
|
367596
368009
|
if (!listener) {
|
|
367597
368010
|
return {
|
|
367598
368011
|
status: "WAITING_ON_INPUT",
|
|
367599
|
-
active_run_ids: []
|
|
368012
|
+
active_run_ids: [],
|
|
368013
|
+
executing_tool_call_ids: []
|
|
367600
368014
|
};
|
|
367601
368015
|
}
|
|
367602
368016
|
const scope = getScopeForRuntime(runtime, params);
|
|
@@ -367608,7 +368022,8 @@ function buildLoopStatus(runtime, params) {
|
|
|
367608
368022
|
const status = interruptedCacheActive ? !conversationRuntime?.isProcessing ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus === "WAITING_ON_APPROVAL" ? "WAITING_ON_INPUT" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT" : recovered && recovered.pendingRequestIds.size > 0 && conversationRuntime?.loopStatus === "WAITING_ON_INPUT" ? "WAITING_ON_APPROVAL" : conversationRuntime?.loopStatus ?? "WAITING_ON_INPUT";
|
|
367609
368023
|
return {
|
|
367610
368024
|
status,
|
|
367611
|
-
active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : []
|
|
368025
|
+
active_run_ids: interruptedCacheActive && !conversationRuntime?.isProcessing ? [] : conversationRuntime?.activeRunId ? [conversationRuntime.activeRunId] : [],
|
|
368026
|
+
executing_tool_call_ids: status === "EXECUTING_CLIENT_SIDE_TOOL" && conversationRuntime ? [...conversationRuntime.turnLifecycle.executingToolCallIds] : []
|
|
367612
368027
|
};
|
|
367613
368028
|
}
|
|
367614
368029
|
function buildQueueSnapshot(runtime, params) {
|
|
@@ -368054,6 +368469,13 @@ async function switchCurrentRuntimeWorkingDirectory(workingDirectory) {
|
|
|
368054
368469
|
process.env.USER_CWD = workingDirectory;
|
|
368055
368470
|
updateRuntimeContext({ workingDirectory });
|
|
368056
368471
|
}
|
|
368472
|
+
async function updateToolExecutionContextCwd(executionContextId, workingDirectory) {
|
|
368473
|
+
if (!executionContextId) {
|
|
368474
|
+
return;
|
|
368475
|
+
}
|
|
368476
|
+
const { updateToolExecutionContextWorkingDirectory } = await init_manager4().then(() => exports_manager2);
|
|
368477
|
+
updateToolExecutionContextWorkingDirectory(executionContextId, workingDirectory);
|
|
368478
|
+
}
|
|
368057
368479
|
async function switchConversationWorkingDirectory(params) {
|
|
368058
368480
|
const { runtime, workingDirectory } = params;
|
|
368059
368481
|
const agentId = normalizeCwdAgentId(params.agentId);
|
|
@@ -368227,7 +368649,7 @@ import {
|
|
|
368227
368649
|
lstat,
|
|
368228
368650
|
mkdir as mkdir8,
|
|
368229
368651
|
readdir as readdir5,
|
|
368230
|
-
readFile as
|
|
368652
|
+
readFile as readFile8,
|
|
368231
368653
|
realpath as realpath2,
|
|
368232
368654
|
rmdir,
|
|
368233
368655
|
stat as stat6,
|
|
@@ -368464,7 +368886,7 @@ async function readProvisionConfig(primaryRoot) {
|
|
|
368464
368886
|
include: []
|
|
368465
368887
|
};
|
|
368466
368888
|
try {
|
|
368467
|
-
const raw = await
|
|
368889
|
+
const raw = await readFile8(path19.join(primaryRoot, ".letta", "settings.json"), "utf8");
|
|
368468
368890
|
const parsed = JSON.parse(raw);
|
|
368469
368891
|
const worktree = parsed.worktree;
|
|
368470
368892
|
if (!worktree) {
|
|
@@ -368556,7 +368978,7 @@ async function copyLocalSettingsFile(primaryRoot, worktreePath) {
|
|
|
368556
368978
|
}
|
|
368557
368979
|
async function readWorktreeIncludeEntries(primaryRoot) {
|
|
368558
368980
|
try {
|
|
368559
|
-
const raw = await
|
|
368981
|
+
const raw = await readFile8(path19.join(primaryRoot, ".worktreeinclude"), "utf8");
|
|
368560
368982
|
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
368561
368983
|
} catch {
|
|
368562
368984
|
return [];
|
|
@@ -368657,13 +369079,10 @@ async function switchSessionToWorktree(params) {
|
|
|
368657
369079
|
agentId: runtimeContext.agentId ?? null,
|
|
368658
369080
|
conversationId: runtimeContext.conversationId
|
|
368659
369081
|
});
|
|
368660
|
-
|
|
368661
|
-
|
|
368662
|
-
await switchCurrentRuntimeWorkingDirectory(worktreePath);
|
|
368663
|
-
if (params.executionContextId) {
|
|
368664
|
-
const { updateToolExecutionContextWorkingDirectory } = await init_manager4().then(() => exports_manager2);
|
|
368665
|
-
updateToolExecutionContextWorkingDirectory(params.executionContextId, worktreePath);
|
|
369082
|
+
} else {
|
|
369083
|
+
await switchCurrentRuntimeWorkingDirectory(worktreePath);
|
|
368666
369084
|
}
|
|
369085
|
+
await updateToolExecutionContextCwd(params.executionContextId, worktreePath);
|
|
368667
369086
|
return true;
|
|
368668
369087
|
}
|
|
368669
369088
|
async function resolveWorktreeGitDir(worktreePath) {
|
|
@@ -371064,15 +371483,15 @@ var require_parse3 = __commonJS((exports, module3) => {
|
|
|
371064
371483
|
}
|
|
371065
371484
|
if (value === "{" && opts.nobrace !== true) {
|
|
371066
371485
|
increment("braces");
|
|
371067
|
-
const
|
|
371486
|
+
const open3 = {
|
|
371068
371487
|
type: "brace",
|
|
371069
371488
|
value,
|
|
371070
371489
|
output: "(",
|
|
371071
371490
|
outputIndex: state.output.length,
|
|
371072
371491
|
tokensIndex: state.tokens.length
|
|
371073
371492
|
};
|
|
371074
|
-
braces.push(
|
|
371075
|
-
push(
|
|
371493
|
+
braces.push(open3);
|
|
371494
|
+
push(open3);
|
|
371076
371495
|
continue;
|
|
371077
371496
|
}
|
|
371078
371497
|
if (value === "}") {
|
|
@@ -371723,12 +372142,12 @@ var init_list_directory_gemini = __esm(() => {
|
|
|
371723
372142
|
import { existsSync as existsSync27 } from "node:fs";
|
|
371724
372143
|
import {
|
|
371725
372144
|
mkdir as mkdir9,
|
|
371726
|
-
readFile as
|
|
371727
|
-
rename,
|
|
371728
|
-
rm as
|
|
372145
|
+
readFile as readFile9,
|
|
372146
|
+
rename as rename2,
|
|
372147
|
+
rm as rm4,
|
|
371729
372148
|
stat as stat8,
|
|
371730
372149
|
unlink as unlink2,
|
|
371731
|
-
writeFile as
|
|
372150
|
+
writeFile as writeFile11
|
|
371732
372151
|
} from "node:fs/promises";
|
|
371733
372152
|
import { dirname as dirname14, isAbsolute as isAbsolute15, relative as relative3, resolve as resolve18 } from "node:path";
|
|
371734
372153
|
async function getMemoryWriteSyncMode() {
|
|
@@ -371809,7 +372228,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371809
372228
|
throw new Error(`memory create: block already exists at ${pathArg}`);
|
|
371810
372229
|
}
|
|
371811
372230
|
await mkdir9(dirname14(filePath), { recursive: true });
|
|
371812
|
-
await
|
|
372231
|
+
await writeFile11(filePath, rendered, "utf8");
|
|
371813
372232
|
return [relPath];
|
|
371814
372233
|
}
|
|
371815
372234
|
if (command === "str_replace") {
|
|
@@ -371826,7 +372245,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371826
372245
|
}
|
|
371827
372246
|
const nextBody = `${file3.body.slice(0, idx)}${newString}${file3.body.slice(idx + oldString.length)}`;
|
|
371828
372247
|
const rendered = renderMemoryFile(file3.frontmatter, nextBody);
|
|
371829
|
-
await
|
|
372248
|
+
await writeFile11(filePath, rendered, "utf8");
|
|
371830
372249
|
return [relPath];
|
|
371831
372250
|
}
|
|
371832
372251
|
if (command === "insert") {
|
|
@@ -371849,7 +372268,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371849
372268
|
const nextBody = existingLines.join(`
|
|
371850
372269
|
`);
|
|
371851
372270
|
const rendered = renderMemoryFile(file3.frontmatter, nextBody);
|
|
371852
|
-
await
|
|
372271
|
+
await writeFile11(filePath, rendered, "utf8");
|
|
371853
372272
|
return [relPath];
|
|
371854
372273
|
}
|
|
371855
372274
|
if (command === "delete") {
|
|
@@ -371858,7 +372277,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371858
372277
|
const targetPath = resolveMemoryPath(memoryDir, label);
|
|
371859
372278
|
if (existsSync27(targetPath) && (await stat8(targetPath)).isDirectory()) {
|
|
371860
372279
|
const relPath2 = toRepoRelative(memoryDir, targetPath);
|
|
371861
|
-
await
|
|
372280
|
+
await rm4(targetPath, { recursive: true, force: false });
|
|
371862
372281
|
return [relPath2];
|
|
371863
372282
|
}
|
|
371864
372283
|
const filePath = resolveMemoryFilePath(memoryDir, label);
|
|
@@ -371881,7 +372300,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371881
372300
|
}
|
|
371882
372301
|
await loadEditableMemoryFile(oldFilePath, oldPathArg);
|
|
371883
372302
|
await mkdir9(dirname14(newFilePath), { recursive: true });
|
|
371884
|
-
await
|
|
372303
|
+
await rename2(oldFilePath, newFilePath);
|
|
371885
372304
|
return [oldRelPath, newRelPath];
|
|
371886
372305
|
}
|
|
371887
372306
|
if (command === "update_description") {
|
|
@@ -371895,7 +372314,7 @@ async function applyMemoryCommand(memoryDir, args) {
|
|
|
371895
372314
|
...file3.frontmatter,
|
|
371896
372315
|
description: newDescription
|
|
371897
372316
|
}, file3.body);
|
|
371898
|
-
await
|
|
372317
|
+
await writeFile11(filePath, rendered, "utf8");
|
|
371899
372318
|
return [relPath];
|
|
371900
372319
|
}
|
|
371901
372320
|
throw new Error(`Unsupported memory command: ${command}`);
|
|
@@ -371986,7 +372405,7 @@ function toRepoRelative(memoryDir, absolutePath) {
|
|
|
371986
372405
|
return rel.replace(/\\/g, "/");
|
|
371987
372406
|
}
|
|
371988
372407
|
async function loadEditableMemoryFile(filePath, sourcePath) {
|
|
371989
|
-
const content = await
|
|
372408
|
+
const content = await readFile9(filePath, "utf8").catch((error54) => {
|
|
371990
372409
|
const message = error54 instanceof Error ? error54.message : String(error54);
|
|
371991
372410
|
throw new Error(`memory: failed to read ${sourcePath}: ${message}`);
|
|
371992
372411
|
});
|
|
@@ -372082,7 +372501,7 @@ var init_memory4 = __esm(() => {
|
|
|
372082
372501
|
|
|
372083
372502
|
// src/tools/impl/memory-apply-patch.ts
|
|
372084
372503
|
import { existsSync as existsSync28 } from "node:fs";
|
|
372085
|
-
import { access, mkdir as mkdir10, rm as
|
|
372504
|
+
import { access, mkdir as mkdir10, rm as rm5, stat as stat9, unlink as unlink3 } from "node:fs/promises";
|
|
372086
372505
|
import { dirname as dirname15, isAbsolute as isAbsolute16, relative as relative4, resolve as resolve19 } from "node:path";
|
|
372087
372506
|
async function getMemoryWriteSyncMode2() {
|
|
372088
372507
|
const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
|
|
@@ -372235,7 +372654,7 @@ async function applyMemoryPatch(memoryDir, input) {
|
|
|
372235
372654
|
continue;
|
|
372236
372655
|
const stats = await stat9(absPath);
|
|
372237
372656
|
if (stats.isDirectory()) {
|
|
372238
|
-
await
|
|
372657
|
+
await rm5(absPath, { recursive: true, force: false });
|
|
372239
372658
|
} else {
|
|
372240
372659
|
await unlink3(absPath);
|
|
372241
372660
|
}
|
|
@@ -373246,6 +373665,7 @@ function normalizeMessageChannelInput(args) {
|
|
|
373246
373665
|
replyToMessageId: firstNonEmptyString3(args.replyTo),
|
|
373247
373666
|
threadId: firstNonEmptyString3(args.threadId) ?? null,
|
|
373248
373667
|
messageId: firstNonEmptyString3(args.messageId),
|
|
373668
|
+
attachmentId: firstNonEmptyString3(args.attachmentId),
|
|
373249
373669
|
emoji: firstNonEmptyString3(args.emoji),
|
|
373250
373670
|
remove: firstDefinedBoolean(args.remove),
|
|
373251
373671
|
mediaPath: firstNonEmptyString3(args.media),
|
|
@@ -373262,6 +373682,7 @@ function buildMessageChannelRequest(input, chatId, threadId) {
|
|
|
373262
373682
|
replyToMessageId: input.replyToMessageId,
|
|
373263
373683
|
threadId: threadId ?? input.threadId ?? null,
|
|
373264
373684
|
messageId: input.messageId,
|
|
373685
|
+
attachmentId: input.attachmentId,
|
|
373265
373686
|
emoji: input.emoji,
|
|
373266
373687
|
remove: input.remove,
|
|
373267
373688
|
mediaPath: input.mediaPath,
|
|
@@ -373367,6 +373788,9 @@ async function message_channel(args) {
|
|
|
373367
373788
|
if (typeof input === "string") {
|
|
373368
373789
|
return input;
|
|
373369
373790
|
}
|
|
373791
|
+
if (input.channel === "slack" && input.action === "download-file" && input.target) {
|
|
373792
|
+
return "Error: Slack download-file requires chat_id from a routed channel context; target is not supported.";
|
|
373793
|
+
}
|
|
373370
373794
|
try {
|
|
373371
373795
|
let executionContext;
|
|
373372
373796
|
if (input.chatId) {
|
|
@@ -373393,8 +373817,9 @@ async function message_channel(args) {
|
|
|
373393
373817
|
accountId: resolvedAccountId,
|
|
373394
373818
|
channelTurnSources: args.channelTurnSources
|
|
373395
373819
|
});
|
|
373820
|
+
const requestThreadId = input.action === "download-file" ? input.threadId : inferredThreadId ?? route2.threadId ?? input.threadId;
|
|
373396
373821
|
executionContext = {
|
|
373397
|
-
request: buildMessageChannelRequest(input, input.chatId,
|
|
373822
|
+
request: buildMessageChannelRequest(input, input.chatId, requestThreadId),
|
|
373398
373823
|
route: route2,
|
|
373399
373824
|
adapter: adapter2,
|
|
373400
373825
|
plugin: plugin2
|
|
@@ -375709,10 +376134,10 @@ globstar while`, file3, fr, pattern4, pr, swallowee);
|
|
|
375709
376134
|
}
|
|
375710
376135
|
return filtered.join("/");
|
|
375711
376136
|
}).join("|");
|
|
375712
|
-
const [
|
|
375713
|
-
re = "^" +
|
|
376137
|
+
const [open3, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
376138
|
+
re = "^" + open3 + re + close + "$";
|
|
375714
376139
|
if (this.partial) {
|
|
375715
|
-
re = "^(?:\\/|" +
|
|
376140
|
+
re = "^(?:\\/|" + open3 + re.slice(1, -1) + close + ")$";
|
|
375716
376141
|
}
|
|
375717
376142
|
if (this.negate)
|
|
375718
376143
|
re = "^(?!" + re + ").+$";
|
|
@@ -381703,7 +382128,7 @@ __export(exports_skill, {
|
|
|
381703
382128
|
getResolvedSkillsDir: () => getResolvedSkillsDir
|
|
381704
382129
|
});
|
|
381705
382130
|
import { existsSync as existsSync29, readdirSync as readdirSync10 } from "node:fs";
|
|
381706
|
-
import { readFile as
|
|
382131
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
381707
382132
|
import { dirname as dirname16, join as join34 } from "node:path";
|
|
381708
382133
|
function getMemorySkillsDirs2(agentId) {
|
|
381709
382134
|
const dirs = new Set;
|
|
@@ -381735,41 +382160,41 @@ async function readSkillContent(skillId, skillsDir, agentId) {
|
|
|
381735
382160
|
for (const projectSkillsDir of projectSkillsDirs) {
|
|
381736
382161
|
const projectSkillPath = join34(projectSkillsDir, skillId, "SKILL.md");
|
|
381737
382162
|
try {
|
|
381738
|
-
const content = await
|
|
382163
|
+
const content = await readFile10(projectSkillPath, "utf-8");
|
|
381739
382164
|
return { content, path: projectSkillPath };
|
|
381740
382165
|
} catch {}
|
|
381741
382166
|
}
|
|
381742
382167
|
if (agentId) {
|
|
381743
382168
|
const agentSkillPath = join34(getAgentSkillsDir(agentId), skillId, "SKILL.md");
|
|
381744
382169
|
try {
|
|
381745
|
-
const content = await
|
|
382170
|
+
const content = await readFile10(agentSkillPath, "utf-8");
|
|
381746
382171
|
return { content, path: agentSkillPath };
|
|
381747
382172
|
} catch {}
|
|
381748
382173
|
}
|
|
381749
382174
|
for (const memorySkillsDir of getMemorySkillsDirs2(agentId)) {
|
|
381750
382175
|
const memorySkillPath = join34(memorySkillsDir, skillId, "SKILL.md");
|
|
381751
382176
|
try {
|
|
381752
|
-
const content = await
|
|
382177
|
+
const content = await readFile10(memorySkillPath, "utf-8");
|
|
381753
382178
|
return { content, path: memorySkillPath };
|
|
381754
382179
|
} catch {}
|
|
381755
382180
|
}
|
|
381756
382181
|
const globalSkillPath = join34(GLOBAL_SKILLS_DIR, skillId, "SKILL.md");
|
|
381757
382182
|
try {
|
|
381758
|
-
const content = await
|
|
382183
|
+
const content = await readFile10(globalSkillPath, "utf-8");
|
|
381759
382184
|
return { content, path: globalSkillPath };
|
|
381760
382185
|
} catch {}
|
|
381761
382186
|
const bundledSkills = await getBundledSkills();
|
|
381762
382187
|
const bundledSkill = bundledSkills.find((s2) => s2.id === skillId);
|
|
381763
382188
|
if (bundledSkill?.path && isSkillAvailableForAgent(bundledSkill, agentId)) {
|
|
381764
382189
|
try {
|
|
381765
|
-
const content = await
|
|
382190
|
+
const content = await readFile10(bundledSkill.path, "utf-8");
|
|
381766
382191
|
return { content, path: bundledSkill.path };
|
|
381767
382192
|
} catch {}
|
|
381768
382193
|
}
|
|
381769
382194
|
try {
|
|
381770
382195
|
const bundledSkillsDir = join34(process.cwd(), "skills", "skills");
|
|
381771
382196
|
const bundledSkillPath = join34(bundledSkillsDir, skillId, "SKILL.md");
|
|
381772
|
-
const content = await
|
|
382197
|
+
const content = await readFile10(bundledSkillPath, "utf-8");
|
|
381773
382198
|
return { content, path: bundledSkillPath };
|
|
381774
382199
|
} catch {
|
|
381775
382200
|
throw new Error(`Skill "${skillId}" not found. Check that the skill name is correct and that it appears in the available skills list.`);
|
|
@@ -383124,7 +383549,11 @@ function buildSubagentArgs(type3, config3, model, userPrompt, existingAgentId, e
|
|
|
383124
383549
|
args.push("--agent", existingAgentId, "--new");
|
|
383125
383550
|
}
|
|
383126
383551
|
} else {
|
|
383127
|
-
|
|
383552
|
+
if (options3.systemPromptOverride) {
|
|
383553
|
+
args.push("--new-agent", "--system-custom", options3.systemPromptOverride);
|
|
383554
|
+
} else {
|
|
383555
|
+
args.push("--new-agent", "--system", type3);
|
|
383556
|
+
}
|
|
383128
383557
|
const subagentTags = [`type:${type3}`];
|
|
383129
383558
|
if (options3.parentAgentId) {
|
|
383130
383559
|
subagentTags.push(`parent:${options3.parentAgentId}`);
|
|
@@ -383171,7 +383600,7 @@ function buildSubagentArgs(type3, config3, model, userPrompt, existingAgentId, e
|
|
|
383171
383600
|
}
|
|
383172
383601
|
return args;
|
|
383173
383602
|
}
|
|
383174
|
-
async function executeSubagent(type3, config3, model, userPrompt,
|
|
383603
|
+
async function executeSubagent(type3, config3, model, userPrompt, subagentId, isRetry = false, signal, existingAgentId, existingConversationId, maxTurns, parentAgentIdOverride, transcriptPath, memoryScope, systemPromptOverride) {
|
|
383175
383604
|
if (signal?.aborted) {
|
|
383176
383605
|
return {
|
|
383177
383606
|
agentId: "",
|
|
@@ -383199,7 +383628,8 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383199
383628
|
backendMode,
|
|
383200
383629
|
promptTransport: "stdin",
|
|
383201
383630
|
parentAgentId,
|
|
383202
|
-
extraTools: config3.fork && inheritedChannelContext ? ["MessageChannel"] : undefined
|
|
383631
|
+
extraTools: config3.fork && inheritedChannelContext ? ["MessageChannel"] : undefined,
|
|
383632
|
+
systemPromptOverride
|
|
383203
383633
|
});
|
|
383204
383634
|
const launcher = resolveSubagentLauncher(cliArgs);
|
|
383205
383635
|
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
@@ -383314,7 +383744,7 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383314
383744
|
agentId: parentAgentIdOverride
|
|
383315
383745
|
});
|
|
383316
383746
|
if (primaryModel) {
|
|
383317
|
-
return executeSubagent(type3, config3, primaryModel, userPrompt,
|
|
383747
|
+
return executeSubagent(type3, config3, primaryModel, userPrompt, subagentId, true, signal, undefined, undefined, maxTurns, parentAgentIdOverride, transcriptPath);
|
|
383318
383748
|
}
|
|
383319
383749
|
}
|
|
383320
383750
|
const propagatedError = state.finalError?.trim();
|
|
@@ -383369,14 +383799,6 @@ async function executeSubagent(type3, config3, model, userPrompt, baseURL, subag
|
|
|
383369
383799
|
};
|
|
383370
383800
|
}
|
|
383371
383801
|
}
|
|
383372
|
-
function getBaseURL() {
|
|
383373
|
-
const settings3 = settingsManager.getSettings();
|
|
383374
|
-
const baseURL = process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || "https://api.letta.com";
|
|
383375
|
-
if (baseURL === "https://api.letta.com") {
|
|
383376
|
-
return "https://app.letta.com";
|
|
383377
|
-
}
|
|
383378
|
-
return baseURL;
|
|
383379
|
-
}
|
|
383380
383802
|
function buildDeploySystemReminder(senderAgentName, senderAgentId) {
|
|
383381
383803
|
return `${SYSTEM_REMINDER_OPEN}
|
|
383382
383804
|
This task is from "${senderAgentName}" (agent ID: ${senderAgentId}), which deployed you as a subagent inside the Letta Code CLI (docs.letta.com/letta-code).
|
|
@@ -383420,7 +383842,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
383420
383842
|
|
|
383421
383843
|
`;
|
|
383422
383844
|
}
|
|
383423
|
-
async function spawnSubagent(type3, prompt, userModel, subagentId, signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentId, transcriptPath, parentConversationId, memoryScope) {
|
|
383845
|
+
async function spawnSubagent(type3, prompt, userModel, subagentId, signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentId, transcriptPath, parentConversationId, memoryScope, systemPromptOverride) {
|
|
383424
383846
|
const allConfigs = await getAllSubagentConfigs();
|
|
383425
383847
|
const config3 = allConfigs[type3];
|
|
383426
383848
|
if (!config3) {
|
|
@@ -383459,7 +383881,6 @@ async function spawnSubagent(type3, prompt, userModel, subagentId, signal, exist
|
|
|
383459
383881
|
subagentType: type3,
|
|
383460
383882
|
backendMode
|
|
383461
383883
|
});
|
|
383462
|
-
const baseURL = getBaseURL();
|
|
383463
383884
|
let finalPrompt = prompt;
|
|
383464
383885
|
if (isDeployingExisting && resolvedParentAgentId) {
|
|
383465
383886
|
try {
|
|
@@ -383479,7 +383900,7 @@ async function spawnSubagent(type3, prompt, userModel, subagentId, signal, exist
|
|
|
383479
383900
|
});
|
|
383480
383901
|
updateSubagent(subagentId, { agentURL: forkAgentURL });
|
|
383481
383902
|
}
|
|
383482
|
-
const result = await executeSubagent(type3, config3, model, finalPrompt,
|
|
383903
|
+
const result = await executeSubagent(type3, config3, model, finalPrompt, subagentId, false, signal, existingAgentId, existingConversationId, maxTurns, resolvedParentAgentId, transcriptPath, memoryScope, systemPromptOverride);
|
|
383483
383904
|
return result;
|
|
383484
383905
|
}
|
|
383485
383906
|
var NO_BASE_TOOL_SUBAGENT_TYPES;
|
|
@@ -383734,6 +384155,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
383734
384155
|
prompt,
|
|
383735
384156
|
description,
|
|
383736
384157
|
model,
|
|
384158
|
+
systemPromptOverride,
|
|
383737
384159
|
toolCallId,
|
|
383738
384160
|
existingAgentId,
|
|
383739
384161
|
existingConversationId,
|
|
@@ -383776,7 +384198,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
383776
384198
|
backgroundTasks.set(taskId, bgTask);
|
|
383777
384199
|
writeTaskTranscriptStart(outputFile, description, subagentType);
|
|
383778
384200
|
const parentAgentIdForSpawn = resolvedParentScope?.agentId;
|
|
383779
|
-
spawnSubagentFn(subagentType, prompt, model, subagentId, abortController.signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentIdForSpawn, transcriptPath, resolvedParentScope?.conversationId, memoryScope).then(async (result) => {
|
|
384201
|
+
spawnSubagentFn(subagentType, prompt, model, subagentId, abortController.signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentIdForSpawn, transcriptPath, resolvedParentScope?.conversationId, memoryScope, systemPromptOverride).then(async (result) => {
|
|
383780
384202
|
bgTask.status = result.success ? "completed" : "failed";
|
|
383781
384203
|
if (result.error) {
|
|
383782
384204
|
bgTask.error = result.error;
|
|
@@ -387667,8 +388089,8 @@ globstar while`, file3, fr, pattern4, pr, swallowee);
|
|
|
387667
388089
|
});
|
|
387668
388090
|
return pp.filter((p) => p !== GLOBSTAR2).join("/");
|
|
387669
388091
|
}).join("|");
|
|
387670
|
-
const [
|
|
387671
|
-
re = "^" +
|
|
388092
|
+
const [open3, close] = set3.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
388093
|
+
re = "^" + open3 + re + close + "$";
|
|
387672
388094
|
if (this.negate)
|
|
387673
388095
|
re = "^(?!" + re + ").+$";
|
|
387674
388096
|
try {
|
|
@@ -393736,16 +394158,16 @@ function toolResultToStoredReturnValue(message) {
|
|
|
393736
394158
|
};
|
|
393737
394159
|
});
|
|
393738
394160
|
}
|
|
393739
|
-
function projectThinkingContent(message,
|
|
393740
|
-
if (
|
|
394161
|
+
function projectThinkingContent(message, reasoning, contentStartIndex, date6, agentId, conversationId) {
|
|
394162
|
+
if (reasoning.length === 0)
|
|
393741
394163
|
return;
|
|
393742
394164
|
return {
|
|
393743
|
-
id: `${message.id}:reasoning:${
|
|
394165
|
+
id: `${message.id}:reasoning:${contentStartIndex}`,
|
|
393744
394166
|
date: date6,
|
|
393745
394167
|
agent_id: agentId,
|
|
393746
394168
|
conversation_id: conversationId,
|
|
393747
394169
|
message_type: "reasoning_message",
|
|
393748
|
-
reasoning
|
|
394170
|
+
reasoning
|
|
393749
394171
|
};
|
|
393750
394172
|
}
|
|
393751
394173
|
function projectToolCallContent(message, content, date6, agentId, conversationId) {
|
|
@@ -393815,6 +394237,8 @@ function projectLocalMessageToStoredMessages(message, fallbackAgentId, fallbackC
|
|
|
393815
394237
|
const messages = [];
|
|
393816
394238
|
let pendingTextContent = [];
|
|
393817
394239
|
let pendingTextStartIndex = -1;
|
|
394240
|
+
let pendingReasoningContent = [];
|
|
394241
|
+
let pendingReasoningStartIndex = -1;
|
|
393818
394242
|
const flushPendingText = () => {
|
|
393819
394243
|
if (pendingTextContent.length === 0)
|
|
393820
394244
|
return;
|
|
@@ -393831,29 +394255,46 @@ function projectLocalMessageToStoredMessages(message, fallbackAgentId, fallbackC
|
|
|
393831
394255
|
pendingTextContent = [];
|
|
393832
394256
|
pendingTextStartIndex = -1;
|
|
393833
394257
|
};
|
|
394258
|
+
const flushPendingReasoning = () => {
|
|
394259
|
+
if (pendingReasoningContent.length > 0) {
|
|
394260
|
+
const reasoningMessage = projectThinkingContent(message, pendingReasoningContent.join(`
|
|
394261
|
+
|
|
394262
|
+
`), pendingReasoningStartIndex, date6, agentId, conversationId);
|
|
394263
|
+
if (reasoningMessage)
|
|
394264
|
+
messages.push(reasoningMessage);
|
|
394265
|
+
}
|
|
394266
|
+
pendingReasoningContent = [];
|
|
394267
|
+
pendingReasoningStartIndex = -1;
|
|
394268
|
+
};
|
|
393834
394269
|
for (let contentIndex = 0;contentIndex < message.content.length; contentIndex++) {
|
|
393835
394270
|
const content = message.content[contentIndex];
|
|
393836
394271
|
if (!content)
|
|
393837
394272
|
continue;
|
|
393838
394273
|
if (isThinkingContent(content)) {
|
|
393839
394274
|
flushPendingText();
|
|
393840
|
-
|
|
393841
|
-
|
|
393842
|
-
|
|
394275
|
+
if (content.thinking.length > 0) {
|
|
394276
|
+
if (pendingReasoningStartIndex === -1) {
|
|
394277
|
+
pendingReasoningStartIndex = contentIndex;
|
|
394278
|
+
}
|
|
394279
|
+
pendingReasoningContent.push(content.thinking);
|
|
394280
|
+
}
|
|
393843
394281
|
continue;
|
|
393844
394282
|
}
|
|
393845
394283
|
if (isLocalToolCallContent(content)) {
|
|
393846
394284
|
flushPendingText();
|
|
394285
|
+
flushPendingReasoning();
|
|
393847
394286
|
messages.push(projectToolCallContent(message, content, date6, agentId, conversationId));
|
|
393848
394287
|
continue;
|
|
393849
394288
|
}
|
|
393850
394289
|
if (isTextContent(content)) {
|
|
394290
|
+
flushPendingReasoning();
|
|
393851
394291
|
if (pendingTextStartIndex === -1)
|
|
393852
394292
|
pendingTextStartIndex = contentIndex;
|
|
393853
394293
|
pendingTextContent.push({ type: "text", text: content.text });
|
|
393854
394294
|
}
|
|
393855
394295
|
}
|
|
393856
394296
|
flushPendingText();
|
|
394297
|
+
flushPendingReasoning();
|
|
393857
394298
|
return messages;
|
|
393858
394299
|
}
|
|
393859
394300
|
function withProjectedMessageDates(messages, _sourceMessageIndex) {
|
|
@@ -394937,7 +395378,7 @@ class LocalStore {
|
|
|
394937
395378
|
}
|
|
394938
395379
|
this.ensureAgent(agentId);
|
|
394939
395380
|
const conversationId = this.nextConversationId();
|
|
394940
|
-
const conversation = createLocalConversationRecord(conversationId, agentId, this.conversationSeq, body);
|
|
395381
|
+
const conversation = this.withConversationModelDefaults(createLocalConversationRecord(conversationId, agentId, this.conversationSeq, body));
|
|
394941
395382
|
const key = this.conversationKey(conversation.id, agentId);
|
|
394942
395383
|
this.conversations.set(key, conversation);
|
|
394943
395384
|
this.localMessagesByConversationKey.set(key, []);
|
|
@@ -394956,32 +395397,31 @@ class LocalStore {
|
|
|
394956
395397
|
}
|
|
394957
395398
|
const created = this.ensureConversation(conversationId);
|
|
394958
395399
|
const updated2 = updateLocalConversationRecord(created, body, currentIsoTimestamp());
|
|
394959
|
-
const projected = this.
|
|
395400
|
+
const projected = this.withConversationModelDefaults(updated2);
|
|
394960
395401
|
this.conversations.set(this.conversationKey(conversationId, created.agent_id), projected);
|
|
394961
395402
|
this.persistConversationState(conversationId, created.agent_id);
|
|
394962
395403
|
return projected;
|
|
394963
395404
|
}
|
|
394964
|
-
const updated = this.
|
|
395405
|
+
const updated = this.withConversationModelDefaults(updateLocalConversationRecord(current, body, currentIsoTimestamp()));
|
|
394965
395406
|
this.conversations.set(this.conversationKey(conversationId, current.agent_id), updated);
|
|
394966
395407
|
this.persistConversationState(conversationId, current.agent_id);
|
|
394967
395408
|
return updated;
|
|
394968
395409
|
}
|
|
394969
|
-
|
|
394970
|
-
const requestedModel =
|
|
395410
|
+
withConversationModelDefaults(conversation) {
|
|
395411
|
+
const requestedModel = conversation.model;
|
|
394971
395412
|
if (typeof requestedModel !== "string")
|
|
394972
395413
|
return conversation;
|
|
394973
395414
|
const normalizedRequestedModel = normalizeLocalModelHandle(requestedModel, isRecord(conversation.model_settings) ? conversation.model_settings : {});
|
|
394974
|
-
if (previousConversation.model === normalizedRequestedModel)
|
|
394975
|
-
return conversation;
|
|
394976
395415
|
const defaults5 = this.modelSettingsDefaultsForModel(normalizedRequestedModel);
|
|
394977
395416
|
if (!defaults5 || Object.keys(defaults5).length === 0)
|
|
394978
395417
|
return conversation;
|
|
394979
395418
|
const existingSettings = isRecord(conversation.model_settings) ? conversation.model_settings : {};
|
|
394980
395419
|
return {
|
|
394981
395420
|
...conversation,
|
|
395421
|
+
model: normalizedRequestedModel,
|
|
394982
395422
|
model_settings: {
|
|
394983
|
-
...
|
|
394984
|
-
...
|
|
395423
|
+
...defaults5,
|
|
395424
|
+
...existingSettings
|
|
394985
395425
|
}
|
|
394986
395426
|
};
|
|
394987
395427
|
}
|
|
@@ -395877,7 +396317,7 @@ class LocalStore {
|
|
|
395877
396317
|
const existing = this.conversations.get(key);
|
|
395878
396318
|
if (existing && options3.forceRefresh !== true)
|
|
395879
396319
|
return existing;
|
|
395880
|
-
const normalizedInput = normalizeStoredLocalModelRecord(input);
|
|
396320
|
+
const normalizedInput = this.withConversationModelDefaults(normalizeStoredLocalModelRecord(input));
|
|
395881
396321
|
const timing = transcriptTimingForConversationDir(conversationDir);
|
|
395882
396322
|
const requiresFullTimestampRepair = isSyntheticLocalTimestamp(normalizedInput.created_at) || isSyntheticLocalTimestamp(normalizedInput.updated_at) || isSyntheticLocalTimestamp(normalizedInput.last_message_at);
|
|
395883
396323
|
const conversation = requiresFullTimestampRepair ? normalizedInput : repairSyntheticConversationTimestamps(normalizedInput, [], timing);
|
|
@@ -397075,8 +397515,8 @@ var init_error_formatter = __esm(() => {
|
|
|
397075
397515
|
init_app_urls();
|
|
397076
397516
|
init_error_context();
|
|
397077
397517
|
init_zai_errors();
|
|
397078
|
-
LETTA_USAGE_URL =
|
|
397079
|
-
LETTA_AGENTS_URL =
|
|
397518
|
+
LETTA_USAGE_URL = buildChatWebUrl("/preferences/usage");
|
|
397519
|
+
LETTA_AGENTS_URL = buildPlatformUrl("/projects/default-project/agents");
|
|
397080
397520
|
CLOUDFLARE_EDGE_5XX_MARKER_PATTERN = /(^|\s)(502|52[0-6])\s*<!doctype html|error code\s*(502|52[0-6])/i;
|
|
397081
397521
|
CLOUDFLARE_EDGE_5XX_TITLE_PATTERN = /\|\s*(502|52[0-6])\s*:/i;
|
|
397082
397522
|
CLOUDFLARE_EDGE_5XX_FORMATTED_PATTERN = /\bCloudflare\s+(502|52[0-6])\b/i;
|
|
@@ -399020,24 +399460,6 @@ var init_local_model_config = __esm(() => {
|
|
|
399020
399460
|
UNSUPPORTED_LOCAL_CHATGPT_OAUTH_MODELS = new Set(["gpt-5.6-luna"]);
|
|
399021
399461
|
});
|
|
399022
399462
|
|
|
399023
|
-
// src/backend/dev/pi-output-budget.ts
|
|
399024
|
-
function assertViablePiOutputBudget(model, context3, requestedMaxTokens) {
|
|
399025
|
-
if (model.provider !== "llama-cpp")
|
|
399026
|
-
return;
|
|
399027
|
-
const requested = requestedMaxTokens ?? model.maxTokens;
|
|
399028
|
-
if (!Number.isFinite(requested) || requested <= 0)
|
|
399029
|
-
return;
|
|
399030
|
-
const clamped = clampMaxTokensToContext(model, context3, requested);
|
|
399031
|
-
const minimum3 = Math.min(requested, MIN_VIABLE_OUTPUT_TOKENS);
|
|
399032
|
-
if (clamped >= minimum3)
|
|
399033
|
-
return;
|
|
399034
|
-
throw new Error(`Context window of ${model.contextWindow} tokens leaves only ${clamped} output token${clamped === 1 ? "" : "s"}; at least ${minimum3} are required. Compact the conversation or increase the context window.`);
|
|
399035
|
-
}
|
|
399036
|
-
var MIN_VIABLE_OUTPUT_TOKENS = 1024;
|
|
399037
|
-
var init_pi_output_budget = __esm(() => {
|
|
399038
|
-
init_simple_options();
|
|
399039
|
-
});
|
|
399040
|
-
|
|
399041
399463
|
// src/backend/local/local-context-estimate.ts
|
|
399042
399464
|
function positiveUsageNumber(value) {
|
|
399043
399465
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
@@ -399301,12 +399723,26 @@ function errorFromAssistantEvent(part) {
|
|
|
399301
399723
|
return new Error("Unknown provider stream error");
|
|
399302
399724
|
return new Error(part.error.errorMessage ?? "Unknown local provider error");
|
|
399303
399725
|
}
|
|
399304
|
-
function
|
|
399305
|
-
|
|
399726
|
+
function contentMatchesMessageType(content, messageType) {
|
|
399727
|
+
if (!content || typeof content !== "object" || !("type" in content)) {
|
|
399728
|
+
return false;
|
|
399729
|
+
}
|
|
399730
|
+
return messageType === "assistant_message" ? content.type === "text" : content.type === "thinking";
|
|
399731
|
+
}
|
|
399732
|
+
function contiguousContentStartIndex(partial4, contentIndex, messageType) {
|
|
399733
|
+
let startIndex = contentIndex;
|
|
399734
|
+
while (startIndex > 0 && contentMatchesMessageType(partial4.content[startIndex - 1], messageType)) {
|
|
399735
|
+
startIndex -= 1;
|
|
399736
|
+
}
|
|
399737
|
+
return startIndex;
|
|
399738
|
+
}
|
|
399739
|
+
function otidForContentSegment(otids, prefix, contentIndex, partial4, messageType) {
|
|
399740
|
+
const segmentStartIndex = contiguousContentStartIndex(partial4, contentIndex, messageType);
|
|
399741
|
+
const existing = otids.get(segmentStartIndex);
|
|
399306
399742
|
if (existing)
|
|
399307
399743
|
return existing;
|
|
399308
|
-
const otid = `${prefix}-${
|
|
399309
|
-
otids.set(
|
|
399744
|
+
const otid = `${prefix}-${segmentStartIndex}-${randomUUID20()}`;
|
|
399745
|
+
otids.set(segmentStartIndex, otid);
|
|
399310
399746
|
return otid;
|
|
399311
399747
|
}
|
|
399312
399748
|
function createProviderLettaStream(events, contextTokensEstimate) {
|
|
@@ -399337,7 +399773,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
|
|
|
399337
399773
|
if (part.type === "text_delta") {
|
|
399338
399774
|
yield {
|
|
399339
399775
|
message_type: "assistant_message",
|
|
399340
|
-
otid:
|
|
399776
|
+
otid: otidForContentSegment(assistantOtids, "provider-assistant", part.contentIndex, part.partial, "assistant_message"),
|
|
399341
399777
|
content: [{ type: "text", text: part.delta }]
|
|
399342
399778
|
};
|
|
399343
399779
|
continue;
|
|
@@ -399345,7 +399781,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
|
|
|
399345
399781
|
if (part.type === "thinking_delta") {
|
|
399346
399782
|
yield {
|
|
399347
399783
|
message_type: "reasoning_message",
|
|
399348
|
-
otid:
|
|
399784
|
+
otid: otidForContentSegment(reasoningOtids, "provider-reasoning", part.contentIndex, part.partial, "reasoning_message"),
|
|
399349
399785
|
reasoning: part.delta
|
|
399350
399786
|
};
|
|
399351
399787
|
continue;
|
|
@@ -399372,7 +399808,7 @@ function createProviderLettaStream(events, contextTokensEstimate) {
|
|
|
399372
399808
|
}
|
|
399373
399809
|
pendingStopReason = {
|
|
399374
399810
|
message_type: "stop_reason",
|
|
399375
|
-
stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : "end_turn"
|
|
399811
|
+
stop_reason: sawToolCall || part.reason === "toolUse" ? "requires_approval" : part.reason === "length" ? "max_tokens_exceeded" : "end_turn"
|
|
399376
399812
|
};
|
|
399377
399813
|
continue;
|
|
399378
399814
|
}
|
|
@@ -399882,7 +400318,6 @@ class PiStreamAdapter {
|
|
|
399882
400318
|
messageCount: context3.messages.length,
|
|
399883
400319
|
contextWindow: resolved.model.contextWindow
|
|
399884
400320
|
});
|
|
399885
|
-
assertViablePiOutputBudget(resolved.model, context3, options3.maxTokens);
|
|
399886
400321
|
const result = this.runStream(resolved.model, context3, options3);
|
|
399887
400322
|
let streamError;
|
|
399888
400323
|
let finalMessage;
|
|
@@ -400023,7 +400458,6 @@ var init_pi_stream_adapter = __esm(() => {
|
|
|
400023
400458
|
init_context_window_overflow();
|
|
400024
400459
|
init_local_provider_errors();
|
|
400025
400460
|
init_pi_model_factory();
|
|
400026
|
-
init_pi_output_budget();
|
|
400027
400461
|
init_provider_turn_executor();
|
|
400028
400462
|
LOCAL_PROVIDER_ADAPTIVE_IMAGE_ELISION_AFTER_RETRIES = LOCAL_PROVIDER_MAX_RETRIES - 1;
|
|
400029
400463
|
PiProviderError = class PiProviderError extends Error {
|
|
@@ -402208,6 +402642,7 @@ __export(exports_oauth2, {
|
|
|
402208
402642
|
requestDeviceCode: () => requestDeviceCode2,
|
|
402209
402643
|
refreshAccessToken: () => refreshAccessToken3,
|
|
402210
402644
|
pollForToken: () => pollForToken2,
|
|
402645
|
+
OAuthRefreshError: () => OAuthRefreshError2,
|
|
402211
402646
|
OAUTH_CONFIG: () => OAUTH_CONFIG2,
|
|
402212
402647
|
LETTA_CLOUD_API_URL: () => LETTA_CLOUD_API_URL2
|
|
402213
402648
|
});
|
|
@@ -402388,11 +402823,22 @@ async function refreshAccessToken3(refreshToken, deviceId, deviceName) {
|
|
|
402388
402823
|
});
|
|
402389
402824
|
if (!response.ok) {
|
|
402390
402825
|
const error54 = await response.json();
|
|
402391
|
-
throw new
|
|
402826
|
+
throw new OAuthRefreshError2(`Failed to refresh access token from ${authHost}: ${error54.error_description || error54.error}`, {
|
|
402827
|
+
retryable: response.status === 408 || response.status === 429 || response.status >= 500,
|
|
402828
|
+
status: response.status,
|
|
402829
|
+
oauthCode: error54.error
|
|
402830
|
+
});
|
|
402392
402831
|
}
|
|
402393
402832
|
return await response.json();
|
|
402394
402833
|
} catch (error54) {
|
|
402395
|
-
|
|
402834
|
+
if (error54 instanceof OAuthRefreshError2) {
|
|
402835
|
+
throw error54;
|
|
402836
|
+
}
|
|
402837
|
+
const actionError = toOAuthActionError2("refresh access token", error54);
|
|
402838
|
+
throw new OAuthRefreshError2(actionError.message, {
|
|
402839
|
+
retryable: true,
|
|
402840
|
+
cause: error54
|
|
402841
|
+
});
|
|
402396
402842
|
}
|
|
402397
402843
|
}
|
|
402398
402844
|
async function revokeToken2(refreshToken) {
|
|
@@ -402478,7 +402924,7 @@ function classifyCredentialValidationError2(error54) {
|
|
|
402478
402924
|
}
|
|
402479
402925
|
return { ok: false, reason: "unknown", message };
|
|
402480
402926
|
}
|
|
402481
|
-
var LETTA_CLOUD_API_URL2 = "https://api.letta.com", OAUTH_CONFIG2;
|
|
402927
|
+
var LETTA_CLOUD_API_URL2 = "https://api.letta.com", OAUTH_CONFIG2, OAuthRefreshError2;
|
|
402482
402928
|
var init_oauth4 = __esm(() => {
|
|
402483
402929
|
init_letta_client();
|
|
402484
402930
|
init_error();
|
|
@@ -402489,6 +402935,18 @@ var init_oauth4 = __esm(() => {
|
|
|
402489
402935
|
authBaseUrl: "https://app.letta.com",
|
|
402490
402936
|
apiBaseUrl: LETTA_CLOUD_API_URL2
|
|
402491
402937
|
};
|
|
402938
|
+
OAuthRefreshError2 = class OAuthRefreshError2 extends Error {
|
|
402939
|
+
retryable;
|
|
402940
|
+
status;
|
|
402941
|
+
oauthCode;
|
|
402942
|
+
constructor(message, options3) {
|
|
402943
|
+
super(message, { cause: options3.cause });
|
|
402944
|
+
this.name = "OAuthRefreshError";
|
|
402945
|
+
this.retryable = options3.retryable;
|
|
402946
|
+
this.status = options3.status;
|
|
402947
|
+
this.oauthCode = options3.oauthCode;
|
|
402948
|
+
}
|
|
402949
|
+
};
|
|
402492
402950
|
});
|
|
402493
402951
|
|
|
402494
402952
|
// node_modules/react/cjs/react.development.js
|
|
@@ -423490,18 +423948,18 @@ var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles4
|
|
|
423490
423948
|
return getModelAnsi("rgb", level, type3, ...ansi_styles_default2.hexToRgb(...arguments_));
|
|
423491
423949
|
}
|
|
423492
423950
|
return ansi_styles_default2[type3][model](...arguments_);
|
|
423493
|
-
}, usedModels, proto, createStyler = (
|
|
423951
|
+
}, usedModels, proto, createStyler = (open3, close, parent) => {
|
|
423494
423952
|
let openAll;
|
|
423495
423953
|
let closeAll;
|
|
423496
423954
|
if (parent === undefined) {
|
|
423497
|
-
openAll =
|
|
423955
|
+
openAll = open3;
|
|
423498
423956
|
closeAll = close;
|
|
423499
423957
|
} else {
|
|
423500
|
-
openAll = parent.openAll +
|
|
423958
|
+
openAll = parent.openAll + open3;
|
|
423501
423959
|
closeAll = close + parent.closeAll;
|
|
423502
423960
|
}
|
|
423503
423961
|
return {
|
|
423504
|
-
open:
|
|
423962
|
+
open: open3,
|
|
423505
423963
|
close,
|
|
423506
423964
|
openAll,
|
|
423507
423965
|
closeAll,
|
|
@@ -441275,7 +441733,7 @@ var init_conversation_search = __esm(() => {
|
|
|
441275
441733
|
});
|
|
441276
441734
|
|
|
441277
441735
|
// src/utils/file-lock.ts
|
|
441278
|
-
import { open as
|
|
441736
|
+
import { open as open3, readFile as readFile13, stat as stat10, unlink as unlink4 } from "node:fs/promises";
|
|
441279
441737
|
async function withFileLock(lockPath, fn, options3) {
|
|
441280
441738
|
const opts = { ...DEFAULT_OPTIONS, ...options3 };
|
|
441281
441739
|
const release = await acquireFileLock(lockPath, opts);
|
|
@@ -441293,7 +441751,7 @@ async function acquireFileLock(lockPath, opts) {
|
|
|
441293
441751
|
});
|
|
441294
441752
|
while (true) {
|
|
441295
441753
|
try {
|
|
441296
|
-
const handle2 = await
|
|
441754
|
+
const handle2 = await open3(lockPath, "wx");
|
|
441297
441755
|
try {
|
|
441298
441756
|
await handle2.writeFile(payload, "utf-8");
|
|
441299
441757
|
await handle2.close();
|
|
@@ -441329,7 +441787,7 @@ async function acquireFileLock(lockPath, opts) {
|
|
|
441329
441787
|
async function tryReapStaleLock(lockPath, staleMs) {
|
|
441330
441788
|
let raw2;
|
|
441331
441789
|
try {
|
|
441332
|
-
raw2 = await
|
|
441790
|
+
raw2 = await readFile13(lockPath, "utf-8");
|
|
441333
441791
|
} catch {
|
|
441334
441792
|
return true;
|
|
441335
441793
|
}
|
|
@@ -441386,9 +441844,9 @@ import {
|
|
|
441386
441844
|
appendFile,
|
|
441387
441845
|
mkdir as mkdir12,
|
|
441388
441846
|
readdir as readdir8,
|
|
441389
|
-
readFile as
|
|
441847
|
+
readFile as readFile14,
|
|
441390
441848
|
stat as stat11,
|
|
441391
|
-
writeFile as
|
|
441849
|
+
writeFile as writeFile12
|
|
441392
441850
|
} from "node:fs/promises";
|
|
441393
441851
|
import { join as join46 } from "node:path";
|
|
441394
441852
|
function buildReflectionSubagentPrompt(input) {
|
|
@@ -441446,7 +441904,7 @@ async function collectParentMemoryFiles(memoryDir) {
|
|
|
441446
441904
|
continue;
|
|
441447
441905
|
}
|
|
441448
441906
|
try {
|
|
441449
|
-
const content = await
|
|
441907
|
+
const content = await readFile14(entryPath, "utf-8");
|
|
441450
441908
|
const { frontmatter } = parseFrontmatter(content);
|
|
441451
441909
|
const description = typeof frontmatter.description === "string" ? frontmatter.description : undefined;
|
|
441452
441910
|
files.push({
|
|
@@ -441775,11 +442233,11 @@ function lineToTranscriptEntry(line, capturedAt) {
|
|
|
441775
442233
|
}
|
|
441776
442234
|
async function ensurePaths(paths) {
|
|
441777
442235
|
await mkdir12(paths.rootDir, { recursive: true });
|
|
441778
|
-
await
|
|
442236
|
+
await writeFile12(paths.transcriptPath, "", { encoding: "utf-8", flag: "a" });
|
|
441779
442237
|
}
|
|
441780
442238
|
async function readTranscriptLines(paths) {
|
|
441781
442239
|
try {
|
|
441782
|
-
const raw2 = await
|
|
442240
|
+
const raw2 = await readFile14(paths.transcriptPath, "utf-8");
|
|
441783
442241
|
return raw2.split(`
|
|
441784
442242
|
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
441785
442243
|
} catch {
|
|
@@ -441852,7 +442310,7 @@ function buildUnreflectedStateFromTranscript(lines) {
|
|
|
441852
442310
|
async function readState(paths) {
|
|
441853
442311
|
let raw2 = null;
|
|
441854
442312
|
try {
|
|
441855
|
-
raw2 = await
|
|
442313
|
+
raw2 = await readFile14(paths.statePath, "utf-8");
|
|
441856
442314
|
} catch {
|
|
441857
442315
|
raw2 = null;
|
|
441858
442316
|
}
|
|
@@ -441877,7 +442335,7 @@ async function readState(paths) {
|
|
|
441877
442335
|
}
|
|
441878
442336
|
async function writeState(paths, state) {
|
|
441879
442337
|
state.steps_since_last_successful_reflection = Math.max(0, state.total_completed_steps - state.reflected_completed_steps);
|
|
441880
|
-
await
|
|
442338
|
+
await writeFile12(paths.statePath, `${JSON.stringify(state, null, 2)}
|
|
441881
442339
|
`, "utf-8");
|
|
441882
442340
|
}
|
|
441883
442341
|
function buildPayloadPath(rootDir, kind) {
|
|
@@ -442255,7 +442713,7 @@ async function buildReflectionAutoPayload(options3) {
|
|
|
442255
442713
|
candidates: sortedCandidates
|
|
442256
442714
|
};
|
|
442257
442715
|
const candidatesPath = buildPayloadPath(payloadRoot, "candidates");
|
|
442258
|
-
await
|
|
442716
|
+
await writeFile12(candidatesPath, `${JSON.stringify(candidateSet, null, 2)}
|
|
442259
442717
|
`, "utf-8");
|
|
442260
442718
|
return { candidatesPath, candidates: candidateSet };
|
|
442261
442719
|
}
|
|
@@ -442263,7 +442721,7 @@ function isReflectionAutoPriority(value) {
|
|
|
442263
442721
|
return value === "high" || value === "medium" || value === "low";
|
|
442264
442722
|
}
|
|
442265
442723
|
async function readReflectionAutoSelection(options3) {
|
|
442266
|
-
const raw2 = options3.selectionReport ?? (options3.selectionOutputPath ? await
|
|
442724
|
+
const raw2 = options3.selectionReport ?? (options3.selectionOutputPath ? await readFile14(options3.selectionOutputPath, "utf-8") : "");
|
|
442267
442725
|
const parsed = parseReflectionAutoSelectionJson(raw2);
|
|
442268
442726
|
if (!parsed || typeof parsed !== "object") {
|
|
442269
442727
|
throw new Error("Reflection selector did not return valid JSON.");
|
|
@@ -442383,7 +442841,7 @@ async function buildAutoReflectionPayload(agentId, conversationId, systemPrompt)
|
|
|
442383
442841
|
return null;
|
|
442384
442842
|
}
|
|
442385
442843
|
const payloadPath = buildPayloadPath(paths.rootDir, "auto");
|
|
442386
|
-
await
|
|
442844
|
+
await writeFile12(payloadPath, transcript, "utf-8");
|
|
442387
442845
|
state.last_reflection_started_at = new Date().toISOString();
|
|
442388
442846
|
await writeState(paths, state);
|
|
442389
442847
|
return {
|
|
@@ -442472,7 +442930,7 @@ async function buildMultiReflectionPayload(options3) {
|
|
|
442472
442930
|
return null;
|
|
442473
442931
|
}
|
|
442474
442932
|
const payloadPath2 = buildPayloadPath(payloadRoot, "slice");
|
|
442475
|
-
await
|
|
442933
|
+
await writeFile12(payloadPath2, transcript, "utf-8");
|
|
442476
442934
|
state.last_reflection_started_at = new Date().toISOString();
|
|
442477
442935
|
await writeState(paths, state);
|
|
442478
442936
|
return {
|
|
@@ -442514,7 +442972,7 @@ async function buildMultiReflectionPayload(options3) {
|
|
|
442514
442972
|
transcripts
|
|
442515
442973
|
};
|
|
442516
442974
|
const payloadPath = buildPayloadPath(payloadRoot, "multi");
|
|
442517
|
-
await
|
|
442975
|
+
await writeFile12(payloadPath, `${JSON.stringify(manifest, null, 2)}
|
|
442518
442976
|
`, "utf-8");
|
|
442519
442977
|
return {
|
|
442520
442978
|
payloadPath,
|
|
@@ -442898,10 +443356,9 @@ async function prepareReflectionMemoryWorktreeLaunch(params) {
|
|
|
442898
443356
|
parentMemoryDir: memoryDir
|
|
442899
443357
|
});
|
|
442900
443358
|
try {
|
|
442901
|
-
const
|
|
442902
|
-
const reflectionPrompt = buildReflectionSubagentPrompt({
|
|
443359
|
+
const reflectionPrompt = params.reflectionPromptOverride ?? buildReflectionSubagentPrompt({
|
|
442903
443360
|
instruction: params.instruction,
|
|
442904
|
-
parentMemory
|
|
443361
|
+
parentMemory: await buildParentMemorySnapshot(worktree.worktreeDir)
|
|
442905
443362
|
});
|
|
442906
443363
|
return { worktree, reflectionPrompt };
|
|
442907
443364
|
} catch (error54) {
|
|
@@ -442982,7 +443439,8 @@ async function launchReflectionSubagent(options3) {
|
|
|
442982
443439
|
}
|
|
442983
443440
|
const { worktree, reflectionPrompt } = await prepareReflectionMemoryWorktreeLaunch({
|
|
442984
443441
|
agentId,
|
|
442985
|
-
instruction: options3.instruction
|
|
443442
|
+
instruction: options3.instruction,
|
|
443443
|
+
reflectionPromptOverride: options3.reflectionPromptOverride
|
|
442986
443444
|
});
|
|
442987
443445
|
preparedWorktree = worktree;
|
|
442988
443446
|
const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
|
|
@@ -443001,6 +443459,7 @@ async function launchReflectionSubagent(options3) {
|
|
|
443001
443459
|
prompt: reflectionPrompt,
|
|
443002
443460
|
description,
|
|
443003
443461
|
model: options3.model,
|
|
443462
|
+
systemPromptOverride: options3.reflectionSystemPromptOverride,
|
|
443004
443463
|
silentCompletion: true,
|
|
443005
443464
|
transcriptPath: autoPayload.payloadPath,
|
|
443006
443465
|
memoryScope: buildReflectionMemoryScope(worktree),
|
|
@@ -443322,19 +443781,18 @@ function getListenerBlockedReason(lifecycle, pendingApprovalsLen) {
|
|
|
443322
443781
|
return null;
|
|
443323
443782
|
}
|
|
443324
443783
|
|
|
443325
|
-
// src/websocket/listener/
|
|
443326
|
-
|
|
443327
|
-
|
|
443328
|
-
|
|
443329
|
-
|
|
443330
|
-
|
|
443331
|
-
|
|
443332
|
-
|
|
443333
|
-
|
|
443334
|
-
getQueueItemsScope: () => getQueueItemsScope,
|
|
443335
|
-
getQueueItemScope: () => getQueueItemScope,
|
|
443336
|
-
consumeQueuedTurn: () => consumeQueuedTurn
|
|
443784
|
+
// src/websocket/listener/image-policy.ts
|
|
443785
|
+
function getInboundImageFailureMode(incoming) {
|
|
443786
|
+
return (incoming?.channelTurnSources?.length ?? 0) > 0 ? "drop" : "strict";
|
|
443787
|
+
}
|
|
443788
|
+
function getInboundImageFailureModes(incoming) {
|
|
443789
|
+
return getInboundImageFailureMode(incoming) === "drop" ? buildImageFailureModesByMessageOtid(incoming.messages, "drop") : undefined;
|
|
443790
|
+
}
|
|
443791
|
+
var init_image_policy = __esm(async () => {
|
|
443792
|
+
await init_message_image_normalization();
|
|
443337
443793
|
});
|
|
443794
|
+
|
|
443795
|
+
// src/websocket/listener/queue.ts
|
|
443338
443796
|
function getQueueItemScope(item) {
|
|
443339
443797
|
if (!item) {
|
|
443340
443798
|
return {};
|
|
@@ -443438,27 +443896,6 @@ async function buildChannelTurnProgressBuilder(agentId) {
|
|
|
443438
443896
|
return createChannelTurnProgressBuilder();
|
|
443439
443897
|
}
|
|
443440
443898
|
}
|
|
443441
|
-
async function normalizeMessageContentImages2(content, resize = resizeImageIfNeeded3, failureMode = "strict") {
|
|
443442
|
-
return await normalizeMessageContentImages(content, resize, failureMode);
|
|
443443
|
-
}
|
|
443444
|
-
async function normalizeInboundMessages(messages, resize = resizeImageIfNeeded3, options3 = {}) {
|
|
443445
|
-
let didChange = false;
|
|
443446
|
-
const normalizedMessages = await Promise.all(messages.map(async (message) => {
|
|
443447
|
-
if (!("content" in message)) {
|
|
443448
|
-
return message;
|
|
443449
|
-
}
|
|
443450
|
-
const normalizedContent = await normalizeMessageContentImages2(message.content, resize, options3.imageFailureMode ?? "strict");
|
|
443451
|
-
if (normalizedContent !== message.content) {
|
|
443452
|
-
didChange = true;
|
|
443453
|
-
return {
|
|
443454
|
-
...message,
|
|
443455
|
-
content: normalizedContent
|
|
443456
|
-
};
|
|
443457
|
-
}
|
|
443458
|
-
return message;
|
|
443459
|
-
}));
|
|
443460
|
-
return didChange ? normalizedMessages : messages;
|
|
443461
|
-
}
|
|
443462
443899
|
function getPrimaryQueueMessageItem(items3) {
|
|
443463
443900
|
for (const item of items3) {
|
|
443464
443901
|
if (item.kind === "message") {
|
|
@@ -443559,10 +443996,18 @@ function consumeQueuedTurn(runtime) {
|
|
|
443559
443996
|
let hasTaskNotification = false;
|
|
443560
443997
|
let hasCronPrompt = false;
|
|
443561
443998
|
let hasModContinue = false;
|
|
443999
|
+
let batchImageFailureMode = null;
|
|
443562
444000
|
for (const item of queuedItems) {
|
|
443563
444001
|
if (!isCoalescable(item.kind) || !hasSameQueueScope(firstQueuedItem, item)) {
|
|
443564
444002
|
break;
|
|
443565
444003
|
}
|
|
444004
|
+
if (item.kind === "message") {
|
|
444005
|
+
const itemImageFailureMode = getInboundImageFailureMode(runtime.queuedMessagesByItemId.get(item.id));
|
|
444006
|
+
if (batchImageFailureMode !== null && itemImageFailureMode !== batchImageFailureMode) {
|
|
444007
|
+
break;
|
|
444008
|
+
}
|
|
444009
|
+
batchImageFailureMode = itemImageFailureMode;
|
|
444010
|
+
}
|
|
443566
444011
|
queueLen += 1;
|
|
443567
444012
|
if (item.kind === "message") {
|
|
443568
444013
|
hasMessage = true;
|
|
@@ -443695,8 +444140,7 @@ var init_queue = __esm(async () => {
|
|
|
443695
444140
|
init_runtime6();
|
|
443696
444141
|
await __promiseAll([
|
|
443697
444142
|
init_progress_builder(),
|
|
443698
|
-
|
|
443699
|
-
init_message_image_normalization(),
|
|
444143
|
+
init_image_policy(),
|
|
443700
444144
|
init_protocol_outbound()
|
|
443701
444145
|
]);
|
|
443702
444146
|
});
|
|
@@ -445421,6 +445865,303 @@ var init_approval = __esm(async () => {
|
|
|
445421
445865
|
]);
|
|
445422
445866
|
});
|
|
445423
445867
|
|
|
445868
|
+
// src/websocket/listen-register.ts
|
|
445869
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
445870
|
+
function deriveListenerInstanceId(surface, connectionName) {
|
|
445871
|
+
const nameHash = createHash6("sha256").update(connectionName).digest("hex").slice(0, 16);
|
|
445872
|
+
return `${surface}-${nameHash}`;
|
|
445873
|
+
}
|
|
445874
|
+
function isTransientRegistrationError(error54) {
|
|
445875
|
+
if (error54 instanceof RegistrationError) {
|
|
445876
|
+
return error54.statusCode === 0 || error54.statusCode === 429 || error54.statusCode >= 500;
|
|
445877
|
+
}
|
|
445878
|
+
return true;
|
|
445879
|
+
}
|
|
445880
|
+
function parseRetryAfterMs(value) {
|
|
445881
|
+
if (!value) {
|
|
445882
|
+
return;
|
|
445883
|
+
}
|
|
445884
|
+
const seconds = Number(value);
|
|
445885
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
445886
|
+
return seconds * 1000;
|
|
445887
|
+
}
|
|
445888
|
+
const dateMs = Date.parse(value);
|
|
445889
|
+
if (Number.isFinite(dateMs)) {
|
|
445890
|
+
return Math.max(0, dateMs - Date.now());
|
|
445891
|
+
}
|
|
445892
|
+
return;
|
|
445893
|
+
}
|
|
445894
|
+
async function registerWithCloud(opts, fetchImpl = fetch) {
|
|
445895
|
+
const registerUrl = `${opts.serverUrl}/v1/environments/register`;
|
|
445896
|
+
const response = await fetchImpl(registerUrl, {
|
|
445897
|
+
method: "POST",
|
|
445898
|
+
headers: {
|
|
445899
|
+
"Content-Type": "application/json",
|
|
445900
|
+
Authorization: `Bearer ${opts.apiKey}`,
|
|
445901
|
+
"X-Letta-Source": "letta-code"
|
|
445902
|
+
},
|
|
445903
|
+
body: JSON.stringify({
|
|
445904
|
+
deviceId: opts.deviceId,
|
|
445905
|
+
...opts.listenerInstanceId ? { listenerInstanceId: opts.listenerInstanceId } : {},
|
|
445906
|
+
connectionName: opts.connectionName,
|
|
445907
|
+
metadata: {
|
|
445908
|
+
lettaCodeVersion: getVersion(),
|
|
445909
|
+
os: process.platform,
|
|
445910
|
+
nodeVersion: process.version,
|
|
445911
|
+
environmentMessageProtocol: "v2-input",
|
|
445912
|
+
supported_commands: SUPPORTED_REMOTE_COMMANDS,
|
|
445913
|
+
self_update: getSelfUpdateStatus()
|
|
445914
|
+
}
|
|
445915
|
+
})
|
|
445916
|
+
}).catch((fetchError) => {
|
|
445917
|
+
const msg = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
445918
|
+
throw new RegistrationError(`Network error: ${msg}`, 0);
|
|
445919
|
+
});
|
|
445920
|
+
if (!response.ok) {
|
|
445921
|
+
let detail = `HTTP ${response.status}`;
|
|
445922
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
445923
|
+
const text2 = await response.text().catch(() => "");
|
|
445924
|
+
if (text2) {
|
|
445925
|
+
try {
|
|
445926
|
+
const parsed = JSON.parse(text2);
|
|
445927
|
+
if (parsed.message) {
|
|
445928
|
+
detail = parsed.message;
|
|
445929
|
+
} else if (parsed.error) {
|
|
445930
|
+
detail = `HTTP ${response.status}: ${parsed.error}`;
|
|
445931
|
+
if (parsed.errorCode) {
|
|
445932
|
+
detail += ` (${parsed.errorCode})`;
|
|
445933
|
+
}
|
|
445934
|
+
} else {
|
|
445935
|
+
detail += `: ${text2.slice(0, 200)}`;
|
|
445936
|
+
}
|
|
445937
|
+
} catch {
|
|
445938
|
+
detail += `: ${text2.slice(0, 200)}`;
|
|
445939
|
+
}
|
|
445940
|
+
}
|
|
445941
|
+
throw new RegistrationError(detail, response.status, retryAfterMs);
|
|
445942
|
+
}
|
|
445943
|
+
let body3;
|
|
445944
|
+
try {
|
|
445945
|
+
body3 = await response.json();
|
|
445946
|
+
} catch {
|
|
445947
|
+
throw new RegistrationError("Server returned non-JSON response — is the server running?", response.status);
|
|
445948
|
+
}
|
|
445949
|
+
const result = body3;
|
|
445950
|
+
if (typeof result.connectionId !== "string" || typeof result.wsUrl !== "string") {
|
|
445951
|
+
throw new RegistrationError("Server returned unexpected response shape (missing connectionId or wsUrl)", response.status);
|
|
445952
|
+
}
|
|
445953
|
+
return {
|
|
445954
|
+
connectionId: result.connectionId,
|
|
445955
|
+
wsUrl: result.wsUrl,
|
|
445956
|
+
supportsSplitStatusChannels: result.supportsSplitStatusChannels === true
|
|
445957
|
+
};
|
|
445958
|
+
}
|
|
445959
|
+
async function registerWithCloudRetry(opts, callbacks) {
|
|
445960
|
+
const startTime = Date.now();
|
|
445961
|
+
const maxDurationMs = callbacks?.maxDurationMs ?? REGISTER_MAX_DURATION_MS;
|
|
445962
|
+
const sleep9 = callbacks?.sleep ?? ((delayMs) => new Promise((resolve31) => setTimeout(resolve31, delayMs)));
|
|
445963
|
+
let attempt = 0;
|
|
445964
|
+
for (;; ) {
|
|
445965
|
+
try {
|
|
445966
|
+
return await registerWithCloud(opts, callbacks?.fetchImpl);
|
|
445967
|
+
} catch (error54) {
|
|
445968
|
+
const elapsed = Date.now() - startTime;
|
|
445969
|
+
if (!isTransientRegistrationError(error54) || elapsed >= maxDurationMs) {
|
|
445970
|
+
throw error54;
|
|
445971
|
+
}
|
|
445972
|
+
attempt++;
|
|
445973
|
+
const backoffDelay = Math.min(REGISTER_INITIAL_DELAY_MS * 2 ** (attempt - 1), REGISTER_MAX_DELAY_MS);
|
|
445974
|
+
const delay2 = error54 instanceof RegistrationError && error54.retryAfterMs !== undefined ? Math.max(error54.retryAfterMs, backoffDelay) : backoffDelay;
|
|
445975
|
+
const jitterWindow = Math.min(REGISTER_MAX_JITTER_MS, Math.floor(delay2 * REGISTER_JITTER_RATIO));
|
|
445976
|
+
const jitter = jitterWindow > 0 ? Math.floor((callbacks?.random ?? Math.random)() * jitterWindow) : 0;
|
|
445977
|
+
const retryDelay = delay2 + jitter;
|
|
445978
|
+
if (error54 instanceof Error) {
|
|
445979
|
+
callbacks?.onRetry?.(attempt, retryDelay, error54);
|
|
445980
|
+
}
|
|
445981
|
+
await sleep9(retryDelay);
|
|
445982
|
+
}
|
|
445983
|
+
}
|
|
445984
|
+
}
|
|
445985
|
+
var RegistrationError, REGISTER_INITIAL_DELAY_MS = 1000, REGISTER_MAX_DELAY_MS = 30000, REGISTER_MAX_DURATION_MS, REGISTER_MAX_JITTER_MS = 1000, REGISTER_JITTER_RATIO = 0.25;
|
|
445986
|
+
var init_listen_register = __esm(() => {
|
|
445987
|
+
init_auto_update();
|
|
445988
|
+
init_version();
|
|
445989
|
+
init_listener_constants();
|
|
445990
|
+
RegistrationError = class RegistrationError extends Error {
|
|
445991
|
+
statusCode;
|
|
445992
|
+
retryAfterMs;
|
|
445993
|
+
constructor(message, statusCode2, retryAfterMs) {
|
|
445994
|
+
super(message);
|
|
445995
|
+
this.name = "RegistrationError";
|
|
445996
|
+
this.statusCode = statusCode2;
|
|
445997
|
+
this.retryAfterMs = retryAfterMs;
|
|
445998
|
+
}
|
|
445999
|
+
};
|
|
446000
|
+
REGISTER_MAX_DURATION_MS = 2 * 60 * 1000;
|
|
446001
|
+
});
|
|
446002
|
+
|
|
446003
|
+
// src/websocket/listener/auth.ts
|
|
446004
|
+
function getListenerOAuthDeps() {
|
|
446005
|
+
return listenerOAuthDepsOverride ?? defaultListenerOAuthDeps;
|
|
446006
|
+
}
|
|
446007
|
+
function errorMessage(error54) {
|
|
446008
|
+
return error54 instanceof Error ? error54.message : String(error54);
|
|
446009
|
+
}
|
|
446010
|
+
function getListenerServerUrl(settings3) {
|
|
446011
|
+
return process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || getListenerOAuthDeps().LETTA_CLOUD_API_URL;
|
|
446012
|
+
}
|
|
446013
|
+
function normalizeListenerBaseUrl(url2) {
|
|
446014
|
+
return url2.trim().replace(/\/+$/, "");
|
|
446015
|
+
}
|
|
446016
|
+
function isCloudListenerServerUrl(serverUrl) {
|
|
446017
|
+
return normalizeListenerBaseUrl(serverUrl) === normalizeListenerBaseUrl(getListenerOAuthDeps().LETTA_CLOUD_API_URL);
|
|
446018
|
+
}
|
|
446019
|
+
function shouldRefreshListenerAccessToken(settings3, apiKey) {
|
|
446020
|
+
if (!settings3.refreshToken) {
|
|
446021
|
+
return false;
|
|
446022
|
+
}
|
|
446023
|
+
if (!apiKey) {
|
|
446024
|
+
return true;
|
|
446025
|
+
}
|
|
446026
|
+
return settings3.tokenExpiresAt !== undefined && Date.now() >= settings3.tokenExpiresAt - LISTENER_TOKEN_REFRESH_WINDOW_MS;
|
|
446027
|
+
}
|
|
446028
|
+
function isAccessTokenStillValid(settings3, apiKey) {
|
|
446029
|
+
return Boolean(apiKey && (settings3.tokenExpiresAt === undefined || Date.now() < settings3.tokenExpiresAt));
|
|
446030
|
+
}
|
|
446031
|
+
async function refreshListenerAccessToken(settings3, deviceId, connectionName) {
|
|
446032
|
+
if (!settings3.refreshToken) {
|
|
446033
|
+
throw new MissingListenerApiKeyError;
|
|
446034
|
+
}
|
|
446035
|
+
const now = Date.now();
|
|
446036
|
+
console.log("Access token expired, refreshing...");
|
|
446037
|
+
const tokens = await refreshAccessTokenSingleFlight(settings3.refreshToken, deviceId, connectionName, getListenerOAuthDeps().refreshAccessToken);
|
|
446038
|
+
settingsManager.updateSettings({
|
|
446039
|
+
env: { LETTA_API_KEY: tokens.access_token },
|
|
446040
|
+
refreshToken: tokens.refresh_token ?? settings3.refreshToken,
|
|
446041
|
+
tokenExpiresAt: now + tokens.expires_in * 1000
|
|
446042
|
+
});
|
|
446043
|
+
await settingsManager.flush();
|
|
446044
|
+
console.log("Token refreshed successfully.");
|
|
446045
|
+
return tokens.access_token;
|
|
446046
|
+
}
|
|
446047
|
+
async function runListenerOAuthLogin(deviceId, connectionName) {
|
|
446048
|
+
const oauthDeps = getListenerOAuthDeps();
|
|
446049
|
+
console.log(`No API key found. Starting OAuth login...
|
|
446050
|
+
`);
|
|
446051
|
+
const deviceData = await oauthDeps.requestDeviceCode();
|
|
446052
|
+
console.log(`To authenticate, visit: ${deviceData.verification_uri_complete}`);
|
|
446053
|
+
console.log(`Your code: ${deviceData.user_code}
|
|
446054
|
+
`);
|
|
446055
|
+
console.log(`Waiting for authorization...
|
|
446056
|
+
`);
|
|
446057
|
+
const tokens = await oauthDeps.pollForToken(deviceData.device_code, deviceData.interval, deviceData.expires_in, deviceId, connectionName);
|
|
446058
|
+
const now = Date.now();
|
|
446059
|
+
settingsManager.updateSettings({
|
|
446060
|
+
env: { LETTA_API_KEY: tokens.access_token },
|
|
446061
|
+
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {},
|
|
446062
|
+
tokenExpiresAt: now + tokens.expires_in * 1000
|
|
446063
|
+
});
|
|
446064
|
+
await settingsManager.flush();
|
|
446065
|
+
console.log(`Authenticated successfully.
|
|
446066
|
+
`);
|
|
446067
|
+
return tokens.access_token;
|
|
446068
|
+
}
|
|
446069
|
+
async function resolveListenerAuth(deviceId, connectionName, options3) {
|
|
446070
|
+
const allowInteractiveOAuth = options3.allowInteractiveOAuth ?? true;
|
|
446071
|
+
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
446072
|
+
const serverUrl = getListenerServerUrl(settings3);
|
|
446073
|
+
const envApiKey = process.env.LETTA_API_KEY;
|
|
446074
|
+
if (envApiKey) {
|
|
446075
|
+
return { serverUrl, apiKey: envApiKey };
|
|
446076
|
+
}
|
|
446077
|
+
let apiKey = settings3.env?.LETTA_API_KEY;
|
|
446078
|
+
if (!isCloudListenerServerUrl(serverUrl)) {
|
|
446079
|
+
if (!apiKey) {
|
|
446080
|
+
throw new MissingListenerApiKeyError;
|
|
446081
|
+
}
|
|
446082
|
+
return { serverUrl, apiKey };
|
|
446083
|
+
}
|
|
446084
|
+
if (shouldRefreshListenerAccessToken(settings3, apiKey)) {
|
|
446085
|
+
try {
|
|
446086
|
+
apiKey = await refreshListenerAccessToken(settings3, deviceId, connectionName);
|
|
446087
|
+
} catch (refreshError) {
|
|
446088
|
+
const retryable = !(refreshError instanceof OAuthRefreshError) || refreshError.retryable;
|
|
446089
|
+
if (retryable && isAccessTokenStillValid(settings3, apiKey)) {
|
|
446090
|
+
console.warn(`Token refresh failed; using the current access token: ${errorMessage(refreshError)}`);
|
|
446091
|
+
return { serverUrl, apiKey };
|
|
446092
|
+
}
|
|
446093
|
+
if (retryable) {
|
|
446094
|
+
throw new ListenerAuthRetryableError(refreshError);
|
|
446095
|
+
}
|
|
446096
|
+
if (!allowInteractiveOAuth) {
|
|
446097
|
+
throw new ListenerReauthenticationRequiredError(refreshError);
|
|
446098
|
+
}
|
|
446099
|
+
console.warn(`Token refresh failed: ${errorMessage(refreshError)}`);
|
|
446100
|
+
apiKey = undefined;
|
|
446101
|
+
}
|
|
446102
|
+
}
|
|
446103
|
+
if (!apiKey) {
|
|
446104
|
+
if (!allowInteractiveOAuth) {
|
|
446105
|
+
throw new ListenerReauthenticationRequiredError;
|
|
446106
|
+
}
|
|
446107
|
+
apiKey = await runListenerOAuthLogin(deviceId, connectionName);
|
|
446108
|
+
}
|
|
446109
|
+
return { serverUrl, apiKey };
|
|
446110
|
+
}
|
|
446111
|
+
async function resolveListenerRegistrationOptions(deviceId, connectionName, options3 = {}) {
|
|
446112
|
+
const auth = await resolveListenerAuth(deviceId, connectionName, options3);
|
|
446113
|
+
return {
|
|
446114
|
+
...auth,
|
|
446115
|
+
deviceId,
|
|
446116
|
+
connectionName,
|
|
446117
|
+
listenerInstanceId: deriveListenerInstanceId(options3.surface ?? "server", connectionName)
|
|
446118
|
+
};
|
|
446119
|
+
}
|
|
446120
|
+
async function resolveListenerReconnectAuth(options3) {
|
|
446121
|
+
try {
|
|
446122
|
+
const auth = await resolveListenerAuth(options3.deviceId, options3.connectionName, { allowInteractiveOAuth: false });
|
|
446123
|
+
return { kind: "ready", apiKey: auth.apiKey };
|
|
446124
|
+
} catch (error54) {
|
|
446125
|
+
if (error54 instanceof ListenerAuthRetryableError) {
|
|
446126
|
+
return { kind: "retry" };
|
|
446127
|
+
}
|
|
446128
|
+
throw error54;
|
|
446129
|
+
}
|
|
446130
|
+
}
|
|
446131
|
+
var LISTENER_TOKEN_REFRESH_WINDOW_MS, defaultListenerOAuthDeps, listenerOAuthDepsOverride = null, MissingListenerApiKeyError, ListenerAuthRetryableError, ListenerReauthenticationRequiredError;
|
|
446132
|
+
var init_auth = __esm(() => {
|
|
446133
|
+
init_oauth();
|
|
446134
|
+
init_oauth_refresh();
|
|
446135
|
+
init_settings_manager();
|
|
446136
|
+
init_listen_register();
|
|
446137
|
+
LISTENER_TOKEN_REFRESH_WINDOW_MS = 5 * 60 * 1000;
|
|
446138
|
+
defaultListenerOAuthDeps = {
|
|
446139
|
+
LETTA_CLOUD_API_URL,
|
|
446140
|
+
pollForToken,
|
|
446141
|
+
refreshAccessToken,
|
|
446142
|
+
requestDeviceCode
|
|
446143
|
+
};
|
|
446144
|
+
MissingListenerApiKeyError = class MissingListenerApiKeyError extends Error {
|
|
446145
|
+
constructor() {
|
|
446146
|
+
super("LETTA_API_KEY not found");
|
|
446147
|
+
this.name = "MissingListenerApiKeyError";
|
|
446148
|
+
}
|
|
446149
|
+
};
|
|
446150
|
+
ListenerAuthRetryableError = class ListenerAuthRetryableError extends Error {
|
|
446151
|
+
constructor(refreshError) {
|
|
446152
|
+
super(`Could not refresh listener credentials: ${errorMessage(refreshError)}`);
|
|
446153
|
+
this.name = "ListenerAuthRetryableError";
|
|
446154
|
+
}
|
|
446155
|
+
};
|
|
446156
|
+
ListenerReauthenticationRequiredError = class ListenerReauthenticationRequiredError extends Error {
|
|
446157
|
+
constructor(refreshError) {
|
|
446158
|
+
const detail = refreshError ? `: ${errorMessage(refreshError)}` : "";
|
|
446159
|
+
super(`Saved Letta API credentials require reauthentication${detail}. Run letta to sign in again, or set LETTA_API_KEY.`);
|
|
446160
|
+
this.name = "ListenerReauthenticationRequiredError";
|
|
446161
|
+
}
|
|
446162
|
+
};
|
|
446163
|
+
});
|
|
446164
|
+
|
|
445424
446165
|
// src/agent/acting-user.ts
|
|
445425
446166
|
function actingUserRequestOptions(actingUserId) {
|
|
445426
446167
|
if (!actingUserId) {
|
|
@@ -445792,7 +446533,7 @@ __export(exports_custom, {
|
|
|
445792
446533
|
COMMANDS_DIR: () => COMMANDS_DIR
|
|
445793
446534
|
});
|
|
445794
446535
|
import { existsSync as existsSync43 } from "node:fs";
|
|
445795
|
-
import { readdir as readdir9, readFile as
|
|
446536
|
+
import { readdir as readdir9, readFile as readFile15 } from "node:fs/promises";
|
|
445796
446537
|
import { basename as basename20, dirname as dirname24, join as join48 } from "node:path";
|
|
445797
446538
|
async function getCustomCommands() {
|
|
445798
446539
|
if (cachedCommands !== null) {
|
|
@@ -445851,7 +446592,7 @@ async function findCommandFiles(currentPath, rootPath, commands, source2) {
|
|
|
445851
446592
|
} catch (_error) {}
|
|
445852
446593
|
}
|
|
445853
446594
|
async function parseCommandFile(filePath, rootPath, source2) {
|
|
445854
|
-
const content = await
|
|
446595
|
+
const content = await readFile15(filePath, "utf-8");
|
|
445855
446596
|
const { frontmatter, body: body3 } = parseFrontmatter(content);
|
|
445856
446597
|
const id2 = basename20(filePath, ".md");
|
|
445857
446598
|
const relativePath = dirname24(filePath).slice(rootPath.length);
|
|
@@ -446010,7 +446751,7 @@ var init_init_command = __esm(() => {
|
|
|
446010
446751
|
});
|
|
446011
446752
|
|
|
446012
446753
|
// src/cli/helpers/skill-name-frontmatter-repair.ts
|
|
446013
|
-
import { readdir as readdir10, readFile as
|
|
446754
|
+
import { readdir as readdir10, readFile as readFile16, stat as stat12, writeFile as writeFile13 } from "node:fs/promises";
|
|
446014
446755
|
import { basename as basename21, dirname as dirname25, join as join49, relative as relative8 } from "node:path";
|
|
446015
446756
|
async function pathExists(path32) {
|
|
446016
446757
|
try {
|
|
@@ -446117,7 +446858,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
|
|
|
446117
446858
|
const displayPath = relative8(memoryDir, skillFile).replace(/\\/g, "/");
|
|
446118
446859
|
result.scanned++;
|
|
446119
446860
|
try {
|
|
446120
|
-
const content = await
|
|
446861
|
+
const content = await readFile16(skillFile, "utf8");
|
|
446121
446862
|
const repair3 = repairSkillNameFrontmatterContent(content, basename21(dirname25(skillFile)));
|
|
446122
446863
|
if (repair3.reason) {
|
|
446123
446864
|
result.skipped.push({ path: displayPath, reason: repair3.reason });
|
|
@@ -446126,7 +446867,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
|
|
|
446126
446867
|
if (!repair3.changed) {
|
|
446127
446868
|
continue;
|
|
446128
446869
|
}
|
|
446129
|
-
await
|
|
446870
|
+
await writeFile13(skillFile, repair3.content, "utf8");
|
|
446130
446871
|
result.repaired.push(displayPath);
|
|
446131
446872
|
} catch (error54) {
|
|
446132
446873
|
result.skipped.push({
|
|
@@ -447215,7 +447956,7 @@ function isCreateAgentCommand(value) {
|
|
|
447215
447956
|
if (!value || typeof value !== "object")
|
|
447216
447957
|
return false;
|
|
447217
447958
|
const c = value;
|
|
447218
|
-
return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.pin_global === undefined || typeof c.pin_global === "boolean");
|
|
447959
|
+
return c.type === "create_agent" && typeof c.request_id === "string" && (c.personality === "memo" || c.personality === "blank" || c.personality === "tutorial" || c.personality === "linus" || c.personality === "kawaii") && (c.model === undefined || typeof c.model === "string") && (c.tags === undefined || isStringArray6(c.tags)) && (c.pin_global === undefined || typeof c.pin_global === "boolean");
|
|
447219
447960
|
}
|
|
447220
447961
|
function isAgentListCommand(value) {
|
|
447221
447962
|
if (!value || typeof value !== "object")
|
|
@@ -449685,9 +450426,9 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
449685
450426
|
}
|
|
449686
450427
|
}
|
|
449687
450428
|
} catch (e2) {
|
|
449688
|
-
const
|
|
450429
|
+
const errorMessage2 = e2 instanceof Error ? e2.message : String(e2);
|
|
449689
450430
|
const sdkDiagnostic = consumeLastSDKDiagnostic();
|
|
449690
|
-
const errorMessageWithDiagnostic = sdkDiagnostic ? `${
|
|
450431
|
+
const errorMessageWithDiagnostic = sdkDiagnostic ? `${errorMessage2} [${sdkDiagnostic}]` : errorMessage2;
|
|
449691
450432
|
debugWarn("drainStream", "Stream error caught: %s last_chunk=%s stream=%s", errorMessageWithDiagnostic, lastChunkDebugSummary, summarizeStreamForDebug(stream12));
|
|
449692
450433
|
if (e2 instanceof Error && e2.stack) {
|
|
449693
450434
|
debugWarn("drainStream", "Stream error stack: %s", e2.stack);
|
|
@@ -450697,6 +451438,19 @@ function emitToolExecutionFinishedEvents(socket, runtime, params) {
|
|
|
450697
451438
|
});
|
|
450698
451439
|
}
|
|
450699
451440
|
}
|
|
451441
|
+
function emitToolExecutionAbortedEvents(socket, runtime, params) {
|
|
451442
|
+
for (const toolCallId of params.toolCallIds) {
|
|
451443
|
+
const delta2 = {
|
|
451444
|
+
...createLifecycleMessageBase("client_tool_end", params.runId),
|
|
451445
|
+
tool_call_id: toolCallId,
|
|
451446
|
+
status: "error"
|
|
451447
|
+
};
|
|
451448
|
+
emitCanonicalMessageDelta(socket, runtime, delta2, {
|
|
451449
|
+
agent_id: params.agentId,
|
|
451450
|
+
conversation_id: params.conversationId
|
|
451451
|
+
});
|
|
451452
|
+
}
|
|
451453
|
+
}
|
|
450700
451454
|
function createToolExecutionOutputEmitter(socket, runtime, params) {
|
|
450701
451455
|
const outputByToolCallId = new Map;
|
|
450702
451456
|
const emitToolOutput = (toolCallId, outputState) => {
|
|
@@ -451287,6 +452041,17 @@ var init_approval_suggestions = __esm(async () => {
|
|
|
451287
452041
|
]);
|
|
451288
452042
|
});
|
|
451289
452043
|
|
|
452044
|
+
// src/websocket/listener/continuation-input.ts
|
|
452045
|
+
function appendQueuedTurnToInput(input, queuedTurn) {
|
|
452046
|
+
return {
|
|
452047
|
+
input: [...input, ...queuedTurn.messages],
|
|
452048
|
+
imageFailureModesByMessageOtid: getInboundImageFailureModes(queuedTurn)
|
|
452049
|
+
};
|
|
452050
|
+
}
|
|
452051
|
+
var init_continuation_input = __esm(async () => {
|
|
452052
|
+
await init_image_policy();
|
|
452053
|
+
});
|
|
452054
|
+
|
|
451290
452055
|
// src/websocket/listener/turn-terminal.ts
|
|
451291
452056
|
function finishListenerTurn(runtime, lease, options3) {
|
|
451292
452057
|
const transition = runtime.turnLifecycle.finish(lease, options3.stopReason);
|
|
@@ -451711,25 +452476,25 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
451711
452476
|
conversationId: recovered.conversationId,
|
|
451712
452477
|
shouldEmit: () => runtime.turnLifecycle.isCurrent(recoveryLease)
|
|
451713
452478
|
});
|
|
451714
|
-
await ensureSecretsHydrated(runtime.listener, recovered.agentId);
|
|
451715
|
-
if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
451716
|
-
return true;
|
|
451717
|
-
}
|
|
451718
|
-
const preparedToolContext = await prepareToolExecutionContext({
|
|
451719
|
-
agentId: recovered.agentId,
|
|
451720
|
-
conversationId: recovered.conversationId,
|
|
451721
|
-
workingDirectory,
|
|
451722
|
-
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId),
|
|
451723
|
-
modEvents: ensureListenerModAdapter(runtime.listener).events
|
|
451724
|
-
});
|
|
451725
|
-
if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
451726
|
-
return true;
|
|
451727
|
-
}
|
|
451728
|
-
runtime.currentToolset = preparedToolContext.toolset;
|
|
451729
|
-
runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
|
|
451730
|
-
runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
|
|
451731
452479
|
let approvalResults;
|
|
451732
452480
|
try {
|
|
452481
|
+
await ensureSecretsHydrated(runtime.listener, recovered.agentId);
|
|
452482
|
+
if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
452483
|
+
return true;
|
|
452484
|
+
}
|
|
452485
|
+
const preparedToolContext = await prepareToolExecutionContext({
|
|
452486
|
+
agentId: recovered.agentId,
|
|
452487
|
+
conversationId: recovered.conversationId,
|
|
452488
|
+
workingDirectory,
|
|
452489
|
+
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId),
|
|
452490
|
+
modEvents: ensureListenerModAdapter(runtime.listener).events
|
|
452491
|
+
});
|
|
452492
|
+
if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
452493
|
+
return true;
|
|
452494
|
+
}
|
|
452495
|
+
runtime.currentToolset = preparedToolContext.toolset;
|
|
452496
|
+
runtime.currentToolsetPreference = preparedToolContext.toolsetPreference;
|
|
452497
|
+
runtime.currentLoadedTools = preparedToolContext.preparedToolContext.loadedToolNames;
|
|
451733
452498
|
approvalResults = await executeApprovals(decisions, undefined, {
|
|
451734
452499
|
abortSignal: recoveryLease.signal,
|
|
451735
452500
|
onStreamingOutput: emitToolExecutionOutput,
|
|
@@ -451741,6 +452506,17 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
451741
452506
|
} : undefined,
|
|
451742
452507
|
channelTurnSources: executionChannelTurnSources
|
|
451743
452508
|
});
|
|
452509
|
+
} catch (error54) {
|
|
452510
|
+
emitToolExecutionOutput.flush();
|
|
452511
|
+
if (runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
452512
|
+
emitToolExecutionAbortedEvents(socket, runtime, {
|
|
452513
|
+
toolCallIds: approvedToolCallIds,
|
|
452514
|
+
runId: executionRunId,
|
|
452515
|
+
agentId: recovered.agentId,
|
|
452516
|
+
conversationId: recovered.conversationId
|
|
452517
|
+
});
|
|
452518
|
+
}
|
|
452519
|
+
throw error54;
|
|
451744
452520
|
} finally {
|
|
451745
452521
|
emitToolExecutionOutput.flush();
|
|
451746
452522
|
}
|
|
@@ -451760,7 +452536,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
451760
452536
|
return true;
|
|
451761
452537
|
}
|
|
451762
452538
|
emitRuntimeStateUpdates(runtime, scope);
|
|
451763
|
-
|
|
452539
|
+
let continuationMessages = [
|
|
451764
452540
|
{
|
|
451765
452541
|
type: "approval",
|
|
451766
452542
|
approvals: approvalResults,
|
|
@@ -451768,11 +452544,13 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
451768
452544
|
}
|
|
451769
452545
|
];
|
|
451770
452546
|
let continuationBatchId = `batch-recovered-${crypto.randomUUID()}`;
|
|
452547
|
+
let queuedChannelTurnSources;
|
|
451771
452548
|
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
451772
452549
|
if (consumedQueuedTurn) {
|
|
451773
452550
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
451774
452551
|
continuationBatchId = dequeuedBatch.batchId;
|
|
451775
|
-
continuationMessages
|
|
452552
|
+
continuationMessages = appendQueuedTurnToInput(continuationMessages, queuedTurn).input;
|
|
452553
|
+
queuedChannelTurnSources = queuedTurn.channelTurnSources;
|
|
451776
452554
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
451777
452555
|
}
|
|
451778
452556
|
if (!runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
@@ -451782,7 +452560,8 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
451782
452560
|
type: "message",
|
|
451783
452561
|
agentId: recovered.agentId,
|
|
451784
452562
|
conversationId: recovered.conversationId,
|
|
451785
|
-
messages: continuationMessages
|
|
452563
|
+
messages: continuationMessages,
|
|
452564
|
+
...queuedChannelTurnSources?.length ? { channelTurnSources: queuedChannelTurnSources } : {}
|
|
451786
452565
|
}, socket, runtime, opts?.onStatusChange, opts?.connectionId, continuationBatchId, recoveryLease);
|
|
451787
452566
|
if (runtime.turnLifecycle.isCurrent(recoveryLease)) {
|
|
451788
452567
|
throw new Error("Recovered continuation returned without finalizing");
|
|
@@ -451853,6 +452632,7 @@ var init_recovery = __esm(async () => {
|
|
|
451853
452632
|
init_stream(),
|
|
451854
452633
|
init_toolset(),
|
|
451855
452634
|
init_approval_suggestions(),
|
|
452635
|
+
init_continuation_input(),
|
|
451856
452636
|
init_interrupts(),
|
|
451857
452637
|
init_mod_adapter2(),
|
|
451858
452638
|
init_protocol_outbound(),
|
|
@@ -452082,17 +452862,20 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
452082
452862
|
return null;
|
|
452083
452863
|
}
|
|
452084
452864
|
try {
|
|
452085
|
-
|
|
452865
|
+
let continuationMessages = [
|
|
452086
452866
|
{
|
|
452087
452867
|
type: "approval",
|
|
452088
452868
|
approvals: approvalResults,
|
|
452089
452869
|
otid: crypto.randomUUID()
|
|
452090
452870
|
}
|
|
452091
452871
|
];
|
|
452872
|
+
let queuedImageFailureModes;
|
|
452092
452873
|
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
452093
452874
|
if (consumedQueuedTurn) {
|
|
452094
452875
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
452095
|
-
continuationMessages
|
|
452876
|
+
const appended = appendQueuedTurnToInput(continuationMessages, queuedTurn);
|
|
452877
|
+
continuationMessages = appended.input;
|
|
452878
|
+
queuedImageFailureModes = appended.imageFailureModesByMessageOtid;
|
|
452096
452879
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
452097
452880
|
}
|
|
452098
452881
|
const continuationMessagesWithSkillContent = injectQueuedSkillContent(continuationMessages);
|
|
@@ -452101,7 +452884,8 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
452101
452884
|
streamTokens: true,
|
|
452102
452885
|
background: true,
|
|
452103
452886
|
workingDirectory: recoveryWorkingDirectory,
|
|
452104
|
-
preparedToolContext: preparedToolContext.preparedToolContext
|
|
452887
|
+
preparedToolContext: preparedToolContext.preparedToolContext,
|
|
452888
|
+
...queuedImageFailureModes ? { imageFailureModesByMessageOtid: queuedImageFailureModes } : {}
|
|
452105
452889
|
}, socket, runtime, turnLease, { allowApprovalRecovery: false });
|
|
452106
452890
|
assertCurrentTurnLease();
|
|
452107
452891
|
if (recoverySendResult.kind !== "stream") {
|
|
@@ -452442,6 +453226,7 @@ var init_send = __esm(async () => {
|
|
|
452442
453226
|
init_message(),
|
|
452443
453227
|
init_toolset(),
|
|
452444
453228
|
init_approval(),
|
|
453229
|
+
init_continuation_input(),
|
|
452445
453230
|
init_mod_adapter2(),
|
|
452446
453231
|
init_protocol_outbound(),
|
|
452447
453232
|
init_queue(),
|
|
@@ -454823,6 +455608,17 @@ async function handleApprovalStop(params) {
|
|
|
454823
455608
|
channelTurnSources: runtime.activeChannelTurn?.sources,
|
|
454824
455609
|
onFileWrite
|
|
454825
455610
|
});
|
|
455611
|
+
} catch (error54) {
|
|
455612
|
+
emitToolExecutionOutput.flush();
|
|
455613
|
+
if (!shouldInterrupt()) {
|
|
455614
|
+
emitToolExecutionAbortedEvents(socket, runtime, {
|
|
455615
|
+
toolCallIds: lastExecutingToolCallIds,
|
|
455616
|
+
runId: executionRunId,
|
|
455617
|
+
agentId,
|
|
455618
|
+
conversationId
|
|
455619
|
+
});
|
|
455620
|
+
}
|
|
455621
|
+
throw error54;
|
|
454826
455622
|
} finally {
|
|
454827
455623
|
emitToolExecutionOutput.flush();
|
|
454828
455624
|
}
|
|
@@ -454846,7 +455642,7 @@ async function handleApprovalStop(params) {
|
|
|
454846
455642
|
if (shouldInterrupt()) {
|
|
454847
455643
|
return interruptTermination();
|
|
454848
455644
|
}
|
|
454849
|
-
|
|
455645
|
+
let nextInput = [
|
|
454850
455646
|
{
|
|
454851
455647
|
type: "approval",
|
|
454852
455648
|
approvals: persistedExecutionResults,
|
|
@@ -454854,11 +455650,14 @@ async function handleApprovalStop(params) {
|
|
|
454854
455650
|
}
|
|
454855
455651
|
];
|
|
454856
455652
|
let continuationBatchId = dequeuedBatchId;
|
|
455653
|
+
let queuedImageFailureModes;
|
|
454857
455654
|
const consumedQueuedTurn = consumeQueuedTurn(runtime);
|
|
454858
455655
|
if (consumedQueuedTurn) {
|
|
454859
455656
|
const { dequeuedBatch, queuedTurn } = consumedQueuedTurn;
|
|
454860
455657
|
continuationBatchId = dequeuedBatch.batchId;
|
|
454861
|
-
nextInput
|
|
455658
|
+
const appended = appendQueuedTurnToInput(nextInput, queuedTurn);
|
|
455659
|
+
nextInput = appended.input;
|
|
455660
|
+
queuedImageFailureModes = appended.imageFailureModesByMessageOtid;
|
|
454862
455661
|
emitDequeuedUserMessage(socket, runtime, queuedTurn, dequeuedBatch);
|
|
454863
455662
|
}
|
|
454864
455663
|
const nextInputWithSkillContent = injectQueuedSkillContent(nextInput);
|
|
@@ -454871,8 +455670,11 @@ async function handleApprovalStop(params) {
|
|
|
454871
455670
|
});
|
|
454872
455671
|
let sendResult;
|
|
454873
455672
|
try {
|
|
455673
|
+
const sendOptions = buildSendOptions() ?? {};
|
|
455674
|
+
const imageFailureModesByMessageOtid = mergeImageFailureModesByMessageOtid(sendOptions.imageFailureModesByMessageOtid, queuedImageFailureModes);
|
|
454874
455675
|
sendResult = await sendApprovalContinuationWithRetry(conversationId, nextInputWithSkillContent, {
|
|
454875
|
-
...
|
|
455676
|
+
...sendOptions,
|
|
455677
|
+
...imageFailureModesByMessageOtid ? { imageFailureModesByMessageOtid } : {},
|
|
454876
455678
|
...continuationWasFullyAutoHandled ? { allowResponseStateReuse: true } : {}
|
|
454877
455679
|
}, socket, runtime, turnLease, { providerFallback });
|
|
454878
455680
|
} catch (error54) {
|
|
@@ -454940,8 +455742,10 @@ var init_turn_approval = __esm(async () => {
|
|
|
454940
455742
|
init_transport();
|
|
454941
455743
|
await __promiseAll([
|
|
454942
455744
|
init_approval_execution(),
|
|
455745
|
+
init_message_image_normalization(),
|
|
454943
455746
|
init_approval(),
|
|
454944
455747
|
init_approval_suggestions(),
|
|
455748
|
+
init_continuation_input(),
|
|
454945
455749
|
init_interrupts(),
|
|
454946
455750
|
init_protocol_outbound(),
|
|
454947
455751
|
init_queue(),
|
|
@@ -456110,14 +456914,7 @@ async function prepareListenerTurn(params) {
|
|
|
456110
456914
|
if (connectionId) {
|
|
456111
456915
|
onStatusChange?.("processing", connectionId);
|
|
456112
456916
|
}
|
|
456113
|
-
|
|
456114
|
-
const normalizedMessages = await normalizeInboundMessages2(msg.messages, undefined, {
|
|
456115
|
-
imageFailureMode: (msg.channelTurnSources?.length ?? 0) > 0 ? "drop" : "strict"
|
|
456116
|
-
});
|
|
456117
|
-
if (isInterrupted()) {
|
|
456118
|
-
return { kind: "interrupted" };
|
|
456119
|
-
}
|
|
456120
|
-
trackListenerUserInput(normalizedMessages, "unknown");
|
|
456917
|
+
trackListenerUserInput(msg.messages, "unknown");
|
|
456121
456918
|
const messagesToSend = [];
|
|
456122
456919
|
let queuedInterruptedToolCallIds = [];
|
|
456123
456920
|
const consumed = consumeInterruptQueue(runtime, agentId, conversationId);
|
|
@@ -456125,12 +456922,16 @@ async function prepareListenerTurn(params) {
|
|
|
456125
456922
|
messagesToSend.push(consumed.approvalMessage);
|
|
456126
456923
|
queuedInterruptedToolCallIds = consumed.interruptedToolCallIds;
|
|
456127
456924
|
}
|
|
456128
|
-
messagesToSend.push(...
|
|
456925
|
+
messagesToSend.push(...msg.messages.map((message) => ("content" in message) && !message.otid ? {
|
|
456129
456926
|
...message,
|
|
456130
456927
|
otid: "client_message_id" in message && typeof message.client_message_id === "string" ? message.client_message_id : crypto.randomUUID()
|
|
456131
456928
|
} : message));
|
|
456929
|
+
const imageFailureModesByMessageOtid = getInboundImageFailureModes({
|
|
456930
|
+
channelTurnSources: msg.channelTurnSources,
|
|
456931
|
+
messages: messagesToSend
|
|
456932
|
+
});
|
|
456132
456933
|
let inboundUserTranscriptLines = buildInboundUserTranscriptLines(messagesToSend);
|
|
456133
|
-
const firstMessage =
|
|
456934
|
+
const firstMessage = msg.messages[0];
|
|
456134
456935
|
const isApprovalMessage = firstMessage && "type" in firstMessage && firstMessage.type === "approval" && "approvals" in firstMessage;
|
|
456135
456936
|
let cachedAgent = null;
|
|
456136
456937
|
if (!isApprovalMessage) {
|
|
@@ -456242,6 +457043,7 @@ async function prepareListenerTurn(params) {
|
|
|
456242
457043
|
kind: "ready",
|
|
456243
457044
|
getCachedAgent: () => cachedAgent,
|
|
456244
457045
|
currentInput,
|
|
457046
|
+
imageFailureModesByMessageOtid,
|
|
456245
457047
|
inboundUserTranscriptLines,
|
|
456246
457048
|
pendingNormalizationInterruptedToolCallIds: [
|
|
456247
457049
|
...queuedInterruptedToolCallIds
|
|
@@ -456260,6 +457062,7 @@ var init_turn_setup = __esm(async () => {
|
|
|
456260
457062
|
init_warmup();
|
|
456261
457063
|
await __promiseAll([
|
|
456262
457064
|
init_toolset(),
|
|
457065
|
+
init_image_policy(),
|
|
456263
457066
|
init_interrupts(),
|
|
456264
457067
|
init_mod_adapter2(),
|
|
456265
457068
|
init_turn_events()
|
|
@@ -456394,7 +457197,9 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456394
457197
|
workingDirectory: turnWorkingDirectory,
|
|
456395
457198
|
permissionModeState: turnPermissionModeState,
|
|
456396
457199
|
preparedToolContext: preparedToolContext.preparedToolContext,
|
|
456397
|
-
|
|
457200
|
+
...setup.imageFailureModesByMessageOtid ? {
|
|
457201
|
+
imageFailureModesByMessageOtid: setup.imageFailureModesByMessageOtid
|
|
457202
|
+
} : {},
|
|
456398
457203
|
...providerFallback.overrideModel ? { overrideModel: providerFallback.overrideModel } : {},
|
|
456399
457204
|
...msg.actingUserId ? { actingUserId: msg.actingUserId } : {},
|
|
456400
457205
|
...pendingNormalizationInterruptedToolCallIds.length > 0 ? {
|
|
@@ -456706,7 +457511,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456706
457511
|
});
|
|
456707
457512
|
break;
|
|
456708
457513
|
}
|
|
456709
|
-
const
|
|
457514
|
+
const errorMessage2 = errorDetail || `Unexpected stop reason: ${stopReason}`;
|
|
456710
457515
|
const terminalRunId = runId || runtime.activeRunId || runErrorInfo2?.run_id;
|
|
456711
457516
|
const transition = finishTurn({
|
|
456712
457517
|
stopReason: effectiveStopReason,
|
|
@@ -456717,7 +457522,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456717
457522
|
break;
|
|
456718
457523
|
}
|
|
456719
457524
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
456720
|
-
message:
|
|
457525
|
+
message: errorMessage2,
|
|
456721
457526
|
stopReason: effectiveStopReason,
|
|
456722
457527
|
isTerminal: true,
|
|
456723
457528
|
runId: terminalRunId,
|
|
@@ -456727,7 +457532,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456727
457532
|
cancelRequested: turnAbortSignal.aborted,
|
|
456728
457533
|
abortSignal: turnAbortSignal
|
|
456729
457534
|
});
|
|
456730
|
-
runtime.lastTerminalLoopErrorMessage = formattedError ??
|
|
457535
|
+
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
456731
457536
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
456732
457537
|
break;
|
|
456733
457538
|
}
|
|
@@ -456849,7 +457654,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456849
457654
|
});
|
|
456850
457655
|
return;
|
|
456851
457656
|
}
|
|
456852
|
-
const
|
|
457657
|
+
const errorMessage2 = error54 instanceof Error ? error54.message : String(error54);
|
|
456853
457658
|
const terminalRunId = runtime.activeRunId;
|
|
456854
457659
|
const transition = finishTurn({
|
|
456855
457660
|
stopReason: "error",
|
|
@@ -456860,7 +457665,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456860
457665
|
return;
|
|
456861
457666
|
}
|
|
456862
457667
|
const formattedError = emitLoopErrorNotice(socket, runtime, {
|
|
456863
|
-
message:
|
|
457668
|
+
message: errorMessage2,
|
|
456864
457669
|
stopReason: "error",
|
|
456865
457670
|
isTerminal: true,
|
|
456866
457671
|
runId: terminalRunId,
|
|
@@ -456870,7 +457675,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
|
|
|
456870
457675
|
cancelRequested: turnAbortSignal.aborted,
|
|
456871
457676
|
abortSignal: turnAbortSignal
|
|
456872
457677
|
});
|
|
456873
|
-
runtime.lastTerminalLoopErrorMessage = formattedError ??
|
|
457678
|
+
runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage2;
|
|
456874
457679
|
runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
|
|
456875
457680
|
if (isDebugEnabled()) {
|
|
456876
457681
|
console.error("[Listen] Error handling message:", error54);
|
|
@@ -458343,11 +459148,11 @@ async function handleExecuteCommand(command, socket, conversationRuntime, opts)
|
|
|
458343
459148
|
error: error54,
|
|
458344
459149
|
context: "listener_command_execution"
|
|
458345
459150
|
});
|
|
458346
|
-
const
|
|
459151
|
+
const errorMessage2 = error54 instanceof Error ? error54.message : String(error54);
|
|
458347
459152
|
emitSlashCommandEnd(socket, conversationRuntime, scope, {
|
|
458348
459153
|
command_id: command.command_id,
|
|
458349
459154
|
input,
|
|
458350
|
-
output: `Failed: ${
|
|
459155
|
+
output: `Failed: ${errorMessage2}`,
|
|
458351
459156
|
success: false
|
|
458352
459157
|
});
|
|
458353
459158
|
}
|
|
@@ -460748,7 +461553,7 @@ var init_grep_in_files = __esm(() => {
|
|
|
460748
461553
|
});
|
|
460749
461554
|
|
|
460750
461555
|
// src/websocket/listener/file-commands.ts
|
|
460751
|
-
import { readdir as readdir11, readFile as
|
|
461556
|
+
import { readdir as readdir11, readFile as readFile17 } from "node:fs/promises";
|
|
460752
461557
|
import { homedir as homedir30 } from "node:os";
|
|
460753
461558
|
import path35 from "node:path";
|
|
460754
461559
|
function trackListenerError2(errorType, error54, context4) {
|
|
@@ -460803,7 +461608,7 @@ async function getIgnoreConfig(root2) {
|
|
|
460803
461608
|
return cached3;
|
|
460804
461609
|
let patterns2 = [];
|
|
460805
461610
|
try {
|
|
460806
|
-
const content = await
|
|
461611
|
+
const content = await readFile17(path35.join(absRoot, ".letta", ".lettaignore"), "utf-8");
|
|
460807
461612
|
patterns2 = parseLettaIgnore(content);
|
|
460808
461613
|
} catch {
|
|
460809
461614
|
patterns2 = [];
|
|
@@ -463546,7 +464351,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
|
|
|
463546
464351
|
ensureLocalMemfsCheckout: ensureLocalMemfsCheckout2,
|
|
463547
464352
|
isMemfsEnabledOnServer: isMemfsEnabledOnServer2
|
|
463548
464353
|
} = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
|
|
463549
|
-
const { readFile:
|
|
464354
|
+
const { readFile: readFile18 } = await import("node:fs/promises");
|
|
463550
464355
|
const { existsSync: existsSync46 } = await import("node:fs");
|
|
463551
464356
|
const { isAbsolute: isAbsolute24, join: join52, normalize: normalize5, relative: relative13, sep: sep6 } = await import("node:path");
|
|
463552
464357
|
if (isAbsolute24(parsed.path) || parsed.path.length === 0) {
|
|
@@ -463572,7 +464377,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
|
|
|
463572
464377
|
return;
|
|
463573
464378
|
}
|
|
463574
464379
|
}
|
|
463575
|
-
const buffer = await
|
|
464380
|
+
const buffer = await readFile18(absolutePath);
|
|
463576
464381
|
const content = encoding === "base64" ? buffer.toString("base64") : buffer.toString("utf-8");
|
|
463577
464382
|
const pathspec = rel.split(sep6).join("/");
|
|
463578
464383
|
safeSocketSend(socket, {
|
|
@@ -463612,7 +464417,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
|
|
|
463612
464417
|
isMemfsEnabledOnServer: isMemfsEnabledOnServer2
|
|
463613
464418
|
} = await Promise.resolve().then(() => (init_memory_filesystem2(), exports_memory_filesystem));
|
|
463614
464419
|
const { commitMemoryWrite: commitMemoryWrite2 } = await Promise.resolve().then(() => (init_memory_git(), exports_memory_git));
|
|
463615
|
-
const { writeFile:
|
|
464420
|
+
const { writeFile: writeFile14, mkdir: mkdir13 } = await import("node:fs/promises");
|
|
463616
464421
|
const { existsSync: existsSync46 } = await import("node:fs");
|
|
463617
464422
|
const { dirname: dirname27, isAbsolute: isAbsolute24, join: join52, normalize: normalize5, relative: relative13, sep: sep6 } = await import("node:path");
|
|
463618
464423
|
if (isAbsolute24(parsed.path) || parsed.path.length === 0) {
|
|
@@ -463640,7 +464445,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
|
|
|
463640
464445
|
}
|
|
463641
464446
|
const buffer = encoding === "base64" ? Buffer.from(parsed.content, "base64") : Buffer.from(parsed.content, "utf-8");
|
|
463642
464447
|
await mkdir13(dirname27(absolutePath), { recursive: true });
|
|
463643
|
-
await
|
|
464448
|
+
await writeFile14(absolutePath, buffer);
|
|
463644
464449
|
const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
|
|
463645
464450
|
const backend4 = getBackend2();
|
|
463646
464451
|
const memorySyncMode = backend4.capabilities.localMemfs && !backend4.capabilities.remoteMemfs ? "local" : undefined;
|
|
@@ -464280,7 +465085,8 @@ async function handleCreateAgentCommand(parsed, socket, safeSocketSend) {
|
|
|
464280
465085
|
const { createAgentForPersonality: createAgentForPersonality2 } = await Promise.resolve().then(() => (init_personality(), exports_personality));
|
|
464281
465086
|
const result = await createAgentForPersonality2({
|
|
464282
465087
|
personalityId: parsed.personality,
|
|
464283
|
-
model: parsed.model
|
|
465088
|
+
model: parsed.model,
|
|
465089
|
+
...parsed.tags && { tags: parsed.tags }
|
|
464284
465090
|
});
|
|
464285
465091
|
if (parsed.pin_global !== false) {
|
|
464286
465092
|
settingsManager.pinAgent(result.agent.id);
|
|
@@ -465803,11 +466609,13 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
|
|
|
465803
466609
|
if (attempt === 0) {
|
|
465804
466610
|
await loadTools();
|
|
465805
466611
|
}
|
|
465806
|
-
const
|
|
465807
|
-
|
|
465808
|
-
|
|
465809
|
-
|
|
466612
|
+
const auth = await resolveListenerReconnectAuth(opts);
|
|
466613
|
+
if (auth.kind === "retry")
|
|
466614
|
+
return connectWithRetry(runtime, opts, attempt + 1, startTime);
|
|
466615
|
+
if (runtime !== getActiveRuntime() || runtime.intentionallyClosed) {
|
|
466616
|
+
return;
|
|
465810
466617
|
}
|
|
466618
|
+
const apiKey = auth.apiKey;
|
|
465811
466619
|
const url2 = new URL(opts.wsUrl);
|
|
465812
466620
|
url2.searchParams.set("deviceId", opts.deviceId);
|
|
465813
466621
|
url2.searchParams.set("connectionName", opts.connectionName);
|
|
@@ -465994,6 +466802,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
465994
466802
|
init_debug();
|
|
465995
466803
|
init_message_queue_bridge();
|
|
465996
466804
|
init_terminal_handler();
|
|
466805
|
+
init_auth();
|
|
465997
466806
|
init_channel_turn_session();
|
|
465998
466807
|
init_constants3();
|
|
465999
466808
|
init_cwd();
|
|
@@ -466766,7 +467575,7 @@ var execFile15, __dirname2, localXdgOpenPath, platform8, arch3, pTryEach = async
|
|
|
466766
467575
|
}
|
|
466767
467576
|
subprocess.unref();
|
|
466768
467577
|
return subprocess;
|
|
466769
|
-
},
|
|
467578
|
+
}, open4 = (target2, options3) => {
|
|
466770
467579
|
if (typeof target2 !== "string") {
|
|
466771
467580
|
throw new TypeError("Expected a `target`");
|
|
466772
467581
|
}
|
|
@@ -466835,14 +467644,14 @@ var init_open = __esm(() => {
|
|
|
466835
467644
|
}));
|
|
466836
467645
|
defineLazyProperty(apps, "browser", () => "browser");
|
|
466837
467646
|
defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
|
|
466838
|
-
open_default =
|
|
467647
|
+
open_default = open4;
|
|
466839
467648
|
});
|
|
466840
467649
|
|
|
466841
467650
|
// src/cli/commands/connect-oauth-core.ts
|
|
466842
467651
|
async function openOAuthBrowser(authorizationUrl) {
|
|
466843
467652
|
try {
|
|
466844
|
-
const { default:
|
|
466845
|
-
const subprocess = await
|
|
467653
|
+
const { default: open5 } = await Promise.resolve().then(() => (init_open(), exports_open));
|
|
467654
|
+
const subprocess = await open5(authorizationUrl, { wait: false });
|
|
466846
467655
|
subprocess.on("error", () => {});
|
|
466847
467656
|
} catch {}
|
|
466848
467657
|
}
|
|
@@ -468857,141 +469666,6 @@ var init_startup = __esm(() => {
|
|
|
468857
469666
|
init_mode();
|
|
468858
469667
|
});
|
|
468859
469668
|
|
|
468860
|
-
// src/websocket/listen-register.ts
|
|
468861
|
-
import { createHash as createHash7 } from "node:crypto";
|
|
468862
|
-
function deriveListenerInstanceId(surface, connectionName) {
|
|
468863
|
-
const nameHash = createHash7("sha256").update(connectionName).digest("hex").slice(0, 16);
|
|
468864
|
-
return `${surface}-${nameHash}`;
|
|
468865
|
-
}
|
|
468866
|
-
function isTransientRegistrationError(error54) {
|
|
468867
|
-
if (error54 instanceof RegistrationError) {
|
|
468868
|
-
return error54.statusCode === 0 || error54.statusCode === 429 || error54.statusCode >= 500;
|
|
468869
|
-
}
|
|
468870
|
-
return true;
|
|
468871
|
-
}
|
|
468872
|
-
function parseRetryAfterMs(value) {
|
|
468873
|
-
if (!value) {
|
|
468874
|
-
return;
|
|
468875
|
-
}
|
|
468876
|
-
const seconds = Number(value);
|
|
468877
|
-
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
468878
|
-
return seconds * 1000;
|
|
468879
|
-
}
|
|
468880
|
-
const dateMs = Date.parse(value);
|
|
468881
|
-
if (Number.isFinite(dateMs)) {
|
|
468882
|
-
return Math.max(0, dateMs - Date.now());
|
|
468883
|
-
}
|
|
468884
|
-
return;
|
|
468885
|
-
}
|
|
468886
|
-
async function registerWithCloud(opts, fetchImpl = fetch) {
|
|
468887
|
-
const registerUrl = `${opts.serverUrl}/v1/environments/register`;
|
|
468888
|
-
const response = await fetchImpl(registerUrl, {
|
|
468889
|
-
method: "POST",
|
|
468890
|
-
headers: {
|
|
468891
|
-
"Content-Type": "application/json",
|
|
468892
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
468893
|
-
"X-Letta-Source": "letta-code"
|
|
468894
|
-
},
|
|
468895
|
-
body: JSON.stringify({
|
|
468896
|
-
deviceId: opts.deviceId,
|
|
468897
|
-
...opts.listenerInstanceId ? { listenerInstanceId: opts.listenerInstanceId } : {},
|
|
468898
|
-
connectionName: opts.connectionName,
|
|
468899
|
-
metadata: {
|
|
468900
|
-
lettaCodeVersion: getVersion(),
|
|
468901
|
-
os: process.platform,
|
|
468902
|
-
nodeVersion: process.version,
|
|
468903
|
-
environmentMessageProtocol: "v2-input",
|
|
468904
|
-
supported_commands: SUPPORTED_REMOTE_COMMANDS,
|
|
468905
|
-
self_update: getSelfUpdateStatus()
|
|
468906
|
-
}
|
|
468907
|
-
})
|
|
468908
|
-
}).catch((fetchError) => {
|
|
468909
|
-
const msg = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
468910
|
-
throw new RegistrationError(`Network error: ${msg}`, 0);
|
|
468911
|
-
});
|
|
468912
|
-
if (!response.ok) {
|
|
468913
|
-
let detail = `HTTP ${response.status}`;
|
|
468914
|
-
const retryAfterMs2 = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
468915
|
-
const text2 = await response.text().catch(() => "");
|
|
468916
|
-
if (text2) {
|
|
468917
|
-
try {
|
|
468918
|
-
const parsed = JSON.parse(text2);
|
|
468919
|
-
if (parsed.message) {
|
|
468920
|
-
detail = parsed.message;
|
|
468921
|
-
} else if (parsed.error) {
|
|
468922
|
-
detail = `HTTP ${response.status}: ${parsed.error}`;
|
|
468923
|
-
if (parsed.errorCode) {
|
|
468924
|
-
detail += ` (${parsed.errorCode})`;
|
|
468925
|
-
}
|
|
468926
|
-
} else {
|
|
468927
|
-
detail += `: ${text2.slice(0, 200)}`;
|
|
468928
|
-
}
|
|
468929
|
-
} catch {
|
|
468930
|
-
detail += `: ${text2.slice(0, 200)}`;
|
|
468931
|
-
}
|
|
468932
|
-
}
|
|
468933
|
-
throw new RegistrationError(detail, response.status, retryAfterMs2);
|
|
468934
|
-
}
|
|
468935
|
-
let body3;
|
|
468936
|
-
try {
|
|
468937
|
-
body3 = await response.json();
|
|
468938
|
-
} catch {
|
|
468939
|
-
throw new RegistrationError("Server returned non-JSON response — is the server running?", response.status);
|
|
468940
|
-
}
|
|
468941
|
-
const result = body3;
|
|
468942
|
-
if (typeof result.connectionId !== "string" || typeof result.wsUrl !== "string") {
|
|
468943
|
-
throw new RegistrationError("Server returned unexpected response shape (missing connectionId or wsUrl)", response.status);
|
|
468944
|
-
}
|
|
468945
|
-
return {
|
|
468946
|
-
connectionId: result.connectionId,
|
|
468947
|
-
wsUrl: result.wsUrl,
|
|
468948
|
-
supportsSplitStatusChannels: result.supportsSplitStatusChannels === true
|
|
468949
|
-
};
|
|
468950
|
-
}
|
|
468951
|
-
async function registerWithCloudRetry(opts, callbacks) {
|
|
468952
|
-
const startTime = Date.now();
|
|
468953
|
-
const maxDurationMs = callbacks?.maxDurationMs ?? REGISTER_MAX_DURATION_MS;
|
|
468954
|
-
const sleep9 = callbacks?.sleep ?? ((delayMs) => new Promise((resolve31) => setTimeout(resolve31, delayMs)));
|
|
468955
|
-
let attempt = 0;
|
|
468956
|
-
for (;; ) {
|
|
468957
|
-
try {
|
|
468958
|
-
return await registerWithCloud(opts, callbacks?.fetchImpl);
|
|
468959
|
-
} catch (error54) {
|
|
468960
|
-
const elapsed = Date.now() - startTime;
|
|
468961
|
-
if (!isTransientRegistrationError(error54) || elapsed >= maxDurationMs) {
|
|
468962
|
-
throw error54;
|
|
468963
|
-
}
|
|
468964
|
-
attempt++;
|
|
468965
|
-
const backoffDelay = Math.min(REGISTER_INITIAL_DELAY_MS * 2 ** (attempt - 1), REGISTER_MAX_DELAY_MS);
|
|
468966
|
-
const delay2 = error54 instanceof RegistrationError && error54.retryAfterMs !== undefined ? Math.max(error54.retryAfterMs, backoffDelay) : backoffDelay;
|
|
468967
|
-
const jitterWindow = Math.min(REGISTER_MAX_JITTER_MS, Math.floor(delay2 * REGISTER_JITTER_RATIO));
|
|
468968
|
-
const jitter = jitterWindow > 0 ? Math.floor((callbacks?.random ?? Math.random)() * jitterWindow) : 0;
|
|
468969
|
-
const retryDelay = delay2 + jitter;
|
|
468970
|
-
if (error54 instanceof Error) {
|
|
468971
|
-
callbacks?.onRetry?.(attempt, retryDelay, error54);
|
|
468972
|
-
}
|
|
468973
|
-
await sleep9(retryDelay);
|
|
468974
|
-
}
|
|
468975
|
-
}
|
|
468976
|
-
}
|
|
468977
|
-
var RegistrationError, REGISTER_INITIAL_DELAY_MS = 1000, REGISTER_MAX_DELAY_MS = 30000, REGISTER_MAX_DURATION_MS, REGISTER_MAX_JITTER_MS = 1000, REGISTER_JITTER_RATIO = 0.25;
|
|
468978
|
-
var init_listen_register = __esm(() => {
|
|
468979
|
-
init_auto_update();
|
|
468980
|
-
init_version();
|
|
468981
|
-
init_listener_constants();
|
|
468982
|
-
RegistrationError = class RegistrationError extends Error {
|
|
468983
|
-
statusCode;
|
|
468984
|
-
retryAfterMs;
|
|
468985
|
-
constructor(message, statusCode2, retryAfterMs2) {
|
|
468986
|
-
super(message);
|
|
468987
|
-
this.name = "RegistrationError";
|
|
468988
|
-
this.statusCode = statusCode2;
|
|
468989
|
-
this.retryAfterMs = retryAfterMs2;
|
|
468990
|
-
}
|
|
468991
|
-
};
|
|
468992
|
-
REGISTER_MAX_DURATION_MS = 2 * 60 * 1000;
|
|
468993
|
-
});
|
|
468994
|
-
|
|
468995
469669
|
// src/websocket/listener/client.ts
|
|
468996
469670
|
function asListenerRuntimeForTests(runtime) {
|
|
468997
469671
|
return "listener" in runtime ? runtime.listener : runtime;
|
|
@@ -469284,8 +469958,6 @@ var init_client7 = __esm(async () => {
|
|
|
469284
469958
|
shouldAttemptPostStopApprovalRecovery,
|
|
469285
469959
|
markAwaitingAcceptedApprovalContinuationRunId,
|
|
469286
469960
|
resolveStaleApprovals,
|
|
469287
|
-
normalizeMessageContentImages: normalizeMessageContentImages2,
|
|
469288
|
-
normalizeInboundMessages,
|
|
469289
469961
|
consumeQueuedTurn,
|
|
469290
469962
|
handleIncomingMessage,
|
|
469291
469963
|
handleApprovalResponseInput,
|
|
@@ -469729,7 +470401,7 @@ function ConstellationLoginView({
|
|
|
469729
470401
|
const deviceData = await requestDeviceCode();
|
|
469730
470402
|
setUserCode(deviceData.user_code);
|
|
469731
470403
|
setVerificationUri(deviceData.verification_uri_complete);
|
|
469732
|
-
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default:
|
|
470404
|
+
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(deviceData.verification_uri_complete, { wait: false })).then((subprocess) => {
|
|
469733
470405
|
subprocess.on("error", () => {});
|
|
469734
470406
|
}).catch(() => {});
|
|
469735
470407
|
const deviceId = settingsManager.getOrCreateDeviceId();
|
|
@@ -471654,7 +472326,7 @@ __export(exports_skills3, {
|
|
|
471654
472326
|
GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
|
|
471655
472327
|
});
|
|
471656
472328
|
import { existsSync as existsSync54 } from "node:fs";
|
|
471657
|
-
import { readdir as readdir15, readFile as
|
|
472329
|
+
import { readdir as readdir15, readFile as readFile21, realpath as realpath6, stat as stat15 } from "node:fs/promises";
|
|
471658
472330
|
import { dirname as dirname31, join as join62 } from "node:path";
|
|
471659
472331
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
471660
472332
|
function getBundledSkillsPath2() {
|
|
@@ -471826,7 +472498,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors7, source2,
|
|
|
471826
472498
|
}
|
|
471827
472499
|
}
|
|
471828
472500
|
async function parseSkillFile2(filePath, rootPath, source2) {
|
|
471829
|
-
const content = await
|
|
472501
|
+
const content = await readFile21(filePath, "utf-8");
|
|
471830
472502
|
const { frontmatter, body: body3 } = parseFrontmatter(content);
|
|
471831
472503
|
const normalizedRoot = rootPath.endsWith("/") ? rootPath.slice(0, -1) : rootPath;
|
|
471832
472504
|
const relativePath = filePath.slice(normalizedRoot.length + 1);
|
|
@@ -471886,9 +472558,9 @@ var init_skills4 = __esm(() => {
|
|
|
471886
472558
|
var exports_fs = {};
|
|
471887
472559
|
__export(exports_fs, {
|
|
471888
472560
|
writeJsonFile: () => writeJsonFile2,
|
|
471889
|
-
writeFile: () =>
|
|
472561
|
+
writeFile: () => writeFile16,
|
|
471890
472562
|
readJsonFile: () => readJsonFile4,
|
|
471891
|
-
readFile: () =>
|
|
472563
|
+
readFile: () => readFile22,
|
|
471892
472564
|
mkdir: () => mkdir15,
|
|
471893
472565
|
exists: () => exists2
|
|
471894
472566
|
});
|
|
@@ -471899,10 +472571,10 @@ import {
|
|
|
471899
472571
|
mkdirSync as mkdirSync38
|
|
471900
472572
|
} from "node:fs";
|
|
471901
472573
|
import { dirname as dirname32 } from "node:path";
|
|
471902
|
-
async function
|
|
472574
|
+
async function readFile22(path39) {
|
|
471903
472575
|
return fsReadFileSync2(path39, { encoding: "utf-8" });
|
|
471904
472576
|
}
|
|
471905
|
-
async function
|
|
472577
|
+
async function writeFile16(path39, content) {
|
|
471906
472578
|
const dir = dirname32(path39);
|
|
471907
472579
|
if (!existsSync55(dir)) {
|
|
471908
472580
|
mkdirSync38(dir, { recursive: true });
|
|
@@ -471916,14 +472588,14 @@ async function mkdir15(path39, options3) {
|
|
|
471916
472588
|
mkdirSync38(path39, options3);
|
|
471917
472589
|
}
|
|
471918
472590
|
async function readJsonFile4(path39) {
|
|
471919
|
-
const text2 = await
|
|
472591
|
+
const text2 = await readFile22(path39);
|
|
471920
472592
|
return JSON.parse(text2);
|
|
471921
472593
|
}
|
|
471922
472594
|
async function writeJsonFile2(path39, data, options3) {
|
|
471923
472595
|
const indent = options3?.indent ?? 2;
|
|
471924
472596
|
const content = `${JSON.stringify(data, null, indent)}
|
|
471925
472597
|
`;
|
|
471926
|
-
await
|
|
472598
|
+
await writeFile16(path39, content);
|
|
471927
472599
|
}
|
|
471928
472600
|
var init_fs2 = () => {};
|
|
471929
472601
|
|
|
@@ -472122,7 +472794,7 @@ import {
|
|
|
472122
472794
|
execFile as execFile17
|
|
472123
472795
|
} from "node:child_process";
|
|
472124
472796
|
import { accessSync as accessSync2, constants as constants4, realpathSync as realpathSync6 } from "node:fs";
|
|
472125
|
-
import { readdir as readdir16, rm as
|
|
472797
|
+
import { readdir as readdir16, rm as rm7 } from "node:fs/promises";
|
|
472126
472798
|
import { dirname as dirname33, join as join63 } from "node:path";
|
|
472127
472799
|
import { promisify as promisify15 } from "node:util";
|
|
472128
472800
|
function debugLog4(...args) {
|
|
@@ -472354,7 +473026,7 @@ async function cleanupOrphanedDirs2(globalPath) {
|
|
|
472354
473026
|
if (entry.startsWith(".letta-code-")) {
|
|
472355
473027
|
const orphanPath = join63(lettaAiDir, entry);
|
|
472356
473028
|
debugLog4("Cleaning orphaned temp directory:", orphanPath);
|
|
472357
|
-
await
|
|
473029
|
+
await rm7(orphanPath, { recursive: true, force: true });
|
|
472358
473030
|
}
|
|
472359
473031
|
}
|
|
472360
473032
|
} catch {}
|
|
@@ -473822,7 +474494,7 @@ __export(exports_import, {
|
|
|
473822
474494
|
extractSkillsFromAf: () => extractSkillsFromAf
|
|
473823
474495
|
});
|
|
473824
474496
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
473825
|
-
import { access as access2, chmod, mkdir as mkdir16, readFile as
|
|
474497
|
+
import { access as access2, chmod, mkdir as mkdir16, readFile as readFile23, writeFile as writeFile17 } from "node:fs/promises";
|
|
473826
474498
|
import { dirname as dirname34, isAbsolute as isAbsolute25, relative as relative13, resolve as resolve36, sep as sep7, win32 as win325 } from "node:path";
|
|
473827
474499
|
function validateImportedSkillName(name) {
|
|
473828
474500
|
const trimmedName = name.trim();
|
|
@@ -473923,7 +474595,7 @@ async function importAgentFromFile(options3) {
|
|
|
473923
474595
|
}
|
|
473924
474596
|
async function extractSkillsFromAf(afPath, destDir) {
|
|
473925
474597
|
const extracted = [];
|
|
473926
|
-
const content = await
|
|
474598
|
+
const content = await readFile23(afPath, "utf-8");
|
|
473927
474599
|
const afData = JSON.parse(content);
|
|
473928
474600
|
if (!afData.skills || !Array.isArray(afData.skills)) {
|
|
473929
474601
|
return [];
|
|
@@ -473952,7 +474624,7 @@ async function writeSkillFiles(skillDir, files) {
|
|
|
473952
474624
|
async function writeSkillFile(skillDir, filePath, content) {
|
|
473953
474625
|
const fullPath = resolveImportedSkillFilePath(skillDir, filePath);
|
|
473954
474626
|
await mkdir16(dirname34(fullPath), { recursive: true });
|
|
473955
|
-
await
|
|
474627
|
+
await writeFile17(fullPath, content, "utf-8");
|
|
473956
474628
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
473957
474629
|
if (isScript) {
|
|
473958
474630
|
try {
|
|
@@ -474005,7 +474677,7 @@ function parseRegistryHandle(handle2) {
|
|
|
474005
474677
|
async function importAgentFromRegistry(options3) {
|
|
474006
474678
|
const { tmpdir: tmpdir10 } = await import("node:os");
|
|
474007
474679
|
const { join: join68 } = await import("node:path");
|
|
474008
|
-
const { writeFile:
|
|
474680
|
+
const { writeFile: writeFile18, unlink: unlink5 } = await import("node:fs/promises");
|
|
474009
474681
|
const { author, name } = parseRegistryHandle(options3.handle);
|
|
474010
474682
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
|
|
474011
474683
|
const response = await fetch(rawUrl);
|
|
@@ -474017,7 +474689,7 @@ async function importAgentFromRegistry(options3) {
|
|
|
474017
474689
|
}
|
|
474018
474690
|
const afContent = await response.text();
|
|
474019
474691
|
const tempPath = join68(tmpdir10(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
474020
|
-
await
|
|
474692
|
+
await writeFile18(tempPath, afContent, "utf-8");
|
|
474021
474693
|
try {
|
|
474022
474694
|
const result = await importAgentFromFile({
|
|
474023
474695
|
filePath: tempPath,
|
|
@@ -474125,7 +474797,8 @@ async function ensureDefaultAgents(backend4, options3) {
|
|
|
474125
474797
|
const createOptions = personality === "tutorial" ? {
|
|
474126
474798
|
...await buildCreateAgentOptionsForPersonality2({
|
|
474127
474799
|
personalityId: "tutorial",
|
|
474128
|
-
model
|
|
474800
|
+
model,
|
|
474801
|
+
tags: [ONBOARDING_ORIGIN_TAG]
|
|
474129
474802
|
}),
|
|
474130
474803
|
memoryPromptMode
|
|
474131
474804
|
} : {
|
|
@@ -476245,7 +476918,7 @@ ${loadedContents.join(`
|
|
|
476245
476918
|
markIncompleteToolsAsCancelled(buffers, true, "stream_error");
|
|
476246
476919
|
const errorLines = toLines(buffers).filter((line) => line.kind === "error");
|
|
476247
476920
|
const errorMessages2 = errorLines.map((line) => ("text" in line) ? line.text : "").filter(Boolean);
|
|
476248
|
-
let
|
|
476921
|
+
let errorMessage2 = errorMessages2.length > 0 ? errorMessages2.join("; ") : `Unexpected stop reason: ${stopReason}`;
|
|
476249
476922
|
if (lastRunId && errorMessages2.length === 0) {
|
|
476250
476923
|
try {
|
|
476251
476924
|
const run = await getBackend().retrieveRun(lastRunId);
|
|
@@ -476257,18 +476930,18 @@ ${loadedContents.join(`
|
|
|
476257
476930
|
run_id: lastRunId
|
|
476258
476931
|
}
|
|
476259
476932
|
};
|
|
476260
|
-
|
|
476933
|
+
errorMessage2 = formatErrorDetails2(errorObject, agent2.id);
|
|
476261
476934
|
}
|
|
476262
476935
|
} catch (_e) {
|
|
476263
|
-
|
|
476936
|
+
errorMessage2 = `${errorMessage2}
|
|
476264
476937
|
(Unable to fetch additional error details from server)`;
|
|
476265
476938
|
}
|
|
476266
476939
|
}
|
|
476267
|
-
trackHeadlessBoundaryError("headless_turn_failed",
|
|
476940
|
+
trackHeadlessBoundaryError("headless_turn_failed", errorMessage2, "headless_turn_execution");
|
|
476268
476941
|
if (outputFormat === "stream-json") {
|
|
476269
476942
|
const errorMsg = {
|
|
476270
476943
|
type: "error",
|
|
476271
|
-
message:
|
|
476944
|
+
message: errorMessage2,
|
|
476272
476945
|
stop_reason: stopReason,
|
|
476273
476946
|
run_id: lastRunId ?? undefined,
|
|
476274
476947
|
session_id: sessionId,
|
|
@@ -476276,7 +476949,7 @@ ${loadedContents.join(`
|
|
|
476276
476949
|
};
|
|
476277
476950
|
await writeWireMessageAsync(errorMsg);
|
|
476278
476951
|
} else {
|
|
476279
|
-
console.error(`Error: ${
|
|
476952
|
+
console.error(`Error: ${errorMessage2}`);
|
|
476280
476953
|
}
|
|
476281
476954
|
await exitHeadless(1, "headless_stop_reason_error");
|
|
476282
476955
|
}
|
|
@@ -478832,7 +479505,7 @@ var init_queued_message_parts = __esm(() => {
|
|
|
478832
479505
|
// src/cli/helpers/reflection-arena-hf-upload.ts
|
|
478833
479506
|
import { execFile as execFileCb5 } from "node:child_process";
|
|
478834
479507
|
import { existsSync as existsSync60 } from "node:fs";
|
|
478835
|
-
import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as
|
|
479508
|
+
import { appendFile as appendFile2, chmod as chmod2, mkdir as mkdir17, writeFile as writeFile18 } from "node:fs/promises";
|
|
478836
479509
|
import { homedir as homedir38 } from "node:os";
|
|
478837
479510
|
import { join as join69 } from "node:path";
|
|
478838
479511
|
import { promisify as promisify16 } from "node:util";
|
|
@@ -478871,7 +479544,7 @@ async function runGit6(cwd2, args, env5) {
|
|
|
478871
479544
|
}
|
|
478872
479545
|
async function writeGitAskpass(repoRoot) {
|
|
478873
479546
|
const askpassPath = join69(repoRoot, "hf-askpass.sh");
|
|
478874
|
-
await
|
|
479547
|
+
await writeFile18(askpassPath, [
|
|
478875
479548
|
"#!/bin/sh",
|
|
478876
479549
|
'case "$1" in',
|
|
478877
479550
|
" *Username*) printf '%s\\n' 'hf_user' ;;",
|
|
@@ -478956,7 +479629,7 @@ var init_reflection_arena_hf_upload = __esm(() => {
|
|
|
478956
479629
|
// src/cli/helpers/reflection-arena.ts
|
|
478957
479630
|
import { execFile as execFileCb6 } from "node:child_process";
|
|
478958
479631
|
import { randomInt, randomUUID as randomUUID30 } from "node:crypto";
|
|
478959
|
-
import { appendFile as appendFile3, mkdir as mkdir18, readFile as
|
|
479632
|
+
import { appendFile as appendFile3, mkdir as mkdir18, readFile as readFile24, writeFile as writeFile19 } from "node:fs/promises";
|
|
478960
479633
|
import { homedir as homedir39 } from "node:os";
|
|
478961
479634
|
import { join as join70 } from "node:path";
|
|
478962
479635
|
import { promisify as promisify17 } from "node:util";
|
|
@@ -479001,11 +479674,11 @@ function getReflectionArenaRunPath(runId) {
|
|
|
479001
479674
|
}
|
|
479002
479675
|
async function saveReflectionArenaRun(run) {
|
|
479003
479676
|
await mkdir18(getReflectionArenaRunsDir(), { recursive: true });
|
|
479004
|
-
await
|
|
479677
|
+
await writeFile19(getReflectionArenaRunPath(run.runId), `${JSON.stringify(run, null, 2)}
|
|
479005
479678
|
`, "utf-8");
|
|
479006
479679
|
}
|
|
479007
479680
|
async function loadReflectionArenaRun(runId) {
|
|
479008
|
-
const raw2 = await
|
|
479681
|
+
const raw2 = await readFile24(getReflectionArenaRunPath(runId), "utf-8");
|
|
479009
479682
|
return JSON.parse(raw2);
|
|
479010
479683
|
}
|
|
479011
479684
|
async function updateReflectionArenaRun(runId, update2) {
|
|
@@ -479197,7 +479870,7 @@ async function appendChoiceRecord(run) {
|
|
|
479197
479870
|
}
|
|
479198
479871
|
async function readTranscriptPayloadForTelemetry(payloadPath) {
|
|
479199
479872
|
try {
|
|
479200
|
-
const transcript = await
|
|
479873
|
+
const transcript = await readFile24(payloadPath, "utf-8");
|
|
479201
479874
|
return {
|
|
479202
479875
|
transcriptPayload: transcript.slice(0, REFLECTION_ARENA_TELEMETRY_TRANSCRIPT_MAX_CHARS),
|
|
479203
479876
|
transcriptPayloadChars: transcript.length,
|
|
@@ -489773,7 +490446,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
489773
490446
|
const isLocalAgent = agentId ? isLocalAgentId2(agentId) : false;
|
|
489774
490447
|
const showCloudLinks = Boolean(isCloudUser && agentId && !isLocalAgent);
|
|
489775
490448
|
const adeConversationUrl = showCloudLinks && agentId && agentId !== "loading" ? buildChatUrl(agentId, { conversationId }) : "";
|
|
489776
|
-
const usageUrl =
|
|
490449
|
+
const usageUrl = buildChatWebUrl("/preferences/usage");
|
|
489777
490450
|
const showBottomBar = agentId && agentId !== "loading";
|
|
489778
490451
|
const reasoningLabel = shouldHideReasoningForModelDisplay(currentModel) ? null : formatReasoningLabel(currentReasoningEffort);
|
|
489779
490452
|
const modelLine = currentModel ? `${currentModel}${reasoningLabel ? ` (${reasoningLabel})` : ""}` : null;
|
|
@@ -493294,7 +493967,7 @@ function buildInstallPrBody(workflowPath) {
|
|
|
493294
493967
|
"",
|
|
493295
493968
|
"You can also specify a particular agent: `@letta-code [--agent agent-xxx]`",
|
|
493296
493969
|
"",
|
|
493297
|
-
"
|
|
493970
|
+
"Chat with your agent at [chat.letta.com](https://chat.letta.com).",
|
|
493298
493971
|
"",
|
|
493299
493972
|
"### Important Notes",
|
|
493300
493973
|
"",
|
|
@@ -493615,7 +494288,7 @@ var init_InstallGithubAppFlow = __esm(async () => {
|
|
|
493615
494288
|
const solidLine = SOLID_LINE12.repeat(Math.max(terminalWidth, 10));
|
|
493616
494289
|
const [step, setStep] = import_react87.useState("checking");
|
|
493617
494290
|
const [status, setStatus] = import_react87.useState("Checking GitHub CLI prerequisites...");
|
|
493618
|
-
const [
|
|
494291
|
+
const [errorMessage2, setErrorMessage] = import_react87.useState("");
|
|
493619
494292
|
const [currentRepo, setCurrentRepo] = import_react87.useState(null);
|
|
493620
494293
|
const [repoChoiceIndex, setRepoChoiceIndex] = import_react87.useState(0);
|
|
493621
494294
|
const [repoInput, setRepoInput] = import_react87.useState("");
|
|
@@ -494183,14 +494856,14 @@ var init_InstallGithubAppFlow = __esm(async () => {
|
|
|
494183
494856
|
color: "red",
|
|
494184
494857
|
children: [
|
|
494185
494858
|
"Error: ",
|
|
494186
|
-
|
|
494859
|
+
errorMessage2.split(`
|
|
494187
494860
|
`)[0] || "Unknown error"
|
|
494188
494861
|
]
|
|
494189
494862
|
}, undefined, true, undefined, this),
|
|
494190
494863
|
/* @__PURE__ */ jsx_dev_runtime61.jsxDEV(Box_default, {
|
|
494191
494864
|
height: 1
|
|
494192
494865
|
}, undefined, false, undefined, this),
|
|
494193
|
-
|
|
494866
|
+
errorMessage2.split(`
|
|
494194
494867
|
`).slice(1).filter((line) => line.trim().length > 0).map((line, idx) => /* @__PURE__ */ jsx_dev_runtime61.jsxDEV(Text2, {
|
|
494195
494868
|
dimColor: true,
|
|
494196
494869
|
children: line
|
|
@@ -494435,7 +495108,7 @@ var init_McpConnectFlow = __esm(async () => {
|
|
|
494435
495108
|
const authorizationUrl = event2.url;
|
|
494436
495109
|
setAuthUrl(authorizationUrl);
|
|
494437
495110
|
setConnectionStatus("Opening browser for authorization...");
|
|
494438
|
-
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default:
|
|
495111
|
+
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(authorizationUrl)).catch(() => {});
|
|
494439
495112
|
}
|
|
494440
495113
|
break;
|
|
494441
495114
|
case "waiting_for_auth" /* WAITING_FOR_AUTH */:
|
|
@@ -496859,13 +497532,16 @@ html.dark .warning-badge { background: hsl(42, 30%, 18%); color: hsl(42, 80%, 70
|
|
|
496859
497532
|
var agentIdEl = document.getElementById('agent-id');
|
|
496860
497533
|
agentIdEl.textContent = agentId;
|
|
496861
497534
|
if (agentId) {
|
|
496862
|
-
var
|
|
496863
|
-
|
|
496864
|
-
|
|
497535
|
+
var chatBase;
|
|
497536
|
+
var normalizedServerUrl = serverUrl.replace(/\\/+$/, '');
|
|
497537
|
+
if (normalizedServerUrl === 'https://api.letta.com' || normalizedServerUrl === 'https://api.letta.com/v1') {
|
|
497538
|
+
chatBase = 'https://chat.letta.com';
|
|
497539
|
+
} else if (normalizedServerUrl) {
|
|
497540
|
+
chatBase = normalizedServerUrl.replace(/\\/v1$/, '');
|
|
496865
497541
|
} else {
|
|
496866
|
-
|
|
497542
|
+
chatBase = 'https://chat.letta.com';
|
|
496867
497543
|
}
|
|
496868
|
-
agentIdEl.href =
|
|
497544
|
+
agentIdEl.href = chatBase + '/chat/' + encodeURIComponent(agentId);
|
|
496869
497545
|
agentIdEl.target = '_blank';
|
|
496870
497546
|
}
|
|
496871
497547
|
document.getElementById('generated-at').textContent = 'Generated ' + new Date(DATA.generatedAt).toLocaleString();
|
|
@@ -500626,7 +501302,7 @@ var init_PersonalitySelector = __esm(async () => {
|
|
|
500626
501302
|
});
|
|
500627
501303
|
|
|
500628
501304
|
// src/utils/aws-credentials.ts
|
|
500629
|
-
import { readFile as
|
|
501305
|
+
import { readFile as readFile25 } from "node:fs/promises";
|
|
500630
501306
|
import { homedir as homedir45 } from "node:os";
|
|
500631
501307
|
import { join as join77 } from "node:path";
|
|
500632
501308
|
async function parseAwsCredentials() {
|
|
@@ -500634,11 +501310,11 @@ async function parseAwsCredentials() {
|
|
|
500634
501310
|
const configPath = join77(homedir45(), ".aws", "config");
|
|
500635
501311
|
const profiles = new Map;
|
|
500636
501312
|
try {
|
|
500637
|
-
const content = await
|
|
501313
|
+
const content = await readFile25(credentialsPath, "utf-8");
|
|
500638
501314
|
parseIniFile(content, profiles, false);
|
|
500639
501315
|
} catch {}
|
|
500640
501316
|
try {
|
|
500641
|
-
const content = await
|
|
501317
|
+
const content = await readFile25(configPath, "utf-8");
|
|
500642
501318
|
parseIniFile(content, profiles, true);
|
|
500643
501319
|
} catch {}
|
|
500644
501320
|
return Array.from(profiles.values());
|
|
@@ -505910,7 +506586,7 @@ function formatUsageStats({
|
|
|
505910
506586
|
const monthlyCredits = Math.round(balance.monthly_credit_balance);
|
|
505911
506587
|
const purchasedCredits = Math.round(balance.purchased_credit_balance);
|
|
505912
506588
|
const toDollars = (credits) => (credits / 1000).toFixed(2);
|
|
505913
|
-
outputLines.push(`Plan: [${balance.billing_tier}]`,
|
|
506589
|
+
outputLines.push(`Plan: [${balance.billing_tier}]`, buildChatWebUrl("/preferences/usage"), "", `Available credits: ◎${formatNumber2(totalCredits)} ($${toDollars(totalCredits)})`, `Monthly credits: ◎${formatNumber2(monthlyCredits)} ($${toDollars(monthlyCredits)})`, `Purchased credits: ◎${formatNumber2(purchasedCredits)} ($${toDollars(purchasedCredits)})`);
|
|
505914
506590
|
}
|
|
505915
506591
|
return outputLines.join(`
|
|
505916
506592
|
`);
|
|
@@ -516961,13 +517637,13 @@ var init_cleanLastNewline = () => {};
|
|
|
516961
517637
|
function processLine(node, line, state) {
|
|
516962
517638
|
const lineInfo = typeof state.lineInfo === "function" ? state.lineInfo(line) : state.lineInfo[line - 1];
|
|
516963
517639
|
if (lineInfo == null) {
|
|
516964
|
-
const
|
|
516965
|
-
console.error(
|
|
517640
|
+
const errorMessage2 = `processLine: line ${line}, contains no state.lineInfo`;
|
|
517641
|
+
console.error(errorMessage2, {
|
|
516966
517642
|
node,
|
|
516967
517643
|
line,
|
|
516968
517644
|
state
|
|
516969
517645
|
});
|
|
516970
|
-
throw new Error(
|
|
517646
|
+
throw new Error(errorMessage2);
|
|
516971
517647
|
}
|
|
516972
517648
|
node.tagName = "div";
|
|
516973
517649
|
node.properties["data-line"] = lineInfo.lineNumber;
|
|
@@ -520439,9 +521115,9 @@ var instanceId = -1, DiffHunksRenderer = class {
|
|
|
520439
521115
|
let deletionLineContent = deletionLine != null ? deletionLines[deletionLine.lineIndex] : undefined;
|
|
520440
521116
|
let additionLineContent = additionLine != null ? additionLines[additionLine.lineIndex] : undefined;
|
|
520441
521117
|
if (deletionLineContent == null && additionLineContent == null) {
|
|
520442
|
-
const
|
|
520443
|
-
console.error(
|
|
520444
|
-
throw new Error(
|
|
521118
|
+
const errorMessage2 = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
|
|
521119
|
+
console.error(errorMessage2, { file: fileDiff.name });
|
|
521120
|
+
throw new Error(errorMessage2);
|
|
520445
521121
|
}
|
|
520446
521122
|
const lineType = type3 === "change" ? additionLine != null ? "change-addition" : "change-deletion" : type3;
|
|
520447
521123
|
const lineDecoration = this.getUnifiedLineDecoration({
|
|
@@ -520483,9 +521159,9 @@ var instanceId = -1, DiffHunksRenderer = class {
|
|
|
520483
521159
|
lineIndex: additionLine?.lineIndex
|
|
520484
521160
|
});
|
|
520485
521161
|
if (deletionLineContent == null && additionLineContent == null) {
|
|
520486
|
-
const
|
|
520487
|
-
console.error(
|
|
520488
|
-
throw new Error(
|
|
521162
|
+
const errorMessage2 = "DiffHunksRenderer.processDiffResult: deletionLine and additionLine are null, something is wrong";
|
|
521163
|
+
console.error(errorMessage2, { file: fileDiff.name });
|
|
521164
|
+
throw new Error(errorMessage2);
|
|
520489
521165
|
}
|
|
520490
521166
|
const missingSide = (() => {
|
|
520491
521167
|
if (type3 === "change") {
|
|
@@ -528012,7 +528688,7 @@ The deployment target for this project is CITATION-DOGFOOD-OK.
|
|
|
528012
528688
|
|
|
528013
528689
|
// src/mods/learning-harness.ts
|
|
528014
528690
|
import { spawn as spawn13 } from "node:child_process";
|
|
528015
|
-
import { access as access3, copyFile as copyFile2, mkdir as mkdir19, readFile as
|
|
528691
|
+
import { access as access3, copyFile as copyFile2, mkdir as mkdir19, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
|
|
528016
528692
|
import path42 from "node:path";
|
|
528017
528693
|
function slugify2(value) {
|
|
528018
528694
|
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -528260,14 +528936,14 @@ async function existingPath(filePath) {
|
|
|
528260
528936
|
return await fileExists(filePath) ? filePath : undefined;
|
|
528261
528937
|
}
|
|
528262
528938
|
async function writeJsonArtifact(filePath, value) {
|
|
528263
|
-
await
|
|
528939
|
+
await writeFile20(filePath, `${JSON.stringify(value, null, 2)}
|
|
528264
528940
|
`, "utf8");
|
|
528265
528941
|
}
|
|
528266
528942
|
async function writeCommandArtifacts(prefix, command, args, result) {
|
|
528267
|
-
await
|
|
528943
|
+
await writeFile20(`${prefix}.command.txt`, `${renderCommand(command, args)}
|
|
528268
528944
|
`, "utf8");
|
|
528269
|
-
await
|
|
528270
|
-
await
|
|
528945
|
+
await writeFile20(`${prefix}.stdout`, result.stdout, "utf8");
|
|
528946
|
+
await writeFile20(`${prefix}.stderr`, result.stderr, "utf8");
|
|
528271
528947
|
await writeJsonArtifact(`${prefix}.result.json`, result);
|
|
528272
528948
|
}
|
|
528273
528949
|
async function prepareMemoryFiles(memoryDir, memoryFiles) {
|
|
@@ -528275,7 +528951,7 @@ async function prepareMemoryFiles(memoryDir, memoryFiles) {
|
|
|
528275
528951
|
for (const [relativePath, content] of Object.entries(memoryFiles ?? {})) {
|
|
528276
528952
|
const filePath = safeJoin(memoryDir, relativePath);
|
|
528277
528953
|
await mkdir19(path42.dirname(filePath), { recursive: true });
|
|
528278
|
-
await
|
|
528954
|
+
await writeFile20(filePath, content, "utf8");
|
|
528279
528955
|
}
|
|
528280
528956
|
}
|
|
528281
528957
|
function renderEvaluationPrompt(prompt, memoryDir) {
|
|
@@ -528938,7 +529614,7 @@ function renderProposerGuide(params) {
|
|
|
528938
529614
|
`;
|
|
528939
529615
|
}
|
|
528940
529616
|
async function writeHistoryArtifacts(params) {
|
|
528941
|
-
await
|
|
529617
|
+
await writeFile20(params.historyPath, renderHistoryIndex({
|
|
528942
529618
|
attempts: params.attempts,
|
|
528943
529619
|
historyManifestPath: params.historyManifestPath,
|
|
528944
529620
|
proposerGuidePath: params.proposerGuidePath,
|
|
@@ -528946,7 +529622,7 @@ async function writeHistoryArtifacts(params) {
|
|
|
528946
529622
|
spec: params.spec
|
|
528947
529623
|
}), "utf8");
|
|
528948
529624
|
await writeJsonArtifact(params.historyManifestPath, buildHistoryManifest(params));
|
|
528949
|
-
await
|
|
529625
|
+
await writeFile20(params.proposerGuidePath, renderProposerGuide(params), "utf8");
|
|
528950
529626
|
}
|
|
528951
529627
|
async function defaultCommandRunner(command, args, options3) {
|
|
528952
529628
|
const startedAt = Date.now();
|
|
@@ -529037,7 +529713,7 @@ function createScenarioSuiteEvaluator(params) {
|
|
|
529037
529713
|
outputFormat
|
|
529038
529714
|
})
|
|
529039
529715
|
];
|
|
529040
|
-
await
|
|
529716
|
+
await writeFile20(hasConfiguredScenarios ? path42.join(scenarioDir, "prompt.md") : path42.join(context4.runDir, "eval-prompt.md"), evalPrompt, "utf8");
|
|
529041
529717
|
const scenarioEvalResult = await context4.runner(context4.cliCommand, evalArgs, {
|
|
529042
529718
|
cwd: context4.repoRoot,
|
|
529043
529719
|
env: {
|
|
@@ -529229,7 +529905,7 @@ async function runModLearningCandidate(params) {
|
|
|
529229
529905
|
outputFormat: "json"
|
|
529230
529906
|
})
|
|
529231
529907
|
];
|
|
529232
|
-
await
|
|
529908
|
+
await writeFile20(path42.join(runDir, "generation-prompt.md"), generationPrompt, "utf8");
|
|
529233
529909
|
generationResult = await params.runner(params.cliCommand, generationArgs, {
|
|
529234
529910
|
cwd: repoRoot,
|
|
529235
529911
|
env: {
|
|
@@ -529308,7 +529984,7 @@ async function runModLearningCandidate(params) {
|
|
|
529308
529984
|
spec: options3.spec
|
|
529309
529985
|
};
|
|
529310
529986
|
await writeJsonArtifact(path42.join(runDir, "report.json"), report);
|
|
529311
|
-
await
|
|
529987
|
+
await writeFile20(reportPath, renderMarkdownReport(report), "utf8");
|
|
529312
529988
|
await writeCandidateManifest(report);
|
|
529313
529989
|
emitProgress("done", params.candidateCount > 1 ? `Optimization iteration ${params.candidateIndex}/${params.candidateCount} complete` : "mod optimization complete", {
|
|
529314
529990
|
attempts: [...params.previousAttempts, summarizeAttempt(report)],
|
|
@@ -529486,7 +530162,7 @@ async function runModLearning(options3) {
|
|
|
529486
530162
|
spec: normalizedOptions.spec
|
|
529487
530163
|
});
|
|
529488
530164
|
await writeJsonArtifact(path42.join(runDir, "report.json"), report);
|
|
529489
|
-
await
|
|
530165
|
+
await writeFile20(reportPath, renderMarkdownReport(report), "utf8");
|
|
529490
530166
|
normalizedOptions.onProgress?.({
|
|
529491
530167
|
candidateCount,
|
|
529492
530168
|
candidateIndex: selectedCandidateIndex,
|
|
@@ -529504,7 +530180,7 @@ async function runModLearning(options3) {
|
|
|
529504
530180
|
return report;
|
|
529505
530181
|
}
|
|
529506
530182
|
async function readModLearningEnv(envPath) {
|
|
529507
|
-
return JSON.parse(await
|
|
530183
|
+
return JSON.parse(await readFile26(envPath, "utf8"));
|
|
529508
530184
|
}
|
|
529509
530185
|
var init_learning_harness = __esm(async () => {
|
|
529510
530186
|
await init_mod_engine();
|
|
@@ -530589,19 +531265,12 @@ Messages will be executed locally using your letta-code environment.`, true);
|
|
|
530589
531265
|
const deviceName = hostname8();
|
|
530590
531266
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Registering listener "${connectionName}"...
|
|
530591
531267
|
Device: ${deviceName} (${deviceId.slice(0, 8)}...)`, true, "running");
|
|
530592
|
-
const
|
|
530593
|
-
|
|
530594
|
-
|
|
530595
|
-
|
|
530596
|
-
|
|
530597
|
-
}
|
|
530598
|
-
const { connectionId, wsUrl, supportsSplitStatusChannels } = await registerWithCloudRetry({
|
|
530599
|
-
serverUrl,
|
|
530600
|
-
apiKey,
|
|
530601
|
-
deviceId,
|
|
530602
|
-
connectionName,
|
|
530603
|
-
listenerInstanceId: deriveListenerInstanceId("listen", connectionName)
|
|
530604
|
-
}, {
|
|
531268
|
+
const resolveRegisterOptions = () => resolveListenerRegistrationOptions(deviceId, connectionName, {
|
|
531269
|
+
allowInteractiveOAuth: false,
|
|
531270
|
+
surface: "listen"
|
|
531271
|
+
});
|
|
531272
|
+
const registerOptions = await resolveRegisterOptions();
|
|
531273
|
+
const { connectionId, wsUrl, supportsSplitStatusChannels } = await registerWithCloudRetry(registerOptions, {
|
|
530605
531274
|
onRetry: (attempt, delayMs, error54) => {
|
|
530606
531275
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Registering listener "${connectionName}"...
|
|
530607
531276
|
Retry ${attempt} in ${Math.round(delayMs / 1000)}s: ${error54.message}`, true, "running");
|
|
@@ -530655,13 +531324,8 @@ Awaiting instructions${urlText}`, true, "finished");
|
|
|
530655
531324
|
onNeedsReregister: async () => {
|
|
530656
531325
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment expired, re-registering "${connectionName}"...`, true, "running");
|
|
530657
531326
|
try {
|
|
530658
|
-
const
|
|
530659
|
-
|
|
530660
|
-
apiKey,
|
|
530661
|
-
deviceId,
|
|
530662
|
-
connectionName,
|
|
530663
|
-
listenerInstanceId: deriveListenerInstanceId("listen", connectionName)
|
|
530664
|
-
}, {
|
|
531327
|
+
const nextRegisterOptions = await resolveRegisterOptions();
|
|
531328
|
+
const reregisterResult = await registerWithCloudRetry(nextRegisterOptions, {
|
|
530665
531329
|
maxDurationMs: Infinity,
|
|
530666
531330
|
onRetry: (attempt, delayMs, error54) => {
|
|
530667
531331
|
updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Re-registering "${connectionName}"...
|
|
@@ -530694,10 +531358,10 @@ Retry ${attempt} in ${Math.round(delayMs / 1000)}s: ${error54.message}`, true, "
|
|
|
530694
531358
|
}
|
|
530695
531359
|
var activeCommandId3 = null;
|
|
530696
531360
|
var init_listen = __esm(() => {
|
|
530697
|
-
init_client2();
|
|
530698
531361
|
init_app_urls();
|
|
530699
531362
|
init_settings_manager();
|
|
530700
531363
|
init_listen_register();
|
|
531364
|
+
init_auth();
|
|
530701
531365
|
});
|
|
530702
531366
|
|
|
530703
531367
|
// src/cli/app/submit-connection-commands.ts
|
|
@@ -531896,7 +532560,7 @@ var exports_export = {};
|
|
|
531896
532560
|
__export(exports_export, {
|
|
531897
532561
|
packageSkills: () => packageSkills
|
|
531898
532562
|
});
|
|
531899
|
-
import { readdir as readdir17, readFile as
|
|
532563
|
+
import { readdir as readdir17, readFile as readFile27 } from "node:fs/promises";
|
|
531900
532564
|
import { relative as relative16, resolve as resolve40 } from "node:path";
|
|
531901
532565
|
async function packageSkills(agentId, skillsDir) {
|
|
531902
532566
|
const skills = [];
|
|
@@ -531917,7 +532581,7 @@ async function packageSkills(agentId, skillsDir) {
|
|
|
531917
532581
|
const skillDir = resolve40(baseDir, entry.name);
|
|
531918
532582
|
const skillMdPath = resolve40(skillDir, "SKILL.md");
|
|
531919
532583
|
try {
|
|
531920
|
-
await
|
|
532584
|
+
await readFile27(skillMdPath, "utf-8");
|
|
531921
532585
|
} catch {
|
|
531922
532586
|
console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
|
|
531923
532587
|
continue;
|
|
@@ -531949,7 +532613,7 @@ async function readSkillFiles(skillDir) {
|
|
|
531949
532613
|
if (entry.isDirectory()) {
|
|
531950
532614
|
await walk(fullPath);
|
|
531951
532615
|
} else {
|
|
531952
|
-
const content = await
|
|
532616
|
+
const content = await readFile27(fullPath, "utf-8");
|
|
531953
532617
|
const relativePath = relative16(skillDir, fullPath).replace(/\\/g, "/");
|
|
531954
532618
|
files[relativePath] = content;
|
|
531955
532619
|
}
|
|
@@ -532768,7 +533432,7 @@ ${SYSTEM_REMINDER_CLOSE}`),
|
|
|
532768
533432
|
const adeUrl = buildChatUrl(agentId, {
|
|
532769
533433
|
conversationId: conversationIdRef.current
|
|
532770
533434
|
});
|
|
532771
|
-
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default:
|
|
533435
|
+
Promise.resolve().then(() => (init_open(), exports_open)).then(({ default: open5 }) => open5(adeUrl, { wait: false })).catch(() => {});
|
|
532772
533436
|
cmd.finish(`Opening ADE...
|
|
532773
533437
|
→ ${adeUrl}`, true);
|
|
532774
533438
|
return { submitted: true };
|
|
@@ -538727,7 +539391,8 @@ async function ensureDefaultAgents2(backend4, options3) {
|
|
|
538727
539391
|
const createOptions = personality === "tutorial" ? {
|
|
538728
539392
|
...await buildCreateAgentOptionsForPersonality2({
|
|
538729
539393
|
personalityId: "tutorial",
|
|
538730
|
-
model
|
|
539394
|
+
model,
|
|
539395
|
+
tags: [ONBOARDING_ORIGIN_TAG]
|
|
538731
539396
|
}),
|
|
538732
539397
|
memoryPromptMode
|
|
538733
539398
|
} : {
|
|
@@ -538975,7 +539640,7 @@ __export(exports_import2, {
|
|
|
538975
539640
|
extractSkillsFromAf: () => extractSkillsFromAf2
|
|
538976
539641
|
});
|
|
538977
539642
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
538978
|
-
import { access as access4, chmod as chmod3, mkdir as mkdir20, readFile as
|
|
539643
|
+
import { access as access4, chmod as chmod3, mkdir as mkdir20, readFile as readFile28, writeFile as writeFile21 } from "node:fs/promises";
|
|
538979
539644
|
import { dirname as dirname38, isAbsolute as isAbsolute27, relative as relative17, resolve as resolve41, sep as sep8, win32 as win326 } from "node:path";
|
|
538980
539645
|
function validateImportedSkillName2(name) {
|
|
538981
539646
|
const trimmedName = name.trim();
|
|
@@ -539076,7 +539741,7 @@ async function importAgentFromFile2(options3) {
|
|
|
539076
539741
|
}
|
|
539077
539742
|
async function extractSkillsFromAf2(afPath, destDir) {
|
|
539078
539743
|
const extracted = [];
|
|
539079
|
-
const content = await
|
|
539744
|
+
const content = await readFile28(afPath, "utf-8");
|
|
539080
539745
|
const afData = JSON.parse(content);
|
|
539081
539746
|
if (!afData.skills || !Array.isArray(afData.skills)) {
|
|
539082
539747
|
return [];
|
|
@@ -539105,7 +539770,7 @@ async function writeSkillFiles2(skillDir, files) {
|
|
|
539105
539770
|
async function writeSkillFile2(skillDir, filePath, content) {
|
|
539106
539771
|
const fullPath = resolveImportedSkillFilePath2(skillDir, filePath);
|
|
539107
539772
|
await mkdir20(dirname38(fullPath), { recursive: true });
|
|
539108
|
-
await
|
|
539773
|
+
await writeFile21(fullPath, content, "utf-8");
|
|
539109
539774
|
const isScript = filePath.startsWith("scripts/") || content.trimStart().startsWith("#!");
|
|
539110
539775
|
if (isScript) {
|
|
539111
539776
|
try {
|
|
@@ -539158,7 +539823,7 @@ function parseRegistryHandle2(handle2) {
|
|
|
539158
539823
|
async function importAgentFromRegistry2(options3) {
|
|
539159
539824
|
const { tmpdir: tmpdir12 } = await import("node:os");
|
|
539160
539825
|
const { join: join84 } = await import("node:path");
|
|
539161
|
-
const { writeFile:
|
|
539826
|
+
const { writeFile: writeFile22, unlink: unlink5 } = await import("node:fs/promises");
|
|
539162
539827
|
const { author, name } = parseRegistryHandle2(options3.handle);
|
|
539163
539828
|
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
|
|
539164
539829
|
const response = await fetch(rawUrl);
|
|
@@ -539170,7 +539835,7 @@ async function importAgentFromRegistry2(options3) {
|
|
|
539170
539835
|
}
|
|
539171
539836
|
const afContent = await response.text();
|
|
539172
539837
|
const tempPath = join84(tmpdir12(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
539173
|
-
await
|
|
539838
|
+
await writeFile22(tempPath, afContent, "utf-8");
|
|
539174
539839
|
try {
|
|
539175
539840
|
const result = await importAgentFromFile2({
|
|
539176
539841
|
filePath: tempPath,
|
|
@@ -542506,14 +543171,18 @@ function resolveImportFlagAlias(options3) {
|
|
|
542506
543171
|
return options3.importFlagValue ?? options3.fromAfFlagValue;
|
|
542507
543172
|
}
|
|
542508
543173
|
|
|
543174
|
+
// src/cli/helpers/app-urls.ts
|
|
543175
|
+
var CHAT_BASE2 = "https://chat.letta.com";
|
|
543176
|
+
var LETTA_CHAT_API_KEYS_URL2 = `${CHAT_BASE2}/preferences/api-keys`;
|
|
543177
|
+
|
|
542509
543178
|
// src/cli/helpers/error-formatter.ts
|
|
542510
543179
|
init_error();
|
|
542511
543180
|
init_conversation_busy_error();
|
|
542512
543181
|
init_app_urls();
|
|
542513
543182
|
init_error_context();
|
|
542514
543183
|
init_zai_errors();
|
|
542515
|
-
var LETTA_USAGE_URL2 =
|
|
542516
|
-
var LETTA_AGENTS_URL2 =
|
|
543184
|
+
var LETTA_USAGE_URL2 = buildChatWebUrl("/preferences/usage");
|
|
543185
|
+
var LETTA_AGENTS_URL2 = buildPlatformUrl("/projects/default-project/agents");
|
|
542517
543186
|
function formatConversationBusyErrorForDisplay2(errorText, runId, options3) {
|
|
542518
543187
|
if (!isConversationBusyErrorText(errorText))
|
|
542519
543188
|
return null;
|
|
@@ -544256,7 +544925,7 @@ import WebSocket7, { WebSocketServer } from "ws";
|
|
|
544256
544925
|
|
|
544257
544926
|
// src/websocket/app-server-auth.ts
|
|
544258
544927
|
import { createHash as createHash5, createHmac, timingSafeEqual } from "node:crypto";
|
|
544259
|
-
import { readFile as
|
|
544928
|
+
import { readFile as readFile12 } from "node:fs/promises";
|
|
544260
544929
|
import { isIP as isIP2 } from "node:net";
|
|
544261
544930
|
import { isAbsolute as isAbsolute22 } from "node:path";
|
|
544262
544931
|
var INVALID_AUTHORIZATION_HEADER_MESSAGE = "invalid authorization header";
|
|
@@ -544500,7 +545169,7 @@ function bearerTokenFromHeaders(headers) {
|
|
|
544500
545169
|
async function readTrimmedSecret(path31) {
|
|
544501
545170
|
let raw2;
|
|
544502
545171
|
try {
|
|
544503
|
-
raw2 = await
|
|
545172
|
+
raw2 = await readFile12(path31, "utf8");
|
|
544504
545173
|
} catch (error54) {
|
|
544505
545174
|
const message = error54 instanceof Error ? error54.message : String(error54);
|
|
544506
545175
|
throw new Error(`failed to read websocket auth secret ${path31}: ${message}`);
|
|
@@ -546350,10 +547019,10 @@ import { parseArgs as parseArgs7 } from "node:util";
|
|
|
546350
547019
|
|
|
546351
547020
|
// src/cli/subcommands/dream-sources/index.ts
|
|
546352
547021
|
init_reflection_transcript();
|
|
546353
|
-
import { createHash as
|
|
547022
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
546354
547023
|
|
|
546355
547024
|
// src/cli/subcommands/dream-sources/openhands.ts
|
|
546356
|
-
import { readdir as readdir12, readFile as
|
|
547025
|
+
import { readdir as readdir12, readFile as readFile18, stat as stat14 } from "node:fs/promises";
|
|
546357
547026
|
import { join as join52 } from "node:path";
|
|
546358
547027
|
var RESULT_TEXT_TRUNCATE_LIMIT = 4000;
|
|
546359
547028
|
function joinTextContent(content) {
|
|
@@ -546480,7 +547149,7 @@ async function readOpenHandsEventDir(dir) {
|
|
|
546480
547149
|
}
|
|
546481
547150
|
const events = [];
|
|
546482
547151
|
for (const name of fileNames) {
|
|
546483
|
-
const raw2 = await
|
|
547152
|
+
const raw2 = await readFile18(join52(eventsDir, name), "utf-8");
|
|
546484
547153
|
const event2 = safeJsonParseOr(raw2, null);
|
|
546485
547154
|
if (event2 && typeof event2 === "object") {
|
|
546486
547155
|
events.push(event2);
|
|
@@ -546495,17 +547164,17 @@ var openHandsAdapter = {
|
|
|
546495
547164
|
if (info?.isDirectory()) {
|
|
546496
547165
|
return convertOpenHandsEvents(await readOpenHandsEventDir(locator));
|
|
546497
547166
|
}
|
|
546498
|
-
const raw2 = await
|
|
547167
|
+
const raw2 = await readFile18(locator, "utf-8");
|
|
546499
547168
|
return convertOpenHandsEvents(parseOpenHandsEventsFile(raw2, locator));
|
|
546500
547169
|
}
|
|
546501
547170
|
};
|
|
546502
547171
|
|
|
546503
547172
|
// src/cli/subcommands/dream-sources/transcript.ts
|
|
546504
|
-
import { readFile as
|
|
547173
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
546505
547174
|
var transcriptAdapter = {
|
|
546506
547175
|
type: "transcript",
|
|
546507
547176
|
async convert(locator) {
|
|
546508
|
-
const raw2 = await
|
|
547177
|
+
const raw2 = await readFile19(locator, "utf-8");
|
|
546509
547178
|
const entries = [];
|
|
546510
547179
|
for (const line of raw2.split(`
|
|
546511
547180
|
`)) {
|
|
@@ -546543,7 +547212,7 @@ function parseFromSource(spec) {
|
|
|
546543
547212
|
return { adapter, locator };
|
|
546544
547213
|
}
|
|
546545
547214
|
function conversationIdForSource(parsed) {
|
|
546546
|
-
const hash4 =
|
|
547215
|
+
const hash4 = createHash7("sha1").update(`${parsed.adapter.type}:${parsed.locator}`).digest("hex").slice(0, 12);
|
|
546547
547216
|
return `from-${parsed.adapter.type}-${hash4}`;
|
|
546548
547217
|
}
|
|
546549
547218
|
async function stageFromSource(agentId, parsed) {
|
|
@@ -546557,7 +547226,7 @@ async function stageFromSource(agentId, parsed) {
|
|
|
546557
547226
|
init_memory_filesystem2();
|
|
546558
547227
|
init_memory_git();
|
|
546559
547228
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
546560
|
-
import { mkdir as mkdir13, readFile as
|
|
547229
|
+
import { mkdir as mkdir13, readFile as readFile20, rm as rm6, writeFile as writeFile14 } from "node:fs/promises";
|
|
546561
547230
|
import { basename as basename25, dirname as dirname27, join as join53 } from "node:path";
|
|
546562
547231
|
function resolveDreamTarget(spec) {
|
|
546563
547232
|
const fileName = basename25(spec);
|
|
@@ -546633,7 +547302,7 @@ function buildTargetInstruction(target2) {
|
|
|
546633
547302
|
}
|
|
546634
547303
|
async function readExistingTarget(target2) {
|
|
546635
547304
|
try {
|
|
546636
|
-
return await
|
|
547305
|
+
return await readFile20(target2.path, "utf-8");
|
|
546637
547306
|
} catch {
|
|
546638
547307
|
return null;
|
|
546639
547308
|
}
|
|
@@ -546661,7 +547330,7 @@ async function syncTargetIntoMemory(agentId, target2, content) {
|
|
|
546661
547330
|
}
|
|
546662
547331
|
const absPath = join53(memoryDir, relPath);
|
|
546663
547332
|
await mkdir13(dirname27(absPath), { recursive: true });
|
|
546664
|
-
await
|
|
547333
|
+
await writeFile14(absPath, addManagedFrontmatter(content, target2.kind), "utf-8");
|
|
546665
547334
|
try {
|
|
546666
547335
|
const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
|
|
546667
547336
|
const syncMode = getBackend2().capabilities.localMemfs ? "local" : "remote";
|
|
@@ -546678,7 +547347,7 @@ async function syncTargetIntoMemory(agentId, target2, content) {
|
|
|
546678
547347
|
});
|
|
546679
547348
|
return { synced: result.committed };
|
|
546680
547349
|
} catch (error54) {
|
|
546681
|
-
await
|
|
547350
|
+
await rm6(absPath, { force: true });
|
|
546682
547351
|
throw error54;
|
|
546683
547352
|
}
|
|
546684
547353
|
}
|
|
@@ -546694,7 +547363,7 @@ function readTargetFromMemory(agentId, target2) {
|
|
|
546694
547363
|
}
|
|
546695
547364
|
async function writeTarget(target2, content) {
|
|
546696
547365
|
await mkdir13(dirname27(target2.path), { recursive: true });
|
|
546697
|
-
await
|
|
547366
|
+
await writeFile14(target2.path, content, "utf-8");
|
|
546698
547367
|
}
|
|
546699
547368
|
|
|
546700
547369
|
// src/cli/subcommands/dream.ts
|
|
@@ -546721,6 +547390,11 @@ Options:
|
|
|
546721
547390
|
--timeout <seconds> Fail if the reflection pass has not completed
|
|
546722
547391
|
in this many seconds (default: 1500)
|
|
546723
547392
|
-i, --instruction <text> Additional instruction for the reflection pass
|
|
547393
|
+
--prompt <text> Advanced: replace the reflection task prompt
|
|
547394
|
+
entirely (you supply the transcript/memory
|
|
547395
|
+
mechanics via $TRANSCRIPT_PATH and $MEMORY_DIR)
|
|
547396
|
+
--system <text> Advanced: replace the reflection subagent's
|
|
547397
|
+
system prompt
|
|
546724
547398
|
--json Emit machine-readable JSON output
|
|
546725
547399
|
-h, --help Show this help
|
|
546726
547400
|
|
|
@@ -546739,6 +547413,8 @@ var DREAM_OPTIONS = {
|
|
|
546739
547413
|
effort: { type: "string" },
|
|
546740
547414
|
timeout: { type: "string" },
|
|
546741
547415
|
instruction: { type: "string", short: "i" },
|
|
547416
|
+
prompt: { type: "string" },
|
|
547417
|
+
system: { type: "string" },
|
|
546742
547418
|
json: { type: "boolean" }
|
|
546743
547419
|
};
|
|
546744
547420
|
var DEFAULT_TIMEOUT_SECONDS = 1500;
|
|
@@ -546871,6 +547547,8 @@ ${targetInstruction}` : targetInstruction;
|
|
|
546871
547547
|
description: "Reflect on recent conversations",
|
|
546872
547548
|
model: parsed.values.model,
|
|
546873
547549
|
instruction,
|
|
547550
|
+
reflectionPromptOverride: parsed.values.prompt,
|
|
547551
|
+
reflectionSystemPromptOverride: parsed.values.system,
|
|
546874
547552
|
recompileByConversation: new Map,
|
|
546875
547553
|
recompileQueuedByConversation: new Set,
|
|
546876
547554
|
onCompletionMessage: (message, completionResult) => {
|
|
@@ -547125,7 +547803,6 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
|
|
|
547125
547803
|
}
|
|
547126
547804
|
|
|
547127
547805
|
// src/cli/subcommands/listen.tsx
|
|
547128
|
-
init_oauth();
|
|
547129
547806
|
init_paths();
|
|
547130
547807
|
init_restore_scope();
|
|
547131
547808
|
await __promiseAll([
|
|
@@ -547298,26 +547975,9 @@ class RemoteSessionLog {
|
|
|
547298
547975
|
|
|
547299
547976
|
// src/cli/subcommands/listen.tsx
|
|
547300
547977
|
init_listen_register();
|
|
547978
|
+
init_auth();
|
|
547301
547979
|
var jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
547302
|
-
var LISTENER_TOKEN_REFRESH_WINDOW_MS = 5 * 60 * 1000;
|
|
547303
547980
|
var activeListenerProcessAnchors = new Set;
|
|
547304
|
-
var defaultListenerOAuthDeps = {
|
|
547305
|
-
LETTA_CLOUD_API_URL,
|
|
547306
|
-
pollForToken,
|
|
547307
|
-
refreshAccessToken,
|
|
547308
|
-
requestDeviceCode
|
|
547309
|
-
};
|
|
547310
|
-
var listenerOAuthDepsOverride = null;
|
|
547311
|
-
function getListenerOAuthDeps() {
|
|
547312
|
-
return listenerOAuthDepsOverride ?? defaultListenerOAuthDeps;
|
|
547313
|
-
}
|
|
547314
|
-
|
|
547315
|
-
class MissingListenerApiKeyError extends Error {
|
|
547316
|
-
constructor() {
|
|
547317
|
-
super("LETTA_API_KEY not found");
|
|
547318
|
-
this.name = "MissingListenerApiKeyError";
|
|
547319
|
-
}
|
|
547320
|
-
}
|
|
547321
547981
|
function PromptEnvName(props) {
|
|
547322
547982
|
const [value, setValue] = import_react33.useState("");
|
|
547323
547983
|
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -547367,16 +548027,6 @@ async function flushListenerTelemetryEnd(exitReason) {
|
|
|
547367
548027
|
await telemetry.flush();
|
|
547368
548028
|
} catch {}
|
|
547369
548029
|
}
|
|
547370
|
-
function getListenerServerUrl(settings3) {
|
|
547371
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547372
|
-
return process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || oauthDeps.LETTA_CLOUD_API_URL;
|
|
547373
|
-
}
|
|
547374
|
-
function normalizeListenerBaseUrl(url2) {
|
|
547375
|
-
return url2.trim().replace(/\/+$/, "");
|
|
547376
|
-
}
|
|
547377
|
-
function isCloudListenerServerUrl(serverUrl) {
|
|
547378
|
-
return normalizeListenerBaseUrl(serverUrl) === normalizeListenerBaseUrl(getListenerOAuthDeps().LETTA_CLOUD_API_URL);
|
|
547379
|
-
}
|
|
547380
548030
|
async function resolveListenerStartupMode(channelNames) {
|
|
547381
548031
|
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
547382
548032
|
const serverUrl = getListenerServerUrl(settings3);
|
|
@@ -547404,84 +548054,6 @@ function getScopedChannelRestoreAgentScope() {
|
|
|
547404
548054
|
function resolveChannelRestoreAgentScope(scopedRestoreAgentScope) {
|
|
547405
548055
|
return scopedRestoreAgentScope ?? parseChannelRestoreAgentScope(process.env[RESTORE_CHANNEL_AGENT_SCOPE_ENV]) ?? (isLocalBackendEnvEnabled() ? "local" : "cloud");
|
|
547406
548056
|
}
|
|
547407
|
-
async function refreshListenerAccessToken(settings3, deviceId, connectionName) {
|
|
547408
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547409
|
-
const now = Date.now();
|
|
547410
|
-
console.log("Access token expired, refreshing...");
|
|
547411
|
-
const tokens = await oauthDeps.refreshAccessToken(settings3.refreshToken, deviceId, connectionName);
|
|
547412
|
-
settingsManager.updateSettings({
|
|
547413
|
-
env: { LETTA_API_KEY: tokens.access_token },
|
|
547414
|
-
tokenExpiresAt: now + tokens.expires_in * 1000,
|
|
547415
|
-
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {}
|
|
547416
|
-
});
|
|
547417
|
-
await settingsManager.flush();
|
|
547418
|
-
console.log("Token refreshed successfully.");
|
|
547419
|
-
return tokens.access_token;
|
|
547420
|
-
}
|
|
547421
|
-
async function runListenerOAuthLogin(deviceId, connectionName) {
|
|
547422
|
-
const oauthDeps = getListenerOAuthDeps();
|
|
547423
|
-
console.log(`No API key found. Starting OAuth login...
|
|
547424
|
-
`);
|
|
547425
|
-
const deviceData = await oauthDeps.requestDeviceCode();
|
|
547426
|
-
console.log(`To authenticate, visit: ${deviceData.verification_uri_complete}`);
|
|
547427
|
-
console.log(`Your code: ${deviceData.user_code}
|
|
547428
|
-
`);
|
|
547429
|
-
console.log(`Waiting for authorization...
|
|
547430
|
-
`);
|
|
547431
|
-
const tokens = await oauthDeps.pollForToken(deviceData.device_code, deviceData.interval, deviceData.expires_in, deviceId, connectionName);
|
|
547432
|
-
const now = Date.now();
|
|
547433
|
-
settingsManager.updateSettings({
|
|
547434
|
-
env: { LETTA_API_KEY: tokens.access_token },
|
|
547435
|
-
tokenExpiresAt: now + tokens.expires_in * 1000,
|
|
547436
|
-
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : {}
|
|
547437
|
-
});
|
|
547438
|
-
await settingsManager.flush();
|
|
547439
|
-
console.log(`Authenticated successfully.
|
|
547440
|
-
`);
|
|
547441
|
-
return tokens.access_token;
|
|
547442
|
-
}
|
|
547443
|
-
async function resolveListenerRegistrationOptions(deviceId, connectionName) {
|
|
547444
|
-
const settings3 = await settingsManager.getSettingsWithSecureTokens();
|
|
547445
|
-
const serverUrl = getListenerServerUrl(settings3);
|
|
547446
|
-
const envApiKey = process.env.LETTA_API_KEY;
|
|
547447
|
-
if (envApiKey) {
|
|
547448
|
-
return {
|
|
547449
|
-
serverUrl,
|
|
547450
|
-
apiKey: envApiKey,
|
|
547451
|
-
deviceId,
|
|
547452
|
-
connectionName,
|
|
547453
|
-
listenerInstanceId: deriveListenerInstanceId("server", connectionName)
|
|
547454
|
-
};
|
|
547455
|
-
}
|
|
547456
|
-
let apiKey = settings3.env?.LETTA_API_KEY;
|
|
547457
|
-
if (isCloudListenerServerUrl(serverUrl)) {
|
|
547458
|
-
const expiresAt = settings3.tokenExpiresAt;
|
|
547459
|
-
if (settings3.refreshToken && expiresAt) {
|
|
547460
|
-
const now = Date.now();
|
|
547461
|
-
if (!apiKey || now >= expiresAt - LISTENER_TOKEN_REFRESH_WINDOW_MS) {
|
|
547462
|
-
try {
|
|
547463
|
-
apiKey = await refreshListenerAccessToken(settings3, deviceId, connectionName);
|
|
547464
|
-
} catch (refreshErr) {
|
|
547465
|
-
console.warn("Token refresh failed:", refreshErr instanceof Error ? refreshErr.message : String(refreshErr));
|
|
547466
|
-
apiKey = undefined;
|
|
547467
|
-
}
|
|
547468
|
-
}
|
|
547469
|
-
}
|
|
547470
|
-
if (!apiKey) {
|
|
547471
|
-
apiKey = await runListenerOAuthLogin(deviceId, connectionName);
|
|
547472
|
-
}
|
|
547473
|
-
}
|
|
547474
|
-
if (!apiKey) {
|
|
547475
|
-
throw new MissingListenerApiKeyError;
|
|
547476
|
-
}
|
|
547477
|
-
return {
|
|
547478
|
-
serverUrl,
|
|
547479
|
-
apiKey,
|
|
547480
|
-
deviceId,
|
|
547481
|
-
connectionName,
|
|
547482
|
-
listenerInstanceId: deriveListenerInstanceId("server", connectionName)
|
|
547483
|
-
};
|
|
547484
|
-
}
|
|
547485
548057
|
var LISTEN_OPTIONS = {
|
|
547486
548058
|
"env-name": { type: "string" },
|
|
547487
548059
|
channels: { type: "string" },
|
|
@@ -548686,7 +549258,7 @@ async function runMemorySubcommand(argv) {
|
|
|
548686
549258
|
init_backend2();
|
|
548687
549259
|
init_message_search();
|
|
548688
549260
|
init_settings_manager();
|
|
548689
|
-
import { writeFile as
|
|
549261
|
+
import { writeFile as writeFile15 } from "node:fs/promises";
|
|
548690
549262
|
import { resolve as resolve31 } from "node:path";
|
|
548691
549263
|
import { parseArgs as parseArgs12 } from "node:util";
|
|
548692
549264
|
function printUsage9() {
|
|
@@ -549031,7 +549603,7 @@ async function runMessagesSubcommand(argv, deps = {}) {
|
|
|
549031
549603
|
`).trim();
|
|
549032
549604
|
if (outputPathRaw && typeof outputPathRaw === "string") {
|
|
549033
549605
|
const outputPath = resolve31(process.cwd(), outputPathRaw);
|
|
549034
|
-
await
|
|
549606
|
+
await writeFile15(outputPath, `${transcript}
|
|
549035
549607
|
`, "utf-8");
|
|
549036
549608
|
console.log(JSON.stringify({
|
|
549037
549609
|
conversation_id: conversationId,
|
|
@@ -551719,14 +552291,13 @@ class SettingsManager2 {
|
|
|
551719
552291
|
}
|
|
551720
552292
|
async getSettingsWithSecureTokens() {
|
|
551721
552293
|
const baseSettings = this.getSettings();
|
|
551722
|
-
|
|
552294
|
+
const secureTokens = { ...this.secureTokensCache };
|
|
551723
552295
|
if (!getRuntimeContext()) {
|
|
551724
552296
|
const secretsAvailable2 = await this.isKeychainAvailable();
|
|
551725
552297
|
if (secretsAvailable2) {
|
|
551726
|
-
|
|
551727
|
-
|
|
551728
|
-
|
|
551729
|
-
};
|
|
552298
|
+
const storedTokens = await this.getSecureTokens();
|
|
552299
|
+
secureTokens.apiKey = storedTokens.apiKey ?? secureTokens.apiKey;
|
|
552300
|
+
secureTokens.refreshToken = storedTokens.refreshToken ?? secureTokens.refreshToken;
|
|
551730
552301
|
}
|
|
551731
552302
|
}
|
|
551732
552303
|
const fallbackRefreshToken = !secureTokens.refreshToken && baseSettings.refreshToken ? baseSettings.refreshToken : secureTokens.refreshToken;
|
|
@@ -553786,7 +554357,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
553786
554357
|
if (isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !process.env.LETTA_API_KEY) {
|
|
553787
554358
|
console.error("Missing LETTA_API_KEY");
|
|
553788
554359
|
console.error("Headless mode requires an API key set via the LETTA_API_KEY environment variable.");
|
|
553789
|
-
console.error(
|
|
554360
|
+
console.error(`Get an API key at ${LETTA_CHAT_API_KEYS_URL2}`);
|
|
553790
554361
|
process.exit(1);
|
|
553791
554362
|
}
|
|
553792
554363
|
if (!isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !settings3.refreshToken && !apiKey) {
|
|
@@ -554793,4 +555364,4 @@ Error during initialization: ${message}`);
|
|
|
554793
555364
|
}
|
|
554794
555365
|
main2();
|
|
554795
555366
|
|
|
554796
|
-
//# debugId=
|
|
555367
|
+
//# debugId=8DBFF6903CD7B1D064756E2164756E21
|