@letta-ai/letta-code 0.30.25 → 0.30.26
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 +1 -339
- package/dist/agent-presets.js.map +2 -2
- package/dist/channels-slack.js +319 -41
- package/dist/channels-slack.js.map +4 -3
- package/dist/channels-telegram.js +424 -0
- package/dist/channels-telegram.js.map +14 -0
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/modify.d.ts.map +1 -1
- package/dist/types/backend/dev/pi-model-factory.d.ts.map +1 -1
- package/dist/types/channels/slack/attachment-primitives.d.ts +69 -0
- package/dist/types/channels/slack/attachment-primitives.d.ts.map +1 -0
- package/dist/types/channels/telegram/debounce.d.ts +22 -0
- package/dist/types/channels/telegram/debounce.d.ts.map +1 -0
- package/dist/types/channels/telegram/ingress.d.ts +35 -0
- package/dist/types/channels/telegram/ingress.d.ts.map +1 -0
- package/dist/types/channels/telegram/message-action-contract.d.ts +16 -0
- package/dist/types/channels/telegram/message-action-contract.d.ts.map +1 -0
- package/dist/types/channels/telegram/message-shapes.d.ts +154 -0
- package/dist/types/channels/telegram/message-shapes.d.ts.map +1 -0
- package/dist/types/channels/telegram/outbound.d.ts +21 -0
- package/dist/types/channels/telegram/outbound.d.ts.map +1 -0
- package/dist/types/channels-slack.d.ts +2 -0
- package/dist/types/channels-slack.d.ts.map +1 -1
- package/dist/types/channels-telegram.d.ts +20 -0
- package/dist/types/channels-telegram.d.ts.map +1 -0
- package/dist/types/cli/helpers/stream-debug.d.ts +6 -0
- package/dist/types/cli/helpers/stream-debug.d.ts.map +1 -0
- package/dist/types/cli/helpers/stream-stall-reconciler.d.ts +16 -0
- package/dist/types/cli/helpers/stream-stall-reconciler.d.ts.map +1 -0
- package/dist/types/cli/helpers/stream.d.ts +1 -0
- package/dist/types/cli/helpers/stream.d.ts.map +1 -1
- package/dist/types/tools/impl/github-pull-request-tracker.d.ts +2 -0
- package/dist/types/tools/impl/github-pull-request-tracker.d.ts.map +1 -1
- package/dist/types/tools/impl/task.d.ts +2 -0
- package/dist/types/tools/impl/task.d.ts.map +1 -1
- package/dist/types/utils/openai-reasoning-effort.d.ts +6 -0
- package/dist/types/utils/openai-reasoning-effort.d.ts.map +1 -0
- package/dist/types/websocket/listener/constants.d.ts +0 -2
- package/dist/types/websocket/listener/constants.d.ts.map +1 -1
- package/letta.js +1547 -1770
- package/package.json +12 -1
- package/scripts/source-file-size-baseline.json +4 -5
- package/skills/teleporting-between-environments/SKILL.md +23 -9
package/letta.js
CHANGED
|
@@ -5509,7 +5509,7 @@ var package_default;
|
|
|
5509
5509
|
var init_package = __esm(() => {
|
|
5510
5510
|
package_default = {
|
|
5511
5511
|
name: "@letta-ai/letta-code",
|
|
5512
|
-
version: "0.30.
|
|
5512
|
+
version: "0.30.26",
|
|
5513
5513
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5514
5514
|
type: "module",
|
|
5515
5515
|
packageManager: "bun@1.3.10",
|
|
@@ -5543,6 +5543,8 @@ var init_package = __esm(() => {
|
|
|
5543
5543
|
"dist/gateway-core.js.map",
|
|
5544
5544
|
"dist/channels-slack.js",
|
|
5545
5545
|
"dist/channels-slack.js.map",
|
|
5546
|
+
"dist/channels-telegram.js",
|
|
5547
|
+
"dist/channels-telegram.js.map",
|
|
5546
5548
|
"dist/types",
|
|
5547
5549
|
"docs"
|
|
5548
5550
|
],
|
|
@@ -5606,6 +5608,12 @@ var init_package = __esm(() => {
|
|
|
5606
5608
|
browser: "./dist/channels-slack.js",
|
|
5607
5609
|
import: "./dist/channels-slack.js",
|
|
5608
5610
|
default: "./dist/channels-slack.js"
|
|
5611
|
+
},
|
|
5612
|
+
"./channels/telegram": {
|
|
5613
|
+
types: "./dist/types/channels-telegram.d.ts",
|
|
5614
|
+
browser: "./dist/channels-telegram.js",
|
|
5615
|
+
import: "./dist/channels-telegram.js",
|
|
5616
|
+
default: "./dist/channels-telegram.js"
|
|
5609
5617
|
}
|
|
5610
5618
|
},
|
|
5611
5619
|
repository: {
|
|
@@ -5721,6 +5729,9 @@ var init_package = __esm(() => {
|
|
|
5721
5729
|
"channels/slack": [
|
|
5722
5730
|
"./dist/types/channels-slack.d.ts"
|
|
5723
5731
|
],
|
|
5732
|
+
"channels/telegram": [
|
|
5733
|
+
"./dist/types/channels-telegram.d.ts"
|
|
5734
|
+
],
|
|
5724
5735
|
protocol: [
|
|
5725
5736
|
"./dist/types/types/protocol.d.ts"
|
|
5726
5737
|
]
|
|
@@ -140480,6 +140491,46 @@ var init_openai_codex_provider = __esm(() => {
|
|
|
140480
140491
|
CHATGPT_OAUTH_PROVIDER_NAME_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
140481
140492
|
});
|
|
140482
140493
|
|
|
140494
|
+
// src/utils/openai-reasoning-effort.ts
|
|
140495
|
+
function openaiModelNameFromHandle(modelHandleOrId) {
|
|
140496
|
+
if (!modelHandleOrId)
|
|
140497
|
+
return null;
|
|
140498
|
+
const trimmed = modelHandleOrId.trim().toLowerCase();
|
|
140499
|
+
if (!trimmed)
|
|
140500
|
+
return null;
|
|
140501
|
+
const slashIndex = trimmed.lastIndexOf("/");
|
|
140502
|
+
const unprefixed = slashIndex === -1 ? trimmed : trimmed.slice(slashIndex + 1);
|
|
140503
|
+
return unprefixed.endsWith("-fast") ? unprefixed.slice(0, -"-fast".length) : unprefixed;
|
|
140504
|
+
}
|
|
140505
|
+
function supportsNoneReasoningEffort(model) {
|
|
140506
|
+
return NONE_REASONING_MODEL_PREFIXES.some((prefix) => model === prefix || model.startsWith(`${prefix}-`));
|
|
140507
|
+
}
|
|
140508
|
+
function normalizeReasoningEffortForModel(modelHandleOrId, effort) {
|
|
140509
|
+
if (effort == null)
|
|
140510
|
+
return effort;
|
|
140511
|
+
const model = openaiModelNameFromHandle(modelHandleOrId);
|
|
140512
|
+
if (!model)
|
|
140513
|
+
return effort;
|
|
140514
|
+
if (effort === "minimal" && supportsNoneReasoningEffort(model)) {
|
|
140515
|
+
return "none";
|
|
140516
|
+
}
|
|
140517
|
+
if (effort === "max" && model.startsWith("gpt-5.5")) {
|
|
140518
|
+
return "xhigh";
|
|
140519
|
+
}
|
|
140520
|
+
return effort;
|
|
140521
|
+
}
|
|
140522
|
+
var NONE_REASONING_MODEL_PREFIXES;
|
|
140523
|
+
var init_openai_reasoning_effort = __esm(() => {
|
|
140524
|
+
NONE_REASONING_MODEL_PREFIXES = [
|
|
140525
|
+
"gpt-5.1",
|
|
140526
|
+
"gpt-5.2",
|
|
140527
|
+
"gpt-5.3",
|
|
140528
|
+
"gpt-5.4",
|
|
140529
|
+
"gpt-5.5",
|
|
140530
|
+
"gpt-5.6"
|
|
140531
|
+
];
|
|
140532
|
+
});
|
|
140533
|
+
|
|
140483
140534
|
// src/utils/type-guards.ts
|
|
140484
140535
|
function isRecord(value) {
|
|
140485
140536
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -142282,59 +142333,6 @@ var init_models7 = __esm(() => {
|
|
|
142282
142333
|
parallel_tool_calls: true
|
|
142283
142334
|
}
|
|
142284
142335
|
},
|
|
142285
|
-
{
|
|
142286
|
-
id: "bedrock-opus-4.6",
|
|
142287
|
-
handle: "bedrock/us.anthropic.claude-opus-4-6-v1",
|
|
142288
|
-
label: "Bedrock Opus 4.6",
|
|
142289
|
-
shortLabel: "Opus 4.6 BR",
|
|
142290
|
-
description: "Opus 4.6 via AWS Bedrock",
|
|
142291
|
-
updateArgs: {
|
|
142292
|
-
context_window: 180000,
|
|
142293
|
-
max_output_tokens: 64000,
|
|
142294
|
-
max_reasoning_tokens: 31999,
|
|
142295
|
-
parallel_tool_calls: true
|
|
142296
|
-
}
|
|
142297
|
-
},
|
|
142298
|
-
{
|
|
142299
|
-
id: "bedrock-opus-4.7",
|
|
142300
|
-
handle: "bedrock/us.anthropic.claude-opus-4-7",
|
|
142301
|
-
label: "Bedrock Opus 4.7",
|
|
142302
|
-
shortLabel: "Opus 4.7 BR",
|
|
142303
|
-
description: "Opus 4.7 via AWS Bedrock",
|
|
142304
|
-
updateArgs: {
|
|
142305
|
-
context_window: 200000,
|
|
142306
|
-
max_output_tokens: 128000,
|
|
142307
|
-
reasoning_effort: "medium",
|
|
142308
|
-
enable_reasoner: true,
|
|
142309
|
-
parallel_tool_calls: true
|
|
142310
|
-
}
|
|
142311
|
-
},
|
|
142312
|
-
{
|
|
142313
|
-
id: "bedrock-sonnet-4.6",
|
|
142314
|
-
handle: "bedrock/us.anthropic.claude-sonnet-4-6",
|
|
142315
|
-
label: "Bedrock Sonnet 4.6",
|
|
142316
|
-
shortLabel: "Sonnet 4.6 BR",
|
|
142317
|
-
description: "Sonnet 4.6 via AWS Bedrock",
|
|
142318
|
-
updateArgs: {
|
|
142319
|
-
context_window: 180000,
|
|
142320
|
-
max_output_tokens: 64000,
|
|
142321
|
-
max_reasoning_tokens: 31999,
|
|
142322
|
-
parallel_tool_calls: true
|
|
142323
|
-
}
|
|
142324
|
-
},
|
|
142325
|
-
{
|
|
142326
|
-
id: "bedrock-sonnet-5",
|
|
142327
|
-
handle: "bedrock/us.anthropic.claude-sonnet-5",
|
|
142328
|
-
label: "Bedrock Sonnet 5",
|
|
142329
|
-
shortLabel: "Sonnet 5 BR",
|
|
142330
|
-
description: "Sonnet 5 via AWS Bedrock",
|
|
142331
|
-
updateArgs: {
|
|
142332
|
-
context_window: 180000,
|
|
142333
|
-
max_output_tokens: 64000,
|
|
142334
|
-
max_reasoning_tokens: 31999,
|
|
142335
|
-
parallel_tool_calls: true
|
|
142336
|
-
}
|
|
142337
|
-
},
|
|
142338
142336
|
{
|
|
142339
142337
|
id: "haiku",
|
|
142340
142338
|
handle: "anthropic/claude-haiku-4-5",
|
|
@@ -142775,19 +142773,6 @@ var init_models7 = __esm(() => {
|
|
|
142775
142773
|
parallel_tool_calls: true
|
|
142776
142774
|
}
|
|
142777
142775
|
},
|
|
142778
|
-
{
|
|
142779
|
-
id: "gpt-5-codex",
|
|
142780
|
-
handle: "openai/gpt-5-codex",
|
|
142781
|
-
label: "GPT-5-Codex",
|
|
142782
|
-
description: "GPT-5 variant (med reasoning) optimized for coding",
|
|
142783
|
-
updateArgs: {
|
|
142784
|
-
reasoning_effort: "medium",
|
|
142785
|
-
verbosity: "medium",
|
|
142786
|
-
context_window: 272000,
|
|
142787
|
-
max_output_tokens: 128000,
|
|
142788
|
-
parallel_tool_calls: true
|
|
142789
|
-
}
|
|
142790
|
-
},
|
|
142791
142776
|
{
|
|
142792
142777
|
id: "gpt-5.5-none",
|
|
142793
142778
|
handle: "openai/gpt-5.5",
|
|
@@ -142983,45 +142968,6 @@ var init_models7 = __esm(() => {
|
|
|
142983
142968
|
parallel_tool_calls: true
|
|
142984
142969
|
}
|
|
142985
142970
|
},
|
|
142986
|
-
{
|
|
142987
|
-
id: "gpt-5.4-pro-medium",
|
|
142988
|
-
handle: "openai/gpt-5.4-pro",
|
|
142989
|
-
label: "GPT-5.4 Pro",
|
|
142990
|
-
description: "GPT-5.4 Pro — max performance variant (med reasoning)",
|
|
142991
|
-
updateArgs: {
|
|
142992
|
-
reasoning_effort: "medium",
|
|
142993
|
-
verbosity: "medium",
|
|
142994
|
-
context_window: 272000,
|
|
142995
|
-
max_output_tokens: 128000,
|
|
142996
|
-
parallel_tool_calls: true
|
|
142997
|
-
}
|
|
142998
|
-
},
|
|
142999
|
-
{
|
|
143000
|
-
id: "gpt-5.4-pro-high",
|
|
143001
|
-
handle: "openai/gpt-5.4-pro",
|
|
143002
|
-
label: "GPT-5.4 Pro",
|
|
143003
|
-
description: "GPT-5.4 Pro — max performance variant (high reasoning)",
|
|
143004
|
-
updateArgs: {
|
|
143005
|
-
reasoning_effort: "high",
|
|
143006
|
-
verbosity: "medium",
|
|
143007
|
-
context_window: 272000,
|
|
143008
|
-
max_output_tokens: 128000,
|
|
143009
|
-
parallel_tool_calls: true
|
|
143010
|
-
}
|
|
143011
|
-
},
|
|
143012
|
-
{
|
|
143013
|
-
id: "gpt-5.4-pro-xhigh",
|
|
143014
|
-
handle: "openai/gpt-5.4-pro",
|
|
143015
|
-
label: "GPT-5.4 Pro",
|
|
143016
|
-
description: "GPT-5.4 Pro — max performance variant (max reasoning)",
|
|
143017
|
-
updateArgs: {
|
|
143018
|
-
reasoning_effort: "xhigh",
|
|
143019
|
-
verbosity: "medium",
|
|
143020
|
-
context_window: 272000,
|
|
143021
|
-
max_output_tokens: 128000,
|
|
143022
|
-
parallel_tool_calls: true
|
|
143023
|
-
}
|
|
143024
|
-
},
|
|
143025
142971
|
{
|
|
143026
142972
|
id: "gpt-5.4-mini-none",
|
|
143027
142973
|
handle: "openai/gpt-5.4-mini",
|
|
@@ -143087,71 +143033,6 @@ var init_models7 = __esm(() => {
|
|
|
143087
143033
|
parallel_tool_calls: true
|
|
143088
143034
|
}
|
|
143089
143035
|
},
|
|
143090
|
-
{
|
|
143091
|
-
id: "gpt-5.4-nano-none",
|
|
143092
|
-
handle: "openai/gpt-5.4-nano",
|
|
143093
|
-
label: "GPT-5.4 Nano",
|
|
143094
|
-
description: "Smallest, cheapest GPT-5.4 variant (no reasoning)",
|
|
143095
|
-
updateArgs: {
|
|
143096
|
-
reasoning_effort: "none",
|
|
143097
|
-
verbosity: "low",
|
|
143098
|
-
context_window: 272000,
|
|
143099
|
-
max_output_tokens: 128000,
|
|
143100
|
-
parallel_tool_calls: true
|
|
143101
|
-
}
|
|
143102
|
-
},
|
|
143103
|
-
{
|
|
143104
|
-
id: "gpt-5.4-nano-low",
|
|
143105
|
-
handle: "openai/gpt-5.4-nano",
|
|
143106
|
-
label: "GPT-5.4 Nano",
|
|
143107
|
-
description: "Smallest, cheapest GPT-5.4 variant (low reasoning)",
|
|
143108
|
-
updateArgs: {
|
|
143109
|
-
reasoning_effort: "low",
|
|
143110
|
-
verbosity: "low",
|
|
143111
|
-
context_window: 272000,
|
|
143112
|
-
max_output_tokens: 128000,
|
|
143113
|
-
parallel_tool_calls: true
|
|
143114
|
-
}
|
|
143115
|
-
},
|
|
143116
|
-
{
|
|
143117
|
-
id: "gpt-5.4-nano-medium",
|
|
143118
|
-
handle: "openai/gpt-5.4-nano",
|
|
143119
|
-
label: "GPT-5.4 Nano",
|
|
143120
|
-
description: "Smallest, cheapest GPT-5.4 variant (med reasoning)",
|
|
143121
|
-
updateArgs: {
|
|
143122
|
-
reasoning_effort: "medium",
|
|
143123
|
-
verbosity: "low",
|
|
143124
|
-
context_window: 272000,
|
|
143125
|
-
max_output_tokens: 128000,
|
|
143126
|
-
parallel_tool_calls: true
|
|
143127
|
-
}
|
|
143128
|
-
},
|
|
143129
|
-
{
|
|
143130
|
-
id: "gpt-5.4-nano-high",
|
|
143131
|
-
handle: "openai/gpt-5.4-nano",
|
|
143132
|
-
label: "GPT-5.4 Nano",
|
|
143133
|
-
description: "Smallest, cheapest GPT-5.4 variant (high reasoning)",
|
|
143134
|
-
updateArgs: {
|
|
143135
|
-
reasoning_effort: "high",
|
|
143136
|
-
verbosity: "low",
|
|
143137
|
-
context_window: 272000,
|
|
143138
|
-
max_output_tokens: 128000,
|
|
143139
|
-
parallel_tool_calls: true
|
|
143140
|
-
}
|
|
143141
|
-
},
|
|
143142
|
-
{
|
|
143143
|
-
id: "gpt-5.4-nano-xhigh",
|
|
143144
|
-
handle: "openai/gpt-5.4-nano",
|
|
143145
|
-
label: "GPT-5.4 Nano",
|
|
143146
|
-
description: "Smallest, cheapest GPT-5.4 variant (max reasoning)",
|
|
143147
|
-
updateArgs: {
|
|
143148
|
-
reasoning_effort: "xhigh",
|
|
143149
|
-
verbosity: "low",
|
|
143150
|
-
context_window: 272000,
|
|
143151
|
-
max_output_tokens: 128000,
|
|
143152
|
-
parallel_tool_calls: true
|
|
143153
|
-
}
|
|
143154
|
-
},
|
|
143155
143036
|
{
|
|
143156
143037
|
id: "gpt-5.3-codex-none",
|
|
143157
143038
|
handle: "openai/gpt-5.3-codex",
|
|
@@ -143217,45 +143098,6 @@ var init_models7 = __esm(() => {
|
|
|
143217
143098
|
parallel_tool_calls: true
|
|
143218
143099
|
}
|
|
143219
143100
|
},
|
|
143220
|
-
{
|
|
143221
|
-
id: "gpt-5-mini-high",
|
|
143222
|
-
handle: "openai/gpt-5-mini-2025-08-07",
|
|
143223
|
-
label: "GPT-5-Mini",
|
|
143224
|
-
description: "GPT-5-Mini (high reasoning)",
|
|
143225
|
-
updateArgs: {
|
|
143226
|
-
reasoning_effort: "high",
|
|
143227
|
-
verbosity: "medium",
|
|
143228
|
-
context_window: 272000,
|
|
143229
|
-
max_output_tokens: 128000,
|
|
143230
|
-
parallel_tool_calls: true
|
|
143231
|
-
}
|
|
143232
|
-
},
|
|
143233
|
-
{
|
|
143234
|
-
id: "gpt-5-mini-medium",
|
|
143235
|
-
handle: "openai/gpt-5-mini-2025-08-07",
|
|
143236
|
-
label: "GPT-5-Mini",
|
|
143237
|
-
description: "GPT-5-Mini (medium reasoning)",
|
|
143238
|
-
updateArgs: {
|
|
143239
|
-
reasoning_effort: "medium",
|
|
143240
|
-
verbosity: "medium",
|
|
143241
|
-
context_window: 272000,
|
|
143242
|
-
max_output_tokens: 128000,
|
|
143243
|
-
parallel_tool_calls: true
|
|
143244
|
-
}
|
|
143245
|
-
},
|
|
143246
|
-
{
|
|
143247
|
-
id: "gpt-5-nano-medium",
|
|
143248
|
-
handle: "openai/gpt-5-nano-2025-08-07",
|
|
143249
|
-
label: "GPT-5-Nano",
|
|
143250
|
-
description: "GPT-5-Nano (medium reasoning)",
|
|
143251
|
-
updateArgs: {
|
|
143252
|
-
reasoning_effort: "medium",
|
|
143253
|
-
verbosity: "medium",
|
|
143254
|
-
context_window: 272000,
|
|
143255
|
-
max_output_tokens: 128000,
|
|
143256
|
-
parallel_tool_calls: true
|
|
143257
|
-
}
|
|
143258
|
-
},
|
|
143259
143101
|
{
|
|
143260
143102
|
id: "grok-4.5",
|
|
143261
143103
|
handle: "xai/grok-4.5",
|
|
@@ -143268,18 +143110,6 @@ var init_models7 = __esm(() => {
|
|
|
143268
143110
|
parallel_tool_calls: true
|
|
143269
143111
|
}
|
|
143270
143112
|
},
|
|
143271
|
-
{
|
|
143272
|
-
id: "deepseek-v4-pro",
|
|
143273
|
-
handle: "openrouter/deepseek/deepseek-v4-pro",
|
|
143274
|
-
label: "DeepSeek V4 Pro",
|
|
143275
|
-
description: "DeepSeek's V4 Pro model",
|
|
143276
|
-
updateArgs: {
|
|
143277
|
-
context_window: 1048576,
|
|
143278
|
-
max_output_tokens: 384000,
|
|
143279
|
-
parallel_tool_calls: true
|
|
143280
|
-
},
|
|
143281
|
-
isFeatured: true
|
|
143282
|
-
},
|
|
143283
143113
|
{
|
|
143284
143114
|
id: "glm-5.2",
|
|
143285
143115
|
handle: "zai/glm-5.2",
|
|
@@ -143329,17 +143159,6 @@ var init_models7 = __esm(() => {
|
|
|
143329
143159
|
parallel_tool_calls: true
|
|
143330
143160
|
}
|
|
143331
143161
|
},
|
|
143332
|
-
{
|
|
143333
|
-
id: "minimax-m2",
|
|
143334
|
-
handle: "openrouter/minimax/minimax-m2",
|
|
143335
|
-
label: "MiniMax M2",
|
|
143336
|
-
description: "MiniMax's M2 model",
|
|
143337
|
-
updateArgs: {
|
|
143338
|
-
context_window: 160000,
|
|
143339
|
-
max_output_tokens: 64000,
|
|
143340
|
-
parallel_tool_calls: true
|
|
143341
|
-
}
|
|
143342
|
-
},
|
|
143343
143162
|
{
|
|
143344
143163
|
id: "kimi-k3",
|
|
143345
143164
|
handle: "moonshot/kimi-k3",
|
|
@@ -143352,50 +143171,6 @@ var init_models7 = __esm(() => {
|
|
|
143352
143171
|
parallel_tool_calls: true
|
|
143353
143172
|
}
|
|
143354
143173
|
},
|
|
143355
|
-
{
|
|
143356
|
-
id: "kimi-k3-openrouter",
|
|
143357
|
-
handle: "openrouter/moonshotai/kimi-k3",
|
|
143358
|
-
label: "Kimi K3",
|
|
143359
|
-
description: "Moonshot AI's Kimi K3 model for long-context agentic coding and reasoning tasks",
|
|
143360
|
-
updateArgs: {
|
|
143361
|
-
context_window: 1048576,
|
|
143362
|
-
max_output_tokens: 131072,
|
|
143363
|
-
parallel_tool_calls: true
|
|
143364
|
-
}
|
|
143365
|
-
},
|
|
143366
|
-
{
|
|
143367
|
-
id: "kimi-k2.7",
|
|
143368
|
-
handle: "openrouter/moonshotai/kimi-k2.7-code",
|
|
143369
|
-
label: "Kimi K2.7 Code",
|
|
143370
|
-
description: "Moonshot AI's coding-focused Kimi K2.7 model for long-context agentic programming tasks",
|
|
143371
|
-
isFeatured: true,
|
|
143372
|
-
updateArgs: {
|
|
143373
|
-
context_window: 262144,
|
|
143374
|
-
max_output_tokens: 16384,
|
|
143375
|
-
parallel_tool_calls: true
|
|
143376
|
-
}
|
|
143377
|
-
},
|
|
143378
|
-
{
|
|
143379
|
-
id: "kimi-k2.6",
|
|
143380
|
-
handle: "openrouter/moonshotai/kimi-k2.6",
|
|
143381
|
-
label: "Kimi K2.6",
|
|
143382
|
-
description: "Moonshot AI's next-gen multimodal coding and agent model",
|
|
143383
|
-
updateArgs: {
|
|
143384
|
-
context_window: 200000,
|
|
143385
|
-
max_output_tokens: 64000,
|
|
143386
|
-
parallel_tool_calls: true
|
|
143387
|
-
}
|
|
143388
|
-
},
|
|
143389
|
-
{
|
|
143390
|
-
id: "deepseek-chat-v3.1",
|
|
143391
|
-
handle: "openrouter/deepseek/deepseek-chat-v3.1",
|
|
143392
|
-
label: "DeepSeek Chat V3.1",
|
|
143393
|
-
description: "DeepSeek V3.1 model",
|
|
143394
|
-
updateArgs: {
|
|
143395
|
-
context_window: 128000,
|
|
143396
|
-
parallel_tool_calls: true
|
|
143397
|
-
}
|
|
143398
|
-
},
|
|
143399
143174
|
{
|
|
143400
143175
|
id: "gemini-3.1",
|
|
143401
143176
|
handle: "google_ai/gemini-3.1-pro-preview",
|
|
@@ -143430,68 +143205,6 @@ var init_models7 = __esm(() => {
|
|
|
143430
143205
|
temperature: 1,
|
|
143431
143206
|
parallel_tool_calls: true
|
|
143432
143207
|
}
|
|
143433
|
-
},
|
|
143434
|
-
{
|
|
143435
|
-
id: "gemini-3.1-flash-lite",
|
|
143436
|
-
handle: "google_ai/gemini-3.1-flash-lite",
|
|
143437
|
-
label: "Gemini 3.1 Flash-Lite",
|
|
143438
|
-
description: "Google's lightweight Gemini 3.1 Flash-Lite model",
|
|
143439
|
-
updateArgs: {
|
|
143440
|
-
context_window: 1048576,
|
|
143441
|
-
temperature: 1,
|
|
143442
|
-
parallel_tool_calls: true
|
|
143443
|
-
}
|
|
143444
|
-
},
|
|
143445
|
-
{
|
|
143446
|
-
id: "gpt-4.1",
|
|
143447
|
-
handle: "openai/gpt-4.1",
|
|
143448
|
-
label: "GPT-4.1",
|
|
143449
|
-
description: "OpenAI's most recent non-reasoner model",
|
|
143450
|
-
updateArgs: {
|
|
143451
|
-
context_window: 1047576,
|
|
143452
|
-
parallel_tool_calls: true
|
|
143453
|
-
}
|
|
143454
|
-
},
|
|
143455
|
-
{
|
|
143456
|
-
id: "gpt-4.1-mini",
|
|
143457
|
-
handle: "openai/gpt-4.1-mini-2025-04-14",
|
|
143458
|
-
label: "GPT-4.1-Mini",
|
|
143459
|
-
description: "OpenAI's most recent non-reasoner model (mini version)",
|
|
143460
|
-
updateArgs: {
|
|
143461
|
-
context_window: 1047576,
|
|
143462
|
-
parallel_tool_calls: true
|
|
143463
|
-
}
|
|
143464
|
-
},
|
|
143465
|
-
{
|
|
143466
|
-
id: "gpt-4.1-nano",
|
|
143467
|
-
handle: "openai/gpt-4.1-nano-2025-04-14",
|
|
143468
|
-
label: "GPT-4.1-Nano",
|
|
143469
|
-
description: "OpenAI's most recent non-reasoner model (nano version)",
|
|
143470
|
-
updateArgs: {
|
|
143471
|
-
context_window: 1047576,
|
|
143472
|
-
parallel_tool_calls: true
|
|
143473
|
-
}
|
|
143474
|
-
},
|
|
143475
|
-
{
|
|
143476
|
-
id: "o4-mini",
|
|
143477
|
-
handle: "openai/o4-mini",
|
|
143478
|
-
label: "o4-mini",
|
|
143479
|
-
description: "OpenAI's latest o-series reasoning model",
|
|
143480
|
-
updateArgs: {
|
|
143481
|
-
context_window: 180000,
|
|
143482
|
-
parallel_tool_calls: true
|
|
143483
|
-
}
|
|
143484
|
-
},
|
|
143485
|
-
{
|
|
143486
|
-
id: "gemini-3.1-vertex",
|
|
143487
|
-
handle: "google_vertex/gemini-3.1-pro-preview",
|
|
143488
|
-
label: "Gemini 3.1 Pro",
|
|
143489
|
-
description: "Google's latest Gemini 3.1 Pro model (via Vertex AI)",
|
|
143490
|
-
updateArgs: {
|
|
143491
|
-
context_window: 180000,
|
|
143492
|
-
temperature: 1,
|
|
143493
|
-
parallel_tool_calls: true
|
|
143494
|
-
}
|
|
143495
143208
|
}
|
|
143496
143209
|
]
|
|
143497
143210
|
};
|
|
@@ -145589,7 +145302,9 @@ function buildModelSettings(modelHandle, updateArgs) {
|
|
|
145589
145302
|
openaiSettings.provider_type = "chatgpt_oauth";
|
|
145590
145303
|
}
|
|
145591
145304
|
if (updateArgs && "reasoning_effort" in updateArgs) {
|
|
145592
|
-
openaiSettings.reasoning = updateArgs.reasoning_effort === null ? null : {
|
|
145305
|
+
openaiSettings.reasoning = updateArgs.reasoning_effort === null ? null : {
|
|
145306
|
+
reasoning_effort: normalizeReasoningEffortForModel(modelHandle, String(updateArgs.reasoning_effort))
|
|
145307
|
+
};
|
|
145593
145308
|
}
|
|
145594
145309
|
const verbosity = updateArgs?.verbosity;
|
|
145595
145310
|
if (verbosity === "low" || verbosity === "medium" || verbosity === "high") {
|
|
@@ -145695,7 +145410,9 @@ function buildModelSettings(modelHandle, updateArgs) {
|
|
|
145695
145410
|
parallel_tool_calls: typeof updateArgs?.parallel_tool_calls === "boolean" ? updateArgs.parallel_tool_calls : true
|
|
145696
145411
|
};
|
|
145697
145412
|
if (updateArgs && "reasoning_effort" in updateArgs) {
|
|
145698
|
-
openaiProxySettings.reasoning = updateArgs.reasoning_effort === null ? null : {
|
|
145413
|
+
openaiProxySettings.reasoning = updateArgs.reasoning_effort === null ? null : {
|
|
145414
|
+
reasoning_effort: normalizeReasoningEffortForModel(modelHandle, String(updateArgs.reasoning_effort))
|
|
145415
|
+
};
|
|
145699
145416
|
}
|
|
145700
145417
|
if (typeof updateArgs?.strict === "boolean") {
|
|
145701
145418
|
openaiProxySettings.strict = updateArgs.strict;
|
|
@@ -146005,6 +145722,7 @@ var init_modify = __esm(() => {
|
|
|
146005
145722
|
init_backend2();
|
|
146006
145723
|
init_openai_codex_provider();
|
|
146007
145724
|
init_debug();
|
|
145725
|
+
init_openai_reasoning_effort();
|
|
146008
145726
|
init_available_models();
|
|
146009
145727
|
init_model();
|
|
146010
145728
|
__modifyTestUtils = {
|
|
@@ -154763,6 +154481,10 @@ var init_shell_env = __esm(() => {
|
|
|
154763
154481
|
});
|
|
154764
154482
|
|
|
154765
154483
|
// src/tools/impl/github-pull-request-tracker.ts
|
|
154484
|
+
function conversationTags(conversation) {
|
|
154485
|
+
const tags = typeof conversation === "object" && conversation !== null ? Reflect.get(conversation, "tags") : undefined;
|
|
154486
|
+
return Array.isArray(tags) ? tags.filter((tag) => typeof tag === "string") : [];
|
|
154487
|
+
}
|
|
154766
154488
|
function executableName(value) {
|
|
154767
154489
|
return value.replaceAll("\\", "/").split("/").pop()?.toLowerCase() ?? "";
|
|
154768
154490
|
}
|
|
@@ -154893,15 +154615,14 @@ function tagFromOutputLine(line) {
|
|
|
154893
154615
|
if (!owner || !repo || !number7) {
|
|
154894
154616
|
return;
|
|
154895
154617
|
}
|
|
154896
|
-
return
|
|
154618
|
+
return `${GITHUB_PR_TAG_PREFIX}${owner.toLowerCase()}:${repo.toLowerCase()}:${number7}`;
|
|
154897
154619
|
}
|
|
154898
154620
|
function appendOutputTail(outputByStream, text, stream11) {
|
|
154899
154621
|
outputByStream[stream11] = `${outputByStream[stream11]}${text}`.slice(-MAX_TRACKED_OUTPUT_CHARS);
|
|
154900
154622
|
}
|
|
154901
154623
|
async function appendConversationTags(backend, conversationId, tags) {
|
|
154902
154624
|
const conversation = await backend.retrieveConversation(conversationId);
|
|
154903
|
-
const
|
|
154904
|
-
const existingTags = Array.isArray(currentTags) ? currentTags.filter((tag) => typeof tag === "string") : [];
|
|
154625
|
+
const existingTags = conversationTags(conversation);
|
|
154905
154626
|
const missingTags = tags.filter((tag) => !existingTags.includes(tag));
|
|
154906
154627
|
if (missingTags.length === 0) {
|
|
154907
154628
|
return;
|
|
@@ -154923,6 +154644,22 @@ function queueConversationTagUpdate(backend, conversationId, tags) {
|
|
|
154923
154644
|
});
|
|
154924
154645
|
return update2;
|
|
154925
154646
|
}
|
|
154647
|
+
async function copyGitHubPullRequestTags(sourceConversationId, targetConversationId, backend) {
|
|
154648
|
+
if (!sourceConversationId || !targetConversationId || sourceConversationId === "default" || targetConversationId === "default" || sourceConversationId === targetConversationId) {
|
|
154649
|
+
return;
|
|
154650
|
+
}
|
|
154651
|
+
try {
|
|
154652
|
+
const activeBackend = backend ?? getBackend();
|
|
154653
|
+
const sourceConversation = await activeBackend.retrieveConversation(sourceConversationId);
|
|
154654
|
+
const pullRequestTags = conversationTags(sourceConversation).filter((tag) => tag.startsWith(GITHUB_PR_TAG_PREFIX));
|
|
154655
|
+
if (pullRequestTags.length === 0) {
|
|
154656
|
+
return;
|
|
154657
|
+
}
|
|
154658
|
+
await queueConversationTagUpdate(activeBackend, targetConversationId, pullRequestTags);
|
|
154659
|
+
} catch (error54) {
|
|
154660
|
+
debugLog("github-pr-tracking", `Failed to copy PR tags from ${sourceConversationId} to ${targetConversationId}`, error54);
|
|
154661
|
+
}
|
|
154662
|
+
}
|
|
154926
154663
|
function createGitHubPullRequestOutputTracker(command, options3) {
|
|
154927
154664
|
if (!isGitHubPullRequestCreateCommand(command)) {
|
|
154928
154665
|
return;
|
|
@@ -154969,7 +154706,7 @@ ${outputByStream.stderr}`.split(/\r\n|\n|\r/)) {
|
|
|
154969
154706
|
}
|
|
154970
154707
|
};
|
|
154971
154708
|
}
|
|
154972
|
-
var ENV_ASSIGNMENT, GITHUB_PR_URL, HEREDOC_AT_LINE_END, MAX_TRACKED_OUTPUT_CHARS = 30000, GH_GLOBAL_FLAGS_WITH_VALUES, conversationTagUpdateTails;
|
|
154709
|
+
var ENV_ASSIGNMENT, GITHUB_PR_URL, GITHUB_PR_TAG_PREFIX = "github:pull-request:", HEREDOC_AT_LINE_END, MAX_TRACKED_OUTPUT_CHARS = 30000, GH_GLOBAL_FLAGS_WITH_VALUES, conversationTagUpdateTails;
|
|
154973
154710
|
var init_github_pull_request_tracker = __esm(() => {
|
|
154974
154711
|
init_strip_ansi();
|
|
154975
154712
|
init_backend2();
|
|
@@ -158255,33 +157992,10 @@ var init_background_process_snapshot = __esm(() => {
|
|
|
158255
157992
|
});
|
|
158256
157993
|
|
|
158257
157994
|
// src/websocket/listener/constants.ts
|
|
158258
|
-
var MAX_RETRY_DURATION_MS, INITIAL_RETRY_DELAY_MS2 = 1000, MAX_RETRY_DELAY_MS = 30000, LISTENER_STREAM_OPEN_TIMEOUT_MS = 30000, LISTENER_HEARTBEAT_INTERVAL_MS = 30000, LISTENER_PONG_TIMEOUT_MS = 90000, SYSTEM_REMINDER_RE, LLM_API_ERROR_MAX_RETRIES = 3, EMPTY_RESPONSE_MAX_RETRIES = 2, MAX_PRE_STREAM_RECOVERY = 2, MAX_POST_STOP_APPROVAL_RECOVERY = 2
|
|
157995
|
+
var MAX_RETRY_DURATION_MS, INITIAL_RETRY_DELAY_MS2 = 1000, MAX_RETRY_DELAY_MS = 30000, LISTENER_STREAM_OPEN_TIMEOUT_MS = 30000, LISTENER_HEARTBEAT_INTERVAL_MS = 30000, LISTENER_PONG_TIMEOUT_MS = 90000, SYSTEM_REMINDER_RE, LLM_API_ERROR_MAX_RETRIES = 3, EMPTY_RESPONSE_MAX_RETRIES = 2, MAX_PRE_STREAM_RECOVERY = 2, MAX_POST_STOP_APPROVAL_RECOVERY = 2;
|
|
158259
157996
|
var init_constants3 = __esm(() => {
|
|
158260
157997
|
MAX_RETRY_DURATION_MS = 5 * 60 * 1000;
|
|
158261
157998
|
SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
158262
|
-
PROVIDER_FALLBACK_MAP = {
|
|
158263
|
-
"opus-4.7-low": "bedrock-opus-4.7",
|
|
158264
|
-
"opus-4.7-medium": "bedrock-opus-4.7",
|
|
158265
|
-
"opus-4.7-high": "bedrock-opus-4.7",
|
|
158266
|
-
"opus-4.7-xhigh": "bedrock-opus-4.7",
|
|
158267
|
-
"opus-4.7-max": "bedrock-opus-4.7",
|
|
158268
|
-
"opus-4.6-no-reasoning": "bedrock-opus-4.6",
|
|
158269
|
-
"opus-4.6-low": "bedrock-opus-4.6",
|
|
158270
|
-
"opus-4.6-medium": "bedrock-opus-4.6",
|
|
158271
|
-
"opus-4.6-high": "bedrock-opus-4.6",
|
|
158272
|
-
"opus-4.6-xhigh": "bedrock-opus-4.6",
|
|
158273
|
-
sonnet: "bedrock-sonnet-5",
|
|
158274
|
-
"sonnet-5-no-reasoning": "bedrock-sonnet-5",
|
|
158275
|
-
"sonnet-5-low": "bedrock-sonnet-5",
|
|
158276
|
-
"sonnet-5-medium": "bedrock-sonnet-5",
|
|
158277
|
-
"sonnet-5-xhigh": "bedrock-sonnet-5",
|
|
158278
|
-
"sonnet-4.6": "bedrock-sonnet-4.6",
|
|
158279
|
-
"sonnet-1m": "bedrock-sonnet-4.6",
|
|
158280
|
-
"sonnet-4.6-no-reasoning": "bedrock-sonnet-4.6",
|
|
158281
|
-
"sonnet-4.6-low": "bedrock-sonnet-4.6",
|
|
158282
|
-
"sonnet-4.6-medium": "bedrock-sonnet-4.6",
|
|
158283
|
-
"sonnet-4.6-xhigh": "bedrock-sonnet-4.6"
|
|
158284
|
-
};
|
|
158285
157999
|
});
|
|
158286
158000
|
|
|
158287
158001
|
// src/websocket/listener/device-status-cache.ts
|
|
@@ -175734,6 +175448,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
175734
175448
|
const shouldEmitCompletionNotification = emitCompletionNotification ?? !silentCompletion;
|
|
175735
175449
|
const resolvedParentScope = resolveNotificationScope(parentScope);
|
|
175736
175450
|
const spawnSubagentFn = deps?.spawnSubagentImpl ?? spawnSubagent;
|
|
175451
|
+
const copyGitHubPullRequestTagsFn = deps?.copyGitHubPullRequestTagsImpl ?? copyGitHubPullRequestTags;
|
|
175737
175452
|
const addToMessageQueueFn = deps?.addToMessageQueueImpl ?? addToMessageQueue;
|
|
175738
175453
|
const formatTaskNotificationFn = deps?.formatTaskNotificationImpl ?? formatTaskNotification;
|
|
175739
175454
|
const runSubagentStopHooksFn = deps?.runSubagentStopHooksImpl ?? runSubagentStopHooks;
|
|
@@ -175762,6 +175477,7 @@ function spawnBackgroundSubagentTask(args) {
|
|
|
175762
175477
|
writeTaskTranscriptStart(outputFile, description, subagentType);
|
|
175763
175478
|
const parentAgentIdForSpawn = resolvedParentScope?.agentId;
|
|
175764
175479
|
spawnSubagentFn(subagentType, prompt, model, subagentId, abortController.signal, existingAgentId, existingConversationId, maxTurns, forkedContext, parentAgentIdForSpawn, transcriptPath, resolvedParentScope?.conversationId, memoryScope, systemPromptOverride).then(async (result) => {
|
|
175480
|
+
await copyGitHubPullRequestTagsFn(result.conversationId, resolvedParentScope?.conversationId);
|
|
175765
175481
|
bgTask.status = result.success ? "completed" : "failed";
|
|
175766
175482
|
if (result.error) {
|
|
175767
175483
|
bgTask.error = result.error;
|
|
@@ -175979,6 +175695,7 @@ You will be notified automatically when this task completes — a <task-notifica
|
|
|
175979
175695
|
try {
|
|
175980
175696
|
const parentAgentIdForSpawn = resolvedParentScope?.agentId;
|
|
175981
175697
|
const result = await spawnSubagent(subagent_type, prompt, model, subagentId, signal, effectiveAgentId, effectiveConversationId, args.max_turns, config3.fork, parentAgentIdForSpawn, undefined, resolvedParentScope?.conversationId);
|
|
175698
|
+
await copyGitHubPullRequestTags(result.conversationId, resolvedParentScope?.conversationId);
|
|
175982
175699
|
completeSubagent(subagentId, {
|
|
175983
175700
|
success: result.success,
|
|
175984
175701
|
error: result.error,
|
|
@@ -176039,6 +175756,7 @@ var init_task = __esm(() => {
|
|
|
176039
175756
|
init_settings_manager();
|
|
176040
175757
|
init_message_queue_bridge();
|
|
176041
175758
|
init_task_notifications();
|
|
175759
|
+
init_github_pull_request_tracker();
|
|
176042
175760
|
init_process_manager();
|
|
176043
175761
|
init_truncation();
|
|
176044
175762
|
VALID_DEPLOY_TYPES = new Set(["general-purpose"]);
|
|
@@ -192320,6 +192038,8 @@ function thinkingLevelSetting(value, preserveMax) {
|
|
|
192320
192038
|
const effort = settingString(value);
|
|
192321
192039
|
if (effort === "max")
|
|
192322
192040
|
return preserveMax ? "max" : "xhigh";
|
|
192041
|
+
if (effort === "none")
|
|
192042
|
+
return "none";
|
|
192323
192043
|
return effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" ? effort : undefined;
|
|
192324
192044
|
}
|
|
192325
192045
|
function reasoningForSettings(modelSettings, modelHandle) {
|
|
@@ -192329,7 +192049,8 @@ function reasoningForSettings(modelSettings, modelHandle) {
|
|
|
192329
192049
|
const nestedReasoning = isRecord(modelSettings.reasoning) ? modelSettings.reasoning : undefined;
|
|
192330
192050
|
const modelId = modelHandle?.slice(modelHandle.indexOf("/") + 1);
|
|
192331
192051
|
const preserveMax = modelId?.startsWith("gpt-5.6") === true;
|
|
192332
|
-
|
|
192052
|
+
const rawEffort = nestedReasoning?.reasoning_effort ?? modelSettings.effort ?? modelSettings.reasoning_effort;
|
|
192053
|
+
return thinkingLevelSetting(normalizeReasoningEffortForModel(modelHandle, typeof rawEffort === "string" ? rawEffort : undefined), preserveMax);
|
|
192333
192054
|
}
|
|
192334
192055
|
function applyPiEnvOverrides(overrides) {
|
|
192335
192056
|
if (!overrides)
|
|
@@ -192591,6 +192312,7 @@ var init_pi_model_factory = __esm(() => {
|
|
|
192591
192312
|
init_local_pi_credential_store();
|
|
192592
192313
|
init_local_provider_auth_store();
|
|
192593
192314
|
init_local_provider_timeout();
|
|
192315
|
+
init_openai_reasoning_effort();
|
|
192594
192316
|
init_pi_models_runtime();
|
|
192595
192317
|
init_pi_provider_mod_registry();
|
|
192596
192318
|
init_pi_provider_registry();
|
|
@@ -235726,6 +235448,26 @@ var init_recent_agent_options = __esm(() => {
|
|
|
235726
235448
|
init_settings_manager();
|
|
235727
235449
|
});
|
|
235728
235450
|
|
|
235451
|
+
// src/agent/reasoning-effort-label.ts
|
|
235452
|
+
function catalogHasDistinctMaxTier(params) {
|
|
235453
|
+
const { modelLabel, modelHandle } = params;
|
|
235454
|
+
if (!modelLabel && !modelHandle)
|
|
235455
|
+
return false;
|
|
235456
|
+
return models2.some((model) => {
|
|
235457
|
+
if (model.updateArgs?.reasoning_effort !== "max")
|
|
235458
|
+
return false;
|
|
235459
|
+
if (modelHandle && model.handle === modelHandle)
|
|
235460
|
+
return true;
|
|
235461
|
+
return Boolean(modelLabel && model.label === modelLabel);
|
|
235462
|
+
});
|
|
235463
|
+
}
|
|
235464
|
+
function formatXhighEffortLabel(hasDistinctMaxTier) {
|
|
235465
|
+
return hasDistinctMaxTier ? "Extra High" : "Max";
|
|
235466
|
+
}
|
|
235467
|
+
var init_reasoning_effort_label = __esm(() => {
|
|
235468
|
+
init_model_catalog();
|
|
235469
|
+
});
|
|
235470
|
+
|
|
235729
235471
|
// src/cli/components/ModelReasoningSelector.tsx
|
|
235730
235472
|
function formatEffortLabel(effort, hasDistinctMaxTier) {
|
|
235731
235473
|
if (effort === null)
|
|
@@ -235733,7 +235475,7 @@ function formatEffortLabel(effort, hasDistinctMaxTier) {
|
|
|
235733
235475
|
if (effort === "none")
|
|
235734
235476
|
return "Off";
|
|
235735
235477
|
if (effort === "xhigh")
|
|
235736
|
-
return hasDistinctMaxTier
|
|
235478
|
+
return formatXhighEffortLabel(hasDistinctMaxTier);
|
|
235737
235479
|
if (effort === "max")
|
|
235738
235480
|
return "Max";
|
|
235739
235481
|
if (effort === "minimal")
|
|
@@ -235875,6 +235617,7 @@ function ModelReasoningSelector({
|
|
|
235875
235617
|
}
|
|
235876
235618
|
var import_react27, jsx_dev_runtime8, SOLID_LINE2 = "─", EFFORT_BLOCK = "▌";
|
|
235877
235619
|
var init_ModelReasoningSelector = __esm(async () => {
|
|
235620
|
+
init_reasoning_effort_label();
|
|
235878
235621
|
init_use_terminal_width();
|
|
235879
235622
|
init_colors();
|
|
235880
235623
|
await __promiseAll([
|
|
@@ -239831,195 +239574,7 @@ var init_lifecycle_error = __esm(() => {
|
|
|
239831
239574
|
CHANNEL_LIFECYCLE_CONVERSATION_BUSY_TITLE = CONVERSATION_BUSY_TITLE;
|
|
239832
239575
|
});
|
|
239833
239576
|
|
|
239834
|
-
// src/channels/
|
|
239835
|
-
var exports_transcription = {};
|
|
239836
|
-
__export(exports_transcription, {
|
|
239837
|
-
transcribeAudioFile: () => transcribeAudioFile,
|
|
239838
|
-
isTranscriptionConfigured: () => isTranscriptionConfigured
|
|
239839
|
-
});
|
|
239840
|
-
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
239841
|
-
import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync22, rmSync as rmSync8 } from "node:fs";
|
|
239842
|
-
import { tmpdir as tmpdir8 } from "node:os";
|
|
239843
|
-
import { basename as basename12, extname as extname5, join as join41 } from "node:path";
|
|
239844
|
-
function audioMimeTypeForPath(localPath) {
|
|
239845
|
-
switch (extname5(localPath).toLowerCase()) {
|
|
239846
|
-
case ".flac":
|
|
239847
|
-
return "audio/flac";
|
|
239848
|
-
case ".m4a":
|
|
239849
|
-
return "audio/mp4";
|
|
239850
|
-
case ".mp3":
|
|
239851
|
-
case ".mpeg":
|
|
239852
|
-
case ".mpga":
|
|
239853
|
-
return "audio/mpeg";
|
|
239854
|
-
case ".mp4":
|
|
239855
|
-
return "video/mp4";
|
|
239856
|
-
case ".oga":
|
|
239857
|
-
case ".ogg":
|
|
239858
|
-
return "audio/ogg";
|
|
239859
|
-
case ".wav":
|
|
239860
|
-
return "audio/wav";
|
|
239861
|
-
case ".webm":
|
|
239862
|
-
return "audio/webm";
|
|
239863
|
-
default:
|
|
239864
|
-
return "audio/mp4";
|
|
239865
|
-
}
|
|
239866
|
-
}
|
|
239867
|
-
function prepareOpenAiTranscriptionFile(localPath) {
|
|
239868
|
-
if (OPENAI_SUPPORTED_AUDIO_EXTENSIONS.has(extname5(localPath).toLowerCase())) {
|
|
239869
|
-
return { localPath };
|
|
239870
|
-
}
|
|
239871
|
-
const tempDir = mkdtempSync3(join41(tmpdir8(), "letta-transcription-"));
|
|
239872
|
-
const convertedPath = join41(tempDir, `${basename12(localPath)}.m4a`);
|
|
239873
|
-
try {
|
|
239874
|
-
execFileSync4("ffmpeg", [
|
|
239875
|
-
"-y",
|
|
239876
|
-
"-loglevel",
|
|
239877
|
-
"error",
|
|
239878
|
-
"-i",
|
|
239879
|
-
localPath,
|
|
239880
|
-
"-vn",
|
|
239881
|
-
"-c:a",
|
|
239882
|
-
"aac",
|
|
239883
|
-
convertedPath
|
|
239884
|
-
], { stdio: "ignore", timeout: TRANSCRIPTION_TIMEOUT_MS });
|
|
239885
|
-
} catch (error54) {
|
|
239886
|
-
rmSync8(tempDir, { recursive: true, force: true });
|
|
239887
|
-
throw new Error(`Unsupported audio format ${extname5(localPath).replace(/^\./, "") || "unknown"}; ffmpeg conversion failed. ffmpeg is required to transcribe this audio format; install ffmpeg on the channel listener machine. ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
239888
|
-
}
|
|
239889
|
-
return {
|
|
239890
|
-
localPath: convertedPath,
|
|
239891
|
-
cleanup: () => rmSync8(tempDir, { recursive: true, force: true })
|
|
239892
|
-
};
|
|
239893
|
-
}
|
|
239894
|
-
function isTranscriptionConfigured() {
|
|
239895
|
-
return !!process.env.OPENAI_API_KEY;
|
|
239896
|
-
}
|
|
239897
|
-
async function transcribeAudioFile(localPath) {
|
|
239898
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
239899
|
-
if (!apiKey) {
|
|
239900
|
-
return {
|
|
239901
|
-
success: false,
|
|
239902
|
-
error: "OPENAI_API_KEY not set; transcription skipped."
|
|
239903
|
-
};
|
|
239904
|
-
}
|
|
239905
|
-
try {
|
|
239906
|
-
const prepared = prepareOpenAiTranscriptionFile(localPath);
|
|
239907
|
-
try {
|
|
239908
|
-
const buffer = readFileSync22(prepared.localPath);
|
|
239909
|
-
const filename = basename12(prepared.localPath);
|
|
239910
|
-
const formData = new FormData;
|
|
239911
|
-
const blob = new Blob([buffer], {
|
|
239912
|
-
type: audioMimeTypeForPath(prepared.localPath)
|
|
239913
|
-
});
|
|
239914
|
-
formData.append("file", blob, filename);
|
|
239915
|
-
formData.append("model", OPENAI_TRANSCRIPTION_MODEL);
|
|
239916
|
-
const controller = new AbortController;
|
|
239917
|
-
const timeout = setTimeout(() => controller.abort(), TRANSCRIPTION_TIMEOUT_MS);
|
|
239918
|
-
try {
|
|
239919
|
-
const response = await fetch(OPENAI_TRANSCRIPTION_API_URL, {
|
|
239920
|
-
method: "POST",
|
|
239921
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
239922
|
-
body: formData,
|
|
239923
|
-
signal: controller.signal
|
|
239924
|
-
});
|
|
239925
|
-
if (!response.ok) {
|
|
239926
|
-
const errorText = await response.text();
|
|
239927
|
-
return {
|
|
239928
|
-
success: false,
|
|
239929
|
-
error: `OpenAI transcription API error (${response.status}): ${errorText}`
|
|
239930
|
-
};
|
|
239931
|
-
}
|
|
239932
|
-
const data = await response.json();
|
|
239933
|
-
return { success: true, text: data.text };
|
|
239934
|
-
} finally {
|
|
239935
|
-
clearTimeout(timeout);
|
|
239936
|
-
}
|
|
239937
|
-
} finally {
|
|
239938
|
-
prepared.cleanup?.();
|
|
239939
|
-
}
|
|
239940
|
-
} catch (error54) {
|
|
239941
|
-
return {
|
|
239942
|
-
success: false,
|
|
239943
|
-
error: error54 instanceof Error ? error54.message : String(error54)
|
|
239944
|
-
};
|
|
239945
|
-
}
|
|
239946
|
-
}
|
|
239947
|
-
var OPENAI_TRANSCRIPTION_API_URL = "https://api.openai.com/v1/audio/transcriptions", OPENAI_TRANSCRIPTION_MODEL = "gpt-4o-transcribe", TRANSCRIPTION_TIMEOUT_MS = 30000, OPENAI_SUPPORTED_AUDIO_EXTENSIONS;
|
|
239948
|
-
var init_transcription = __esm(() => {
|
|
239949
|
-
OPENAI_SUPPORTED_AUDIO_EXTENSIONS = new Set([
|
|
239950
|
-
".flac",
|
|
239951
|
-
".m4a",
|
|
239952
|
-
".mp3",
|
|
239953
|
-
".mp4",
|
|
239954
|
-
".mpeg",
|
|
239955
|
-
".mpga",
|
|
239956
|
-
".oga",
|
|
239957
|
-
".ogg",
|
|
239958
|
-
".wav",
|
|
239959
|
-
".webm"
|
|
239960
|
-
]);
|
|
239961
|
-
});
|
|
239962
|
-
|
|
239963
|
-
// src/channels/telegram/media.ts
|
|
239964
|
-
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
239965
|
-
import { mkdir as mkdir8, writeFile as writeFile10 } from "node:fs/promises";
|
|
239966
|
-
import { basename as basename13, extname as extname6, join as join42 } from "node:path";
|
|
239967
|
-
function normalizeTelegramMimeType(mimeType) {
|
|
239968
|
-
const normalized = mimeType?.split(";")[0]?.trim().toLowerCase();
|
|
239969
|
-
return normalized || undefined;
|
|
239970
|
-
}
|
|
239971
|
-
function sanitizeTelegramPathSegment(input) {
|
|
239972
|
-
const cleaned = input.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^_+|_+$/g, "");
|
|
239973
|
-
return cleaned || "attachment";
|
|
239974
|
-
}
|
|
239975
|
-
function coerceSizeBytes(value) {
|
|
239976
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
239977
|
-
return value;
|
|
239978
|
-
}
|
|
239979
|
-
return;
|
|
239980
|
-
}
|
|
239981
|
-
function isImageMimeType(mimeType) {
|
|
239982
|
-
return normalizeTelegramMimeType(mimeType)?.startsWith("image/") ?? false;
|
|
239983
|
-
}
|
|
239984
|
-
function canInlineTelegramImage(mimeType) {
|
|
239985
|
-
const normalized = normalizeTelegramMimeType(mimeType);
|
|
239986
|
-
return !!normalized && normalized.startsWith("image/") && normalized !== "image/svg+xml";
|
|
239987
|
-
}
|
|
239988
|
-
function isAudioMimeType(mimeType) {
|
|
239989
|
-
return normalizeTelegramMimeType(mimeType)?.startsWith("audio/") ?? false;
|
|
239990
|
-
}
|
|
239991
|
-
function isVideoMimeType(mimeType) {
|
|
239992
|
-
return normalizeTelegramMimeType(mimeType)?.startsWith("video/") ?? false;
|
|
239993
|
-
}
|
|
239994
|
-
function isGenericTelegramMimeType(mimeType) {
|
|
239995
|
-
const normalized = normalizeTelegramMimeType(mimeType);
|
|
239996
|
-
return !normalized || normalized === "application/octet-stream";
|
|
239997
|
-
}
|
|
239998
|
-
function inferAttachmentKind(params) {
|
|
239999
|
-
if (isImageMimeType(params.mimeType)) {
|
|
240000
|
-
return "image";
|
|
240001
|
-
}
|
|
240002
|
-
if (isAudioMimeType(params.mimeType)) {
|
|
240003
|
-
return "audio";
|
|
240004
|
-
}
|
|
240005
|
-
if (isVideoMimeType(params.mimeType)) {
|
|
240006
|
-
return "video";
|
|
240007
|
-
}
|
|
240008
|
-
const lowerName = params.fileName?.toLowerCase();
|
|
240009
|
-
if (lowerName) {
|
|
240010
|
-
const extension = extname6(lowerName);
|
|
240011
|
-
if (IMAGE_EXTENSIONS3.has(extension) || STATIC_STICKER_EXTENSIONS.has(extension)) {
|
|
240012
|
-
return "image";
|
|
240013
|
-
}
|
|
240014
|
-
if (AUDIO_EXTENSIONS.has(extension) || VOICE_EXTENSIONS.has(extension)) {
|
|
240015
|
-
return "audio";
|
|
240016
|
-
}
|
|
240017
|
-
if (VIDEO_EXTENSIONS.has(extension) || ANIMATION_EXTENSIONS.has(extension)) {
|
|
240018
|
-
return "video";
|
|
240019
|
-
}
|
|
240020
|
-
}
|
|
240021
|
-
return params.fallback;
|
|
240022
|
-
}
|
|
239577
|
+
// src/channels/telegram/message-shapes.ts
|
|
240023
239578
|
function extractTelegramMessageText(message) {
|
|
240024
239579
|
if (typeof message.text === "string") {
|
|
240025
239580
|
return message.text;
|
|
@@ -240035,351 +239590,8 @@ function getTelegramSenderName(message) {
|
|
|
240035
239590
|
}
|
|
240036
239591
|
return message.from.username ?? ([message.from.first_name, message.from.last_name].filter(Boolean).join(" ") || undefined);
|
|
240037
239592
|
}
|
|
240038
|
-
function collectTelegramAttachmentCandidates(message) {
|
|
240039
|
-
const attachments = [];
|
|
240040
|
-
if (Array.isArray(message.photo) && message.photo.length > 0) {
|
|
240041
|
-
const photo = message.photo[message.photo.length - 1];
|
|
240042
|
-
if (photo?.file_id) {
|
|
240043
|
-
attachments.push({
|
|
240044
|
-
fileId: photo.file_id,
|
|
240045
|
-
kind: "image",
|
|
240046
|
-
name: `photo-${photo.file_unique_id ?? photo.file_id}.jpg`,
|
|
240047
|
-
mimeType: "image/jpeg",
|
|
240048
|
-
sizeBytes: coerceSizeBytes(photo.file_size)
|
|
240049
|
-
});
|
|
240050
|
-
}
|
|
240051
|
-
}
|
|
240052
|
-
if (message.document?.file_id) {
|
|
240053
|
-
attachments.push({
|
|
240054
|
-
fileId: message.document.file_id,
|
|
240055
|
-
kind: inferAttachmentKind({
|
|
240056
|
-
mimeType: message.document.mime_type,
|
|
240057
|
-
fileName: message.document.file_name,
|
|
240058
|
-
fallback: "file"
|
|
240059
|
-
}),
|
|
240060
|
-
name: message.document.file_name,
|
|
240061
|
-
mimeType: message.document.mime_type,
|
|
240062
|
-
sizeBytes: coerceSizeBytes(message.document.file_size)
|
|
240063
|
-
});
|
|
240064
|
-
}
|
|
240065
|
-
if (message.video?.file_id) {
|
|
240066
|
-
attachments.push({
|
|
240067
|
-
fileId: message.video.file_id,
|
|
240068
|
-
kind: "video",
|
|
240069
|
-
name: message.video.file_name ?? `video-${message.video.file_unique_id ?? message.video.file_id}.mp4`,
|
|
240070
|
-
mimeType: message.video.mime_type,
|
|
240071
|
-
sizeBytes: coerceSizeBytes(message.video.file_size)
|
|
240072
|
-
});
|
|
240073
|
-
}
|
|
240074
|
-
if (message.audio?.file_id) {
|
|
240075
|
-
attachments.push({
|
|
240076
|
-
fileId: message.audio.file_id,
|
|
240077
|
-
kind: "audio",
|
|
240078
|
-
name: message.audio.file_name ?? `audio-${message.audio.file_unique_id ?? message.audio.file_id}.mp3`,
|
|
240079
|
-
mimeType: message.audio.mime_type,
|
|
240080
|
-
sizeBytes: coerceSizeBytes(message.audio.file_size)
|
|
240081
|
-
});
|
|
240082
|
-
}
|
|
240083
|
-
if (message.voice?.file_id) {
|
|
240084
|
-
attachments.push({
|
|
240085
|
-
fileId: message.voice.file_id,
|
|
240086
|
-
kind: "audio",
|
|
240087
|
-
name: `voice-${message.voice.file_unique_id ?? message.voice.file_id}.ogg`,
|
|
240088
|
-
mimeType: message.voice.mime_type,
|
|
240089
|
-
sizeBytes: coerceSizeBytes(message.voice.file_size),
|
|
240090
|
-
isVoice: true
|
|
240091
|
-
});
|
|
240092
|
-
}
|
|
240093
|
-
if (message.animation?.file_id) {
|
|
240094
|
-
attachments.push({
|
|
240095
|
-
fileId: message.animation.file_id,
|
|
240096
|
-
kind: "video",
|
|
240097
|
-
name: message.animation.file_name ?? `animation-${message.animation.file_unique_id ?? message.animation.file_id}.gif`,
|
|
240098
|
-
mimeType: message.animation.mime_type,
|
|
240099
|
-
sizeBytes: coerceSizeBytes(message.animation.file_size)
|
|
240100
|
-
});
|
|
240101
|
-
}
|
|
240102
|
-
if (message.sticker?.file_id && !message.sticker.is_animated && !message.sticker.is_video) {
|
|
240103
|
-
attachments.push({
|
|
240104
|
-
fileId: message.sticker.file_id,
|
|
240105
|
-
kind: "image",
|
|
240106
|
-
name: `sticker-${message.sticker.file_unique_id ?? message.sticker.file_id}.webp`,
|
|
240107
|
-
mimeType: message.sticker.mime_type ?? "image/webp",
|
|
240108
|
-
sizeBytes: coerceSizeBytes(message.sticker.file_size)
|
|
240109
|
-
});
|
|
240110
|
-
}
|
|
240111
|
-
return attachments;
|
|
240112
|
-
}
|
|
240113
|
-
function inferUploadMethodFromMimeType(mimeType) {
|
|
240114
|
-
const normalized = normalizeTelegramMimeType(mimeType);
|
|
240115
|
-
if (!normalized) {
|
|
240116
|
-
return null;
|
|
240117
|
-
}
|
|
240118
|
-
if (["image/png", "image/jpeg"].includes(normalized)) {
|
|
240119
|
-
return "photo";
|
|
240120
|
-
}
|
|
240121
|
-
if (normalized === "image/gif") {
|
|
240122
|
-
return "animation";
|
|
240123
|
-
}
|
|
240124
|
-
if (normalized === "image/webp") {
|
|
240125
|
-
return "document";
|
|
240126
|
-
}
|
|
240127
|
-
if (normalized.startsWith("video/")) {
|
|
240128
|
-
return "video";
|
|
240129
|
-
}
|
|
240130
|
-
if (["audio/ogg", "audio/opus"].includes(normalized)) {
|
|
240131
|
-
return "voice";
|
|
240132
|
-
}
|
|
240133
|
-
if (normalized.startsWith("audio/")) {
|
|
240134
|
-
return "audio";
|
|
240135
|
-
}
|
|
240136
|
-
return null;
|
|
240137
|
-
}
|
|
240138
|
-
function detectTelegramUploadMethod(filePath, fileName) {
|
|
240139
|
-
const inferredName = (fileName ?? basename13(filePath)).toLowerCase();
|
|
240140
|
-
const extension = extname6(inferredName);
|
|
240141
|
-
const mimeType = inferMimeTypeFromName(inferredName);
|
|
240142
|
-
const byMimeType = inferUploadMethodFromMimeType(mimeType);
|
|
240143
|
-
if (byMimeType) {
|
|
240144
|
-
return byMimeType;
|
|
240145
|
-
}
|
|
240146
|
-
if (ANIMATION_EXTENSIONS.has(extension)) {
|
|
240147
|
-
return "animation";
|
|
240148
|
-
}
|
|
240149
|
-
if (VIDEO_EXTENSIONS.has(extension)) {
|
|
240150
|
-
return "video";
|
|
240151
|
-
}
|
|
240152
|
-
if (VOICE_EXTENSIONS.has(extension)) {
|
|
240153
|
-
return "voice";
|
|
240154
|
-
}
|
|
240155
|
-
if (AUDIO_EXTENSIONS.has(extension)) {
|
|
240156
|
-
return "audio";
|
|
240157
|
-
}
|
|
240158
|
-
return "document";
|
|
240159
|
-
}
|
|
240160
|
-
function inferMimeTypeFromName(name) {
|
|
240161
|
-
const normalized = name.toLowerCase();
|
|
240162
|
-
const extension = extname6(normalized);
|
|
240163
|
-
if (IMAGE_EXTENSIONS3.has(extension)) {
|
|
240164
|
-
return extension === ".png" ? "image/png" : "image/jpeg";
|
|
240165
|
-
}
|
|
240166
|
-
if (ANIMATION_EXTENSIONS.has(extension)) {
|
|
240167
|
-
return "image/gif";
|
|
240168
|
-
}
|
|
240169
|
-
if (STATIC_STICKER_EXTENSIONS.has(extension)) {
|
|
240170
|
-
return "image/webp";
|
|
240171
|
-
}
|
|
240172
|
-
if (extension === ".mp4" || extension === ".m4v") {
|
|
240173
|
-
return "video/mp4";
|
|
240174
|
-
}
|
|
240175
|
-
if (extension === ".mov") {
|
|
240176
|
-
return "video/quicktime";
|
|
240177
|
-
}
|
|
240178
|
-
if (extension === ".webm") {
|
|
240179
|
-
return "video/webm";
|
|
240180
|
-
}
|
|
240181
|
-
if (extension === ".mp3") {
|
|
240182
|
-
return "audio/mpeg";
|
|
240183
|
-
}
|
|
240184
|
-
if (extension === ".m4a") {
|
|
240185
|
-
return "audio/mp4";
|
|
240186
|
-
}
|
|
240187
|
-
if (extension === ".wav") {
|
|
240188
|
-
return "audio/wav";
|
|
240189
|
-
}
|
|
240190
|
-
if (VOICE_EXTENSIONS.has(extension)) {
|
|
240191
|
-
return "audio/ogg";
|
|
240192
|
-
}
|
|
240193
|
-
if (extension === ".pdf") {
|
|
240194
|
-
return "application/pdf";
|
|
240195
|
-
}
|
|
240196
|
-
if (extension === ".txt") {
|
|
240197
|
-
return "text/plain";
|
|
240198
|
-
}
|
|
240199
|
-
if (extension === ".md") {
|
|
240200
|
-
return "text/markdown";
|
|
240201
|
-
}
|
|
240202
|
-
if (extension === ".json") {
|
|
240203
|
-
return "application/json";
|
|
240204
|
-
}
|
|
240205
|
-
return;
|
|
240206
|
-
}
|
|
240207
|
-
function extensionForMimeType(mimeType) {
|
|
240208
|
-
switch (normalizeTelegramMimeType(mimeType)) {
|
|
240209
|
-
case "image/png":
|
|
240210
|
-
return ".png";
|
|
240211
|
-
case "image/jpeg":
|
|
240212
|
-
return ".jpg";
|
|
240213
|
-
case "image/gif":
|
|
240214
|
-
return ".gif";
|
|
240215
|
-
case "image/webp":
|
|
240216
|
-
return ".webp";
|
|
240217
|
-
case "video/mp4":
|
|
240218
|
-
return ".mp4";
|
|
240219
|
-
case "video/quicktime":
|
|
240220
|
-
return ".mov";
|
|
240221
|
-
case "video/webm":
|
|
240222
|
-
return ".webm";
|
|
240223
|
-
case "audio/mpeg":
|
|
240224
|
-
return ".mp3";
|
|
240225
|
-
case "audio/mp4":
|
|
240226
|
-
return ".m4a";
|
|
240227
|
-
case "audio/wav":
|
|
240228
|
-
case "audio/x-wav":
|
|
240229
|
-
case "audio/wave":
|
|
240230
|
-
return ".wav";
|
|
240231
|
-
case "audio/ogg":
|
|
240232
|
-
case "audio/opus":
|
|
240233
|
-
return ".ogg";
|
|
240234
|
-
case "application/pdf":
|
|
240235
|
-
return ".pdf";
|
|
240236
|
-
case "text/plain":
|
|
240237
|
-
return ".txt";
|
|
240238
|
-
case "text/markdown":
|
|
240239
|
-
return ".md";
|
|
240240
|
-
case "application/json":
|
|
240241
|
-
return ".json";
|
|
240242
|
-
default:
|
|
240243
|
-
return "";
|
|
240244
|
-
}
|
|
240245
|
-
}
|
|
240246
|
-
function buildTelegramFileUrl(token2, filePath) {
|
|
240247
|
-
return `https://api.telegram.org/file/bot${token2}/${filePath}`;
|
|
240248
|
-
}
|
|
240249
|
-
function inferAttachmentFileName(params) {
|
|
240250
|
-
const hintedName = params.candidate.name?.trim() || basename13(params.remotePath) || "attachment";
|
|
240251
|
-
if (extname6(hintedName)) {
|
|
240252
|
-
return hintedName;
|
|
240253
|
-
}
|
|
240254
|
-
const extension = extensionForMimeType(params.responseMimeType) || extensionForMimeType(params.candidate.mimeType);
|
|
240255
|
-
return extension ? `${hintedName}${extension}` : hintedName;
|
|
240256
|
-
}
|
|
240257
|
-
async function saveTelegramAttachment(params) {
|
|
240258
|
-
const inboundDir = join42(getChannelDir("telegram"), "inbound", sanitizeTelegramPathSegment(params.accountId));
|
|
240259
|
-
await mkdir8(inboundDir, { recursive: true });
|
|
240260
|
-
const filePath = join42(inboundDir, `${Date.now()}-${randomUUID12()}-${sanitizeTelegramPathSegment(params.fileName)}`);
|
|
240261
|
-
await writeFile10(filePath, params.buffer);
|
|
240262
|
-
return filePath;
|
|
240263
|
-
}
|
|
240264
|
-
async function fetchTelegramFile(url2, timeoutMs) {
|
|
240265
|
-
const controller = new AbortController;
|
|
240266
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
240267
|
-
try {
|
|
240268
|
-
return await fetch(url2, { signal: controller.signal });
|
|
240269
|
-
} finally {
|
|
240270
|
-
clearTimeout(timeout);
|
|
240271
|
-
}
|
|
240272
|
-
}
|
|
240273
|
-
async function downloadTelegramAttachment(params) {
|
|
240274
|
-
const { candidate } = params;
|
|
240275
|
-
if (typeof candidate.sizeBytes === "number" && candidate.sizeBytes > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240276
|
-
console.warn(`[Telegram] Skipping attachment ${candidate.name ?? candidate.fileId}: ${candidate.sizeBytes} bytes exceeds Telegram download limit (${MAX_TELEGRAM_DOWNLOAD_BYTES} bytes).`);
|
|
240277
|
-
return null;
|
|
240278
|
-
}
|
|
240279
|
-
const file3 = await params.bot.api.getFile(candidate.fileId);
|
|
240280
|
-
const remotePath = file3.file_path;
|
|
240281
|
-
if (!remotePath) {
|
|
240282
|
-
console.warn(`[Telegram] getFile returned no file_path for attachment ${candidate.name ?? candidate.fileId}.`);
|
|
240283
|
-
return null;
|
|
240284
|
-
}
|
|
240285
|
-
const response = await fetchTelegramFile(buildTelegramFileUrl(params.token, remotePath), TELEGRAM_DOWNLOAD_TIMEOUT_MS);
|
|
240286
|
-
if (!response.ok) {
|
|
240287
|
-
console.warn(`[Telegram] Failed to download attachment ${candidate.name ?? candidate.fileId} from ${remotePath}: ${response.status} ${response.statusText}`);
|
|
240288
|
-
return null;
|
|
240289
|
-
}
|
|
240290
|
-
const contentLength = response.headers.get("content-length");
|
|
240291
|
-
if (contentLength) {
|
|
240292
|
-
const parsedLength = Number(contentLength);
|
|
240293
|
-
if (Number.isFinite(parsedLength) && parsedLength > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240294
|
-
console.warn(`[Telegram] Refusing attachment ${candidate.name ?? candidate.fileId}: content-length ${parsedLength} exceeds limit ${MAX_TELEGRAM_DOWNLOAD_BYTES}.`);
|
|
240295
|
-
return null;
|
|
240296
|
-
}
|
|
240297
|
-
}
|
|
240298
|
-
const buffer = Buffer.from(await response.arrayBuffer());
|
|
240299
|
-
if (buffer.byteLength > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240300
|
-
console.warn(`[Telegram] Refusing attachment ${candidate.name ?? candidate.fileId}: downloaded size ${buffer.byteLength} exceeds limit ${MAX_TELEGRAM_DOWNLOAD_BYTES}.`);
|
|
240301
|
-
return null;
|
|
240302
|
-
}
|
|
240303
|
-
const responseMimeType = normalizeTelegramMimeType(response.headers.get("content-type") ?? undefined);
|
|
240304
|
-
const fileName = inferAttachmentFileName({
|
|
240305
|
-
candidate,
|
|
240306
|
-
remotePath,
|
|
240307
|
-
responseMimeType
|
|
240308
|
-
});
|
|
240309
|
-
const candidateMimeType = normalizeTelegramMimeType(candidate.mimeType);
|
|
240310
|
-
const mimeType = (isGenericTelegramMimeType(responseMimeType) ? candidateMimeType : responseMimeType) ?? inferMimeTypeFromName(fileName);
|
|
240311
|
-
const kind = inferAttachmentKind({
|
|
240312
|
-
mimeType,
|
|
240313
|
-
fileName,
|
|
240314
|
-
fallback: candidate.kind
|
|
240315
|
-
});
|
|
240316
|
-
const localPath = await saveTelegramAttachment({
|
|
240317
|
-
accountId: params.accountId,
|
|
240318
|
-
fileName,
|
|
240319
|
-
buffer
|
|
240320
|
-
});
|
|
240321
|
-
const attachment = {
|
|
240322
|
-
id: candidate.fileId,
|
|
240323
|
-
name: fileName,
|
|
240324
|
-
mimeType,
|
|
240325
|
-
sizeBytes: buffer.byteLength,
|
|
240326
|
-
kind,
|
|
240327
|
-
localPath,
|
|
240328
|
-
...kind === "image" && canInlineTelegramImage(mimeType) && buffer.byteLength <= MAX_TELEGRAM_INLINE_IMAGE_BYTES ? { imageDataBase64: buffer.toString("base64") } : {}
|
|
240329
|
-
};
|
|
240330
|
-
if (candidate.isVoice && params.transcribeVoice) {
|
|
240331
|
-
const { isTranscriptionConfigured: isTranscriptionConfigured2, transcribeAudioFile: transcribeAudioFile2 } = await Promise.resolve().then(() => (init_transcription(), exports_transcription));
|
|
240332
|
-
if (isTranscriptionConfigured2()) {
|
|
240333
|
-
const result2 = await transcribeAudioFile2(localPath);
|
|
240334
|
-
if (result2.success && result2.text) {
|
|
240335
|
-
attachment.transcription = result2.text;
|
|
240336
|
-
} else if (result2.error) {
|
|
240337
|
-
attachment.transcriptionError = result2.error;
|
|
240338
|
-
console.warn(`[Telegram] Voice transcription failed for ${fileName}:`, result2.error);
|
|
240339
|
-
}
|
|
240340
|
-
} else {
|
|
240341
|
-
attachment.transcriptionError = "OPENAI_API_KEY not set; transcription skipped.";
|
|
240342
|
-
}
|
|
240343
|
-
}
|
|
240344
|
-
return attachment;
|
|
240345
|
-
}
|
|
240346
|
-
async function resolveTelegramInboundAttachments(params) {
|
|
240347
|
-
const deduped = new Map;
|
|
240348
|
-
for (const message of params.messages) {
|
|
240349
|
-
for (const candidate of collectTelegramAttachmentCandidates(message)) {
|
|
240350
|
-
deduped.set(candidate.fileId, candidate);
|
|
240351
|
-
}
|
|
240352
|
-
}
|
|
240353
|
-
if (deduped.size === 0) {
|
|
240354
|
-
return [];
|
|
240355
|
-
}
|
|
240356
|
-
const resolved = await Promise.all(Array.from(deduped.values()).map((candidate) => downloadTelegramAttachment({
|
|
240357
|
-
accountId: params.accountId,
|
|
240358
|
-
token: params.token,
|
|
240359
|
-
bot: params.bot,
|
|
240360
|
-
candidate,
|
|
240361
|
-
transcribeVoice: params.transcribeVoice
|
|
240362
|
-
}).catch((error54) => {
|
|
240363
|
-
const message = error54 instanceof Error ? error54.message : String(error54);
|
|
240364
|
-
console.warn(`[Telegram] Attachment download failed for ${candidate.name ?? candidate.fileId}: ${message}`);
|
|
240365
|
-
return null;
|
|
240366
|
-
})));
|
|
240367
|
-
return resolved.filter((attachment) => Boolean(attachment));
|
|
240368
|
-
}
|
|
240369
|
-
var TELEGRAM_MEDIA_GROUP_FLUSH_MS = 150, TELEGRAM_DOWNLOAD_TIMEOUT_MS = 15000, MAX_TELEGRAM_DOWNLOAD_BYTES, MAX_TELEGRAM_INLINE_IMAGE_BYTES, IMAGE_EXTENSIONS3, ANIMATION_EXTENSIONS, VIDEO_EXTENSIONS, AUDIO_EXTENSIONS, VOICE_EXTENSIONS, STATIC_STICKER_EXTENSIONS;
|
|
240370
|
-
var init_media = __esm(() => {
|
|
240371
|
-
init_config2();
|
|
240372
|
-
MAX_TELEGRAM_DOWNLOAD_BYTES = 50 * 1024 * 1024;
|
|
240373
|
-
MAX_TELEGRAM_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
240374
|
-
IMAGE_EXTENSIONS3 = new Set([".png", ".jpg", ".jpeg"]);
|
|
240375
|
-
ANIMATION_EXTENSIONS = new Set([".gif"]);
|
|
240376
|
-
VIDEO_EXTENSIONS = new Set([".mp4", ".m4v", ".mov", ".webm"]);
|
|
240377
|
-
AUDIO_EXTENSIONS = new Set([".mp3", ".m4a", ".wav"]);
|
|
240378
|
-
VOICE_EXTENSIONS = new Set([".ogg", ".oga", ".opus"]);
|
|
240379
|
-
STATIC_STICKER_EXTENSIONS = new Set([".webp"]);
|
|
240380
|
-
});
|
|
240381
239593
|
|
|
240382
|
-
// src/channels/telegram/
|
|
239594
|
+
// src/channels/telegram/ingress.ts
|
|
240383
239595
|
function escapeRegExp3(value) {
|
|
240384
239596
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
240385
239597
|
}
|
|
@@ -240418,20 +239630,98 @@ function detectTelegramBotMention(message, botUsername, botDisplayName, text2 =
|
|
|
240418
239630
|
text: leadingNameRegex ? stripped.replace(leadingNameRegex, "").trimStart() : stripped.trimStart()
|
|
240419
239631
|
};
|
|
240420
239632
|
}
|
|
240421
|
-
function
|
|
240422
|
-
|
|
240423
|
-
|
|
240424
|
-
|
|
239633
|
+
function getTelegramChatType(chat2) {
|
|
239634
|
+
return !chat2.type || chat2.type === "private" ? "direct" : "channel";
|
|
239635
|
+
}
|
|
239636
|
+
function getTelegramChatLabel(message) {
|
|
239637
|
+
const title = message.chat.title?.trim();
|
|
239638
|
+
if (title) {
|
|
239639
|
+
return title;
|
|
240425
239640
|
}
|
|
240426
|
-
|
|
239641
|
+
const username = message.chat.username?.trim();
|
|
239642
|
+
if (username) {
|
|
239643
|
+
return username.startsWith("@") ? username : `@${username}`;
|
|
239644
|
+
}
|
|
239645
|
+
return;
|
|
240427
239646
|
}
|
|
240428
|
-
function
|
|
240429
|
-
|
|
240430
|
-
|
|
240431
|
-
|
|
239647
|
+
function getTelegramMessageThreadId(message) {
|
|
239648
|
+
return message.message_thread_id !== undefined ? String(message.message_thread_id) : null;
|
|
239649
|
+
}
|
|
239650
|
+
function getTelegramReplyContext(message) {
|
|
239651
|
+
const replied = message.reply_to_message;
|
|
239652
|
+
if (!replied) {
|
|
239653
|
+
return;
|
|
240432
239654
|
}
|
|
240433
|
-
|
|
239655
|
+
const text2 = extractTelegramMessageText(replied).trim();
|
|
239656
|
+
const context3 = {
|
|
239657
|
+
messageId: String(replied.message_id)
|
|
239658
|
+
};
|
|
239659
|
+
if (replied.from?.id !== undefined) {
|
|
239660
|
+
context3.senderId = String(replied.from.id);
|
|
239661
|
+
}
|
|
239662
|
+
const senderName = getTelegramSenderName(replied);
|
|
239663
|
+
if (senderName) {
|
|
239664
|
+
context3.senderName = senderName;
|
|
239665
|
+
}
|
|
239666
|
+
if (text2) {
|
|
239667
|
+
context3.text = text2;
|
|
239668
|
+
}
|
|
239669
|
+
return context3;
|
|
239670
|
+
}
|
|
239671
|
+
function getTelegramReactionToken(reaction) {
|
|
239672
|
+
switch (reaction.type) {
|
|
239673
|
+
case "emoji":
|
|
239674
|
+
return reaction.emoji?.trim() || null;
|
|
239675
|
+
case "custom_emoji":
|
|
239676
|
+
return reaction.custom_emoji_id?.trim() ? `custom_emoji:${reaction.custom_emoji_id.trim()}` : null;
|
|
239677
|
+
case "paid":
|
|
239678
|
+
return "paid";
|
|
239679
|
+
default:
|
|
239680
|
+
return null;
|
|
239681
|
+
}
|
|
239682
|
+
}
|
|
239683
|
+
function getTelegramReactionSenderName(update3) {
|
|
239684
|
+
if (update3.user) {
|
|
239685
|
+
return getTelegramSenderName({
|
|
239686
|
+
from: update3.user
|
|
239687
|
+
});
|
|
239688
|
+
}
|
|
239689
|
+
if (update3.actor_chat?.username?.trim()) {
|
|
239690
|
+
return update3.actor_chat.username.trim();
|
|
239691
|
+
}
|
|
239692
|
+
if (update3.actor_chat?.title?.trim()) {
|
|
239693
|
+
return update3.actor_chat.title.trim();
|
|
239694
|
+
}
|
|
239695
|
+
return;
|
|
240434
239696
|
}
|
|
239697
|
+
function getTelegramReactionSenderId(update3) {
|
|
239698
|
+
if (update3.user?.id !== undefined) {
|
|
239699
|
+
return String(update3.user.id);
|
|
239700
|
+
}
|
|
239701
|
+
if (update3.actor_chat?.id !== undefined) {
|
|
239702
|
+
return String(update3.actor_chat.id);
|
|
239703
|
+
}
|
|
239704
|
+
return null;
|
|
239705
|
+
}
|
|
239706
|
+
function diffTelegramReactionUpdate(update3) {
|
|
239707
|
+
const oldTokens = new Set(update3.old_reaction.map((reaction) => getTelegramReactionToken(reaction)).filter((value) => typeof value === "string"));
|
|
239708
|
+
const newTokens = new Set(update3.new_reaction.map((reaction) => getTelegramReactionToken(reaction)).filter((value) => typeof value === "string"));
|
|
239709
|
+
const events = [];
|
|
239710
|
+
for (const emoji3 of oldTokens) {
|
|
239711
|
+
if (!newTokens.has(emoji3)) {
|
|
239712
|
+
events.push({ action: "removed", emoji: emoji3 });
|
|
239713
|
+
}
|
|
239714
|
+
}
|
|
239715
|
+
for (const emoji3 of newTokens) {
|
|
239716
|
+
if (!oldTokens.has(emoji3)) {
|
|
239717
|
+
events.push({ action: "added", emoji: emoji3 });
|
|
239718
|
+
}
|
|
239719
|
+
}
|
|
239720
|
+
return events;
|
|
239721
|
+
}
|
|
239722
|
+
var init_ingress = () => {};
|
|
239723
|
+
|
|
239724
|
+
// src/channels/telegram/outbound.ts
|
|
240435
239725
|
function resolveTelegramOutboundThreadId(msg) {
|
|
240436
239726
|
return msg.threadId?.trim() || null;
|
|
240437
239727
|
}
|
|
@@ -240545,18 +239835,6 @@ function shouldFallbackTelegramRichMessage(error54) {
|
|
|
240545
239835
|
}
|
|
240546
239836
|
return mentionsRichMessage && text2.includes("bad request");
|
|
240547
239837
|
}
|
|
240548
|
-
function getTelegramReactionToken(reaction) {
|
|
240549
|
-
switch (reaction.type) {
|
|
240550
|
-
case "emoji":
|
|
240551
|
-
return reaction.emoji?.trim() || null;
|
|
240552
|
-
case "custom_emoji":
|
|
240553
|
-
return reaction.custom_emoji_id?.trim() ? `custom_emoji:${reaction.custom_emoji_id.trim()}` : null;
|
|
240554
|
-
case "paid":
|
|
240555
|
-
return "paid";
|
|
240556
|
-
default:
|
|
240557
|
-
return null;
|
|
240558
|
-
}
|
|
240559
|
-
}
|
|
240560
239838
|
function parseTelegramReactionInput(reaction) {
|
|
240561
239839
|
const trimmed = reaction.trim();
|
|
240562
239840
|
if (!trimmed) {
|
|
@@ -240578,66 +239856,21 @@ function parseTelegramReactionInput(reaction) {
|
|
|
240578
239856
|
emoji: trimmed
|
|
240579
239857
|
};
|
|
240580
239858
|
}
|
|
240581
|
-
|
|
240582
|
-
|
|
240583
|
-
|
|
240584
|
-
|
|
240585
|
-
|
|
240586
|
-
|
|
240587
|
-
if (update3.actor_chat?.username?.trim()) {
|
|
240588
|
-
return update3.actor_chat.username.trim();
|
|
240589
|
-
}
|
|
240590
|
-
if (update3.actor_chat?.title?.trim()) {
|
|
240591
|
-
return update3.actor_chat.title.trim();
|
|
240592
|
-
}
|
|
240593
|
-
return;
|
|
240594
|
-
}
|
|
240595
|
-
function getTelegramReactionSenderId(update3) {
|
|
240596
|
-
if (update3.user?.id !== undefined) {
|
|
240597
|
-
return String(update3.user.id);
|
|
240598
|
-
}
|
|
240599
|
-
if (update3.actor_chat?.id !== undefined) {
|
|
240600
|
-
return String(update3.actor_chat.id);
|
|
240601
|
-
}
|
|
240602
|
-
return null;
|
|
240603
|
-
}
|
|
240604
|
-
function getTelegramChatType(chat2) {
|
|
240605
|
-
return !chat2.type || chat2.type === "private" ? "direct" : "channel";
|
|
240606
|
-
}
|
|
240607
|
-
function getTelegramChatLabel(message) {
|
|
240608
|
-
const title = message.chat.title?.trim();
|
|
240609
|
-
if (title) {
|
|
240610
|
-
return title;
|
|
240611
|
-
}
|
|
240612
|
-
const username = message.chat.username?.trim();
|
|
240613
|
-
if (username) {
|
|
240614
|
-
return username.startsWith("@") ? username : `@${username}`;
|
|
239859
|
+
|
|
239860
|
+
// src/channels/telegram/utils.ts
|
|
239861
|
+
function resolveTelegramBotConstructor(mod) {
|
|
239862
|
+
const Bot = mod.Bot ?? mod.default?.Bot;
|
|
239863
|
+
if (!Bot) {
|
|
239864
|
+
throw new Error('Installed Telegram runtime did not export "Bot".');
|
|
240615
239865
|
}
|
|
240616
|
-
return;
|
|
240617
|
-
}
|
|
240618
|
-
function getTelegramMessageThreadId(message) {
|
|
240619
|
-
return message.message_thread_id !== undefined ? String(message.message_thread_id) : null;
|
|
239866
|
+
return Bot;
|
|
240620
239867
|
}
|
|
240621
|
-
function
|
|
240622
|
-
const
|
|
240623
|
-
if (!
|
|
240624
|
-
|
|
240625
|
-
}
|
|
240626
|
-
const text2 = extractTelegramMessageText(replied).trim();
|
|
240627
|
-
const context3 = {
|
|
240628
|
-
messageId: String(replied.message_id)
|
|
240629
|
-
};
|
|
240630
|
-
if (replied.from?.id !== undefined) {
|
|
240631
|
-
context3.senderId = String(replied.from.id);
|
|
240632
|
-
}
|
|
240633
|
-
const senderName = getTelegramSenderName(replied);
|
|
240634
|
-
if (senderName) {
|
|
240635
|
-
context3.senderName = senderName;
|
|
240636
|
-
}
|
|
240637
|
-
if (text2) {
|
|
240638
|
-
context3.text = text2;
|
|
239868
|
+
function resolveTelegramInputFileConstructor(mod) {
|
|
239869
|
+
const InputFile = mod.InputFile ?? mod.default?.InputFile;
|
|
239870
|
+
if (!InputFile) {
|
|
239871
|
+
throw new Error('Installed Telegram runtime did not export "InputFile".');
|
|
240639
239872
|
}
|
|
240640
|
-
return
|
|
239873
|
+
return InputFile;
|
|
240641
239874
|
}
|
|
240642
239875
|
function getTelegramLifecycleErrorReplyKey(source2) {
|
|
240643
239876
|
if (source2.channel !== "telegram" || !source2.chatId) {
|
|
@@ -240658,7 +239891,7 @@ function formatTelegramLifecycleErrorMessage(errorText, runId) {
|
|
|
240658
239891
|
var TELEGRAM_LIFECYCLE_ERROR_TEXT_MAX = 3500, TELEGRAM_LIFECYCLE_ERROR_DEDUPE_TTL_MS, TELEGRAM_LIFECYCLE_ERROR_DEDUPE_MAX = 1000, TELEGRAM_LIFECYCLE_ERROR_REPORT_TTL_MS, TELEGRAM_LIFECYCLE_ERROR_REPORT_MAX = 1000, TELEGRAM_REPORT_CALLBACK_PREFIX = "lc_report:", TELEGRAM_TYPING_REFRESH_MS = 4000, TELEGRAM_TYPING_MAX_MS;
|
|
240659
239892
|
var init_utils5 = __esm(() => {
|
|
240660
239893
|
init_lifecycle_error();
|
|
240661
|
-
|
|
239894
|
+
init_ingress();
|
|
240662
239895
|
TELEGRAM_LIFECYCLE_ERROR_DEDUPE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
240663
239896
|
TELEGRAM_LIFECYCLE_ERROR_REPORT_TTL_MS = 6 * 60 * 60 * 1000;
|
|
240664
239897
|
TELEGRAM_TYPING_MAX_MS = 6 * 60 * 60 * 1000;
|
|
@@ -241271,7 +240504,7 @@ var init_lifecycle_error_report = __esm(() => {
|
|
|
241271
240504
|
|
|
241272
240505
|
// src/channels/telegram/debounce.ts
|
|
241273
240506
|
function resolveTelegramInboundDebounceMs(config3) {
|
|
241274
|
-
const raw2 = process.env.LETTA_TELEGRAM_INBOUND_DEBOUNCE_MS;
|
|
240507
|
+
const raw2 = typeof process === "undefined" ? undefined : process.env.LETTA_TELEGRAM_INBOUND_DEBOUNCE_MS;
|
|
241275
240508
|
if (typeof raw2 === "string" && raw2.trim() !== "") {
|
|
241276
240509
|
const envOverride = Number(raw2);
|
|
241277
240510
|
if (Number.isFinite(envOverride) && envOverride >= 0) {
|
|
@@ -241293,6 +240526,539 @@ function buildTelegramDebounceKey(input, accountId) {
|
|
|
241293
240526
|
var TELEGRAM_DEBOUNCE_DEFAULT_MS = 0, TELEGRAM_DEBOUNCE_MAX_MS = 1e4;
|
|
241294
240527
|
var init_debounce3 = () => {};
|
|
241295
240528
|
|
|
240529
|
+
// src/channels/transcription/index.ts
|
|
240530
|
+
var exports_transcription = {};
|
|
240531
|
+
__export(exports_transcription, {
|
|
240532
|
+
transcribeAudioFile: () => transcribeAudioFile,
|
|
240533
|
+
isTranscriptionConfigured: () => isTranscriptionConfigured
|
|
240534
|
+
});
|
|
240535
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
240536
|
+
import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync22, rmSync as rmSync8 } from "node:fs";
|
|
240537
|
+
import { tmpdir as tmpdir8 } from "node:os";
|
|
240538
|
+
import { basename as basename12, extname as extname5, join as join41 } from "node:path";
|
|
240539
|
+
function audioMimeTypeForPath(localPath) {
|
|
240540
|
+
switch (extname5(localPath).toLowerCase()) {
|
|
240541
|
+
case ".flac":
|
|
240542
|
+
return "audio/flac";
|
|
240543
|
+
case ".m4a":
|
|
240544
|
+
return "audio/mp4";
|
|
240545
|
+
case ".mp3":
|
|
240546
|
+
case ".mpeg":
|
|
240547
|
+
case ".mpga":
|
|
240548
|
+
return "audio/mpeg";
|
|
240549
|
+
case ".mp4":
|
|
240550
|
+
return "video/mp4";
|
|
240551
|
+
case ".oga":
|
|
240552
|
+
case ".ogg":
|
|
240553
|
+
return "audio/ogg";
|
|
240554
|
+
case ".wav":
|
|
240555
|
+
return "audio/wav";
|
|
240556
|
+
case ".webm":
|
|
240557
|
+
return "audio/webm";
|
|
240558
|
+
default:
|
|
240559
|
+
return "audio/mp4";
|
|
240560
|
+
}
|
|
240561
|
+
}
|
|
240562
|
+
function prepareOpenAiTranscriptionFile(localPath) {
|
|
240563
|
+
if (OPENAI_SUPPORTED_AUDIO_EXTENSIONS.has(extname5(localPath).toLowerCase())) {
|
|
240564
|
+
return { localPath };
|
|
240565
|
+
}
|
|
240566
|
+
const tempDir = mkdtempSync3(join41(tmpdir8(), "letta-transcription-"));
|
|
240567
|
+
const convertedPath = join41(tempDir, `${basename12(localPath)}.m4a`);
|
|
240568
|
+
try {
|
|
240569
|
+
execFileSync4("ffmpeg", [
|
|
240570
|
+
"-y",
|
|
240571
|
+
"-loglevel",
|
|
240572
|
+
"error",
|
|
240573
|
+
"-i",
|
|
240574
|
+
localPath,
|
|
240575
|
+
"-vn",
|
|
240576
|
+
"-c:a",
|
|
240577
|
+
"aac",
|
|
240578
|
+
convertedPath
|
|
240579
|
+
], { stdio: "ignore", timeout: TRANSCRIPTION_TIMEOUT_MS });
|
|
240580
|
+
} catch (error54) {
|
|
240581
|
+
rmSync8(tempDir, { recursive: true, force: true });
|
|
240582
|
+
throw new Error(`Unsupported audio format ${extname5(localPath).replace(/^\./, "") || "unknown"}; ffmpeg conversion failed. ffmpeg is required to transcribe this audio format; install ffmpeg on the channel listener machine. ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
240583
|
+
}
|
|
240584
|
+
return {
|
|
240585
|
+
localPath: convertedPath,
|
|
240586
|
+
cleanup: () => rmSync8(tempDir, { recursive: true, force: true })
|
|
240587
|
+
};
|
|
240588
|
+
}
|
|
240589
|
+
function isTranscriptionConfigured() {
|
|
240590
|
+
return !!process.env.OPENAI_API_KEY;
|
|
240591
|
+
}
|
|
240592
|
+
async function transcribeAudioFile(localPath) {
|
|
240593
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
240594
|
+
if (!apiKey) {
|
|
240595
|
+
return {
|
|
240596
|
+
success: false,
|
|
240597
|
+
error: "OPENAI_API_KEY not set; transcription skipped."
|
|
240598
|
+
};
|
|
240599
|
+
}
|
|
240600
|
+
try {
|
|
240601
|
+
const prepared = prepareOpenAiTranscriptionFile(localPath);
|
|
240602
|
+
try {
|
|
240603
|
+
const buffer = readFileSync22(prepared.localPath);
|
|
240604
|
+
const filename = basename12(prepared.localPath);
|
|
240605
|
+
const formData = new FormData;
|
|
240606
|
+
const blob = new Blob([buffer], {
|
|
240607
|
+
type: audioMimeTypeForPath(prepared.localPath)
|
|
240608
|
+
});
|
|
240609
|
+
formData.append("file", blob, filename);
|
|
240610
|
+
formData.append("model", OPENAI_TRANSCRIPTION_MODEL);
|
|
240611
|
+
const controller = new AbortController;
|
|
240612
|
+
const timeout = setTimeout(() => controller.abort(), TRANSCRIPTION_TIMEOUT_MS);
|
|
240613
|
+
try {
|
|
240614
|
+
const response = await fetch(OPENAI_TRANSCRIPTION_API_URL, {
|
|
240615
|
+
method: "POST",
|
|
240616
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
240617
|
+
body: formData,
|
|
240618
|
+
signal: controller.signal
|
|
240619
|
+
});
|
|
240620
|
+
if (!response.ok) {
|
|
240621
|
+
const errorText = await response.text();
|
|
240622
|
+
return {
|
|
240623
|
+
success: false,
|
|
240624
|
+
error: `OpenAI transcription API error (${response.status}): ${errorText}`
|
|
240625
|
+
};
|
|
240626
|
+
}
|
|
240627
|
+
const data = await response.json();
|
|
240628
|
+
return { success: true, text: data.text };
|
|
240629
|
+
} finally {
|
|
240630
|
+
clearTimeout(timeout);
|
|
240631
|
+
}
|
|
240632
|
+
} finally {
|
|
240633
|
+
prepared.cleanup?.();
|
|
240634
|
+
}
|
|
240635
|
+
} catch (error54) {
|
|
240636
|
+
return {
|
|
240637
|
+
success: false,
|
|
240638
|
+
error: error54 instanceof Error ? error54.message : String(error54)
|
|
240639
|
+
};
|
|
240640
|
+
}
|
|
240641
|
+
}
|
|
240642
|
+
var OPENAI_TRANSCRIPTION_API_URL = "https://api.openai.com/v1/audio/transcriptions", OPENAI_TRANSCRIPTION_MODEL = "gpt-4o-transcribe", TRANSCRIPTION_TIMEOUT_MS = 30000, OPENAI_SUPPORTED_AUDIO_EXTENSIONS;
|
|
240643
|
+
var init_transcription = __esm(() => {
|
|
240644
|
+
OPENAI_SUPPORTED_AUDIO_EXTENSIONS = new Set([
|
|
240645
|
+
".flac",
|
|
240646
|
+
".m4a",
|
|
240647
|
+
".mp3",
|
|
240648
|
+
".mp4",
|
|
240649
|
+
".mpeg",
|
|
240650
|
+
".mpga",
|
|
240651
|
+
".oga",
|
|
240652
|
+
".ogg",
|
|
240653
|
+
".wav",
|
|
240654
|
+
".webm"
|
|
240655
|
+
]);
|
|
240656
|
+
});
|
|
240657
|
+
|
|
240658
|
+
// src/channels/telegram/media.ts
|
|
240659
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
240660
|
+
import { mkdir as mkdir8, writeFile as writeFile10 } from "node:fs/promises";
|
|
240661
|
+
import { basename as basename13, extname as extname6, join as join42 } from "node:path";
|
|
240662
|
+
function normalizeTelegramMimeType(mimeType) {
|
|
240663
|
+
const normalized = mimeType?.split(";")[0]?.trim().toLowerCase();
|
|
240664
|
+
return normalized || undefined;
|
|
240665
|
+
}
|
|
240666
|
+
function sanitizeTelegramPathSegment(input) {
|
|
240667
|
+
const cleaned = input.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^_+|_+$/g, "");
|
|
240668
|
+
return cleaned || "attachment";
|
|
240669
|
+
}
|
|
240670
|
+
function coerceSizeBytes(value) {
|
|
240671
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
240672
|
+
return value;
|
|
240673
|
+
}
|
|
240674
|
+
return;
|
|
240675
|
+
}
|
|
240676
|
+
function isImageMimeType(mimeType) {
|
|
240677
|
+
return normalizeTelegramMimeType(mimeType)?.startsWith("image/") ?? false;
|
|
240678
|
+
}
|
|
240679
|
+
function canInlineTelegramImage(mimeType) {
|
|
240680
|
+
const normalized = normalizeTelegramMimeType(mimeType);
|
|
240681
|
+
return !!normalized && normalized.startsWith("image/") && normalized !== "image/svg+xml";
|
|
240682
|
+
}
|
|
240683
|
+
function isAudioMimeType(mimeType) {
|
|
240684
|
+
return normalizeTelegramMimeType(mimeType)?.startsWith("audio/") ?? false;
|
|
240685
|
+
}
|
|
240686
|
+
function isVideoMimeType(mimeType) {
|
|
240687
|
+
return normalizeTelegramMimeType(mimeType)?.startsWith("video/") ?? false;
|
|
240688
|
+
}
|
|
240689
|
+
function isGenericTelegramMimeType(mimeType) {
|
|
240690
|
+
const normalized = normalizeTelegramMimeType(mimeType);
|
|
240691
|
+
return !normalized || normalized === "application/octet-stream";
|
|
240692
|
+
}
|
|
240693
|
+
function inferAttachmentKind(params) {
|
|
240694
|
+
if (isImageMimeType(params.mimeType)) {
|
|
240695
|
+
return "image";
|
|
240696
|
+
}
|
|
240697
|
+
if (isAudioMimeType(params.mimeType)) {
|
|
240698
|
+
return "audio";
|
|
240699
|
+
}
|
|
240700
|
+
if (isVideoMimeType(params.mimeType)) {
|
|
240701
|
+
return "video";
|
|
240702
|
+
}
|
|
240703
|
+
const lowerName = params.fileName?.toLowerCase();
|
|
240704
|
+
if (lowerName) {
|
|
240705
|
+
const extension = extname6(lowerName);
|
|
240706
|
+
if (IMAGE_EXTENSIONS3.has(extension) || STATIC_STICKER_EXTENSIONS.has(extension)) {
|
|
240707
|
+
return "image";
|
|
240708
|
+
}
|
|
240709
|
+
if (AUDIO_EXTENSIONS.has(extension) || VOICE_EXTENSIONS.has(extension)) {
|
|
240710
|
+
return "audio";
|
|
240711
|
+
}
|
|
240712
|
+
if (VIDEO_EXTENSIONS.has(extension) || ANIMATION_EXTENSIONS.has(extension)) {
|
|
240713
|
+
return "video";
|
|
240714
|
+
}
|
|
240715
|
+
}
|
|
240716
|
+
return params.fallback;
|
|
240717
|
+
}
|
|
240718
|
+
function collectTelegramAttachmentCandidates(message) {
|
|
240719
|
+
const attachments = [];
|
|
240720
|
+
if (Array.isArray(message.photo) && message.photo.length > 0) {
|
|
240721
|
+
const photo = message.photo[message.photo.length - 1];
|
|
240722
|
+
if (photo?.file_id) {
|
|
240723
|
+
attachments.push({
|
|
240724
|
+
fileId: photo.file_id,
|
|
240725
|
+
kind: "image",
|
|
240726
|
+
name: `photo-${photo.file_unique_id ?? photo.file_id}.jpg`,
|
|
240727
|
+
mimeType: "image/jpeg",
|
|
240728
|
+
sizeBytes: coerceSizeBytes(photo.file_size)
|
|
240729
|
+
});
|
|
240730
|
+
}
|
|
240731
|
+
}
|
|
240732
|
+
if (message.document?.file_id) {
|
|
240733
|
+
attachments.push({
|
|
240734
|
+
fileId: message.document.file_id,
|
|
240735
|
+
kind: inferAttachmentKind({
|
|
240736
|
+
mimeType: message.document.mime_type,
|
|
240737
|
+
fileName: message.document.file_name,
|
|
240738
|
+
fallback: "file"
|
|
240739
|
+
}),
|
|
240740
|
+
name: message.document.file_name,
|
|
240741
|
+
mimeType: message.document.mime_type,
|
|
240742
|
+
sizeBytes: coerceSizeBytes(message.document.file_size)
|
|
240743
|
+
});
|
|
240744
|
+
}
|
|
240745
|
+
if (message.video?.file_id) {
|
|
240746
|
+
attachments.push({
|
|
240747
|
+
fileId: message.video.file_id,
|
|
240748
|
+
kind: "video",
|
|
240749
|
+
name: message.video.file_name ?? `video-${message.video.file_unique_id ?? message.video.file_id}.mp4`,
|
|
240750
|
+
mimeType: message.video.mime_type,
|
|
240751
|
+
sizeBytes: coerceSizeBytes(message.video.file_size)
|
|
240752
|
+
});
|
|
240753
|
+
}
|
|
240754
|
+
if (message.audio?.file_id) {
|
|
240755
|
+
attachments.push({
|
|
240756
|
+
fileId: message.audio.file_id,
|
|
240757
|
+
kind: "audio",
|
|
240758
|
+
name: message.audio.file_name ?? `audio-${message.audio.file_unique_id ?? message.audio.file_id}.mp3`,
|
|
240759
|
+
mimeType: message.audio.mime_type,
|
|
240760
|
+
sizeBytes: coerceSizeBytes(message.audio.file_size)
|
|
240761
|
+
});
|
|
240762
|
+
}
|
|
240763
|
+
if (message.voice?.file_id) {
|
|
240764
|
+
attachments.push({
|
|
240765
|
+
fileId: message.voice.file_id,
|
|
240766
|
+
kind: "audio",
|
|
240767
|
+
name: `voice-${message.voice.file_unique_id ?? message.voice.file_id}.ogg`,
|
|
240768
|
+
mimeType: message.voice.mime_type,
|
|
240769
|
+
sizeBytes: coerceSizeBytes(message.voice.file_size),
|
|
240770
|
+
isVoice: true
|
|
240771
|
+
});
|
|
240772
|
+
}
|
|
240773
|
+
if (message.animation?.file_id) {
|
|
240774
|
+
attachments.push({
|
|
240775
|
+
fileId: message.animation.file_id,
|
|
240776
|
+
kind: "video",
|
|
240777
|
+
name: message.animation.file_name ?? `animation-${message.animation.file_unique_id ?? message.animation.file_id}.gif`,
|
|
240778
|
+
mimeType: message.animation.mime_type,
|
|
240779
|
+
sizeBytes: coerceSizeBytes(message.animation.file_size)
|
|
240780
|
+
});
|
|
240781
|
+
}
|
|
240782
|
+
if (message.sticker?.file_id && !message.sticker.is_animated && !message.sticker.is_video) {
|
|
240783
|
+
attachments.push({
|
|
240784
|
+
fileId: message.sticker.file_id,
|
|
240785
|
+
kind: "image",
|
|
240786
|
+
name: `sticker-${message.sticker.file_unique_id ?? message.sticker.file_id}.webp`,
|
|
240787
|
+
mimeType: message.sticker.mime_type ?? "image/webp",
|
|
240788
|
+
sizeBytes: coerceSizeBytes(message.sticker.file_size)
|
|
240789
|
+
});
|
|
240790
|
+
}
|
|
240791
|
+
return attachments;
|
|
240792
|
+
}
|
|
240793
|
+
function inferUploadMethodFromMimeType(mimeType) {
|
|
240794
|
+
const normalized = normalizeTelegramMimeType(mimeType);
|
|
240795
|
+
if (!normalized) {
|
|
240796
|
+
return null;
|
|
240797
|
+
}
|
|
240798
|
+
if (["image/png", "image/jpeg"].includes(normalized)) {
|
|
240799
|
+
return "photo";
|
|
240800
|
+
}
|
|
240801
|
+
if (normalized === "image/gif") {
|
|
240802
|
+
return "animation";
|
|
240803
|
+
}
|
|
240804
|
+
if (normalized === "image/webp") {
|
|
240805
|
+
return "document";
|
|
240806
|
+
}
|
|
240807
|
+
if (normalized.startsWith("video/")) {
|
|
240808
|
+
return "video";
|
|
240809
|
+
}
|
|
240810
|
+
if (["audio/ogg", "audio/opus"].includes(normalized)) {
|
|
240811
|
+
return "voice";
|
|
240812
|
+
}
|
|
240813
|
+
if (normalized.startsWith("audio/")) {
|
|
240814
|
+
return "audio";
|
|
240815
|
+
}
|
|
240816
|
+
return null;
|
|
240817
|
+
}
|
|
240818
|
+
function detectTelegramUploadMethod(filePath, fileName) {
|
|
240819
|
+
const inferredName = (fileName ?? basename13(filePath)).toLowerCase();
|
|
240820
|
+
const extension = extname6(inferredName);
|
|
240821
|
+
const mimeType = inferMimeTypeFromName(inferredName);
|
|
240822
|
+
const byMimeType = inferUploadMethodFromMimeType(mimeType);
|
|
240823
|
+
if (byMimeType) {
|
|
240824
|
+
return byMimeType;
|
|
240825
|
+
}
|
|
240826
|
+
if (ANIMATION_EXTENSIONS.has(extension)) {
|
|
240827
|
+
return "animation";
|
|
240828
|
+
}
|
|
240829
|
+
if (VIDEO_EXTENSIONS.has(extension)) {
|
|
240830
|
+
return "video";
|
|
240831
|
+
}
|
|
240832
|
+
if (VOICE_EXTENSIONS.has(extension)) {
|
|
240833
|
+
return "voice";
|
|
240834
|
+
}
|
|
240835
|
+
if (AUDIO_EXTENSIONS.has(extension)) {
|
|
240836
|
+
return "audio";
|
|
240837
|
+
}
|
|
240838
|
+
return "document";
|
|
240839
|
+
}
|
|
240840
|
+
function inferMimeTypeFromName(name) {
|
|
240841
|
+
const normalized = name.toLowerCase();
|
|
240842
|
+
const extension = extname6(normalized);
|
|
240843
|
+
if (IMAGE_EXTENSIONS3.has(extension)) {
|
|
240844
|
+
return extension === ".png" ? "image/png" : "image/jpeg";
|
|
240845
|
+
}
|
|
240846
|
+
if (ANIMATION_EXTENSIONS.has(extension)) {
|
|
240847
|
+
return "image/gif";
|
|
240848
|
+
}
|
|
240849
|
+
if (STATIC_STICKER_EXTENSIONS.has(extension)) {
|
|
240850
|
+
return "image/webp";
|
|
240851
|
+
}
|
|
240852
|
+
if (extension === ".mp4" || extension === ".m4v") {
|
|
240853
|
+
return "video/mp4";
|
|
240854
|
+
}
|
|
240855
|
+
if (extension === ".mov") {
|
|
240856
|
+
return "video/quicktime";
|
|
240857
|
+
}
|
|
240858
|
+
if (extension === ".webm") {
|
|
240859
|
+
return "video/webm";
|
|
240860
|
+
}
|
|
240861
|
+
if (extension === ".mp3") {
|
|
240862
|
+
return "audio/mpeg";
|
|
240863
|
+
}
|
|
240864
|
+
if (extension === ".m4a") {
|
|
240865
|
+
return "audio/mp4";
|
|
240866
|
+
}
|
|
240867
|
+
if (extension === ".wav") {
|
|
240868
|
+
return "audio/wav";
|
|
240869
|
+
}
|
|
240870
|
+
if (VOICE_EXTENSIONS.has(extension)) {
|
|
240871
|
+
return "audio/ogg";
|
|
240872
|
+
}
|
|
240873
|
+
if (extension === ".pdf") {
|
|
240874
|
+
return "application/pdf";
|
|
240875
|
+
}
|
|
240876
|
+
if (extension === ".txt") {
|
|
240877
|
+
return "text/plain";
|
|
240878
|
+
}
|
|
240879
|
+
if (extension === ".md") {
|
|
240880
|
+
return "text/markdown";
|
|
240881
|
+
}
|
|
240882
|
+
if (extension === ".json") {
|
|
240883
|
+
return "application/json";
|
|
240884
|
+
}
|
|
240885
|
+
return;
|
|
240886
|
+
}
|
|
240887
|
+
function extensionForMimeType(mimeType) {
|
|
240888
|
+
switch (normalizeTelegramMimeType(mimeType)) {
|
|
240889
|
+
case "image/png":
|
|
240890
|
+
return ".png";
|
|
240891
|
+
case "image/jpeg":
|
|
240892
|
+
return ".jpg";
|
|
240893
|
+
case "image/gif":
|
|
240894
|
+
return ".gif";
|
|
240895
|
+
case "image/webp":
|
|
240896
|
+
return ".webp";
|
|
240897
|
+
case "video/mp4":
|
|
240898
|
+
return ".mp4";
|
|
240899
|
+
case "video/quicktime":
|
|
240900
|
+
return ".mov";
|
|
240901
|
+
case "video/webm":
|
|
240902
|
+
return ".webm";
|
|
240903
|
+
case "audio/mpeg":
|
|
240904
|
+
return ".mp3";
|
|
240905
|
+
case "audio/mp4":
|
|
240906
|
+
return ".m4a";
|
|
240907
|
+
case "audio/wav":
|
|
240908
|
+
case "audio/x-wav":
|
|
240909
|
+
case "audio/wave":
|
|
240910
|
+
return ".wav";
|
|
240911
|
+
case "audio/ogg":
|
|
240912
|
+
case "audio/opus":
|
|
240913
|
+
return ".ogg";
|
|
240914
|
+
case "application/pdf":
|
|
240915
|
+
return ".pdf";
|
|
240916
|
+
case "text/plain":
|
|
240917
|
+
return ".txt";
|
|
240918
|
+
case "text/markdown":
|
|
240919
|
+
return ".md";
|
|
240920
|
+
case "application/json":
|
|
240921
|
+
return ".json";
|
|
240922
|
+
default:
|
|
240923
|
+
return "";
|
|
240924
|
+
}
|
|
240925
|
+
}
|
|
240926
|
+
function buildTelegramFileUrl(token2, filePath) {
|
|
240927
|
+
return `https://api.telegram.org/file/bot${token2}/${filePath}`;
|
|
240928
|
+
}
|
|
240929
|
+
function inferAttachmentFileName(params) {
|
|
240930
|
+
const hintedName = params.candidate.name?.trim() || basename13(params.remotePath) || "attachment";
|
|
240931
|
+
if (extname6(hintedName)) {
|
|
240932
|
+
return hintedName;
|
|
240933
|
+
}
|
|
240934
|
+
const extension = extensionForMimeType(params.responseMimeType) || extensionForMimeType(params.candidate.mimeType);
|
|
240935
|
+
return extension ? `${hintedName}${extension}` : hintedName;
|
|
240936
|
+
}
|
|
240937
|
+
async function saveTelegramAttachment(params) {
|
|
240938
|
+
const inboundDir = join42(getChannelDir("telegram"), "inbound", sanitizeTelegramPathSegment(params.accountId));
|
|
240939
|
+
await mkdir8(inboundDir, { recursive: true });
|
|
240940
|
+
const filePath = join42(inboundDir, `${Date.now()}-${randomUUID12()}-${sanitizeTelegramPathSegment(params.fileName)}`);
|
|
240941
|
+
await writeFile10(filePath, params.buffer);
|
|
240942
|
+
return filePath;
|
|
240943
|
+
}
|
|
240944
|
+
async function fetchTelegramFile(url2, timeoutMs) {
|
|
240945
|
+
const controller = new AbortController;
|
|
240946
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
240947
|
+
try {
|
|
240948
|
+
return await fetch(url2, { signal: controller.signal });
|
|
240949
|
+
} finally {
|
|
240950
|
+
clearTimeout(timeout);
|
|
240951
|
+
}
|
|
240952
|
+
}
|
|
240953
|
+
async function downloadTelegramAttachment(params) {
|
|
240954
|
+
const { candidate } = params;
|
|
240955
|
+
if (typeof candidate.sizeBytes === "number" && candidate.sizeBytes > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240956
|
+
console.warn(`[Telegram] Skipping attachment ${candidate.name ?? candidate.fileId}: ${candidate.sizeBytes} bytes exceeds Telegram download limit (${MAX_TELEGRAM_DOWNLOAD_BYTES} bytes).`);
|
|
240957
|
+
return null;
|
|
240958
|
+
}
|
|
240959
|
+
const file3 = await params.bot.api.getFile(candidate.fileId);
|
|
240960
|
+
const remotePath = file3.file_path;
|
|
240961
|
+
if (!remotePath) {
|
|
240962
|
+
console.warn(`[Telegram] getFile returned no file_path for attachment ${candidate.name ?? candidate.fileId}.`);
|
|
240963
|
+
return null;
|
|
240964
|
+
}
|
|
240965
|
+
const response = await fetchTelegramFile(buildTelegramFileUrl(params.token, remotePath), TELEGRAM_DOWNLOAD_TIMEOUT_MS);
|
|
240966
|
+
if (!response.ok) {
|
|
240967
|
+
console.warn(`[Telegram] Failed to download attachment ${candidate.name ?? candidate.fileId} from ${remotePath}: ${response.status} ${response.statusText}`);
|
|
240968
|
+
return null;
|
|
240969
|
+
}
|
|
240970
|
+
const contentLength = response.headers.get("content-length");
|
|
240971
|
+
if (contentLength) {
|
|
240972
|
+
const parsedLength = Number(contentLength);
|
|
240973
|
+
if (Number.isFinite(parsedLength) && parsedLength > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240974
|
+
console.warn(`[Telegram] Refusing attachment ${candidate.name ?? candidate.fileId}: content-length ${parsedLength} exceeds limit ${MAX_TELEGRAM_DOWNLOAD_BYTES}.`);
|
|
240975
|
+
return null;
|
|
240976
|
+
}
|
|
240977
|
+
}
|
|
240978
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
240979
|
+
if (buffer.byteLength > MAX_TELEGRAM_DOWNLOAD_BYTES) {
|
|
240980
|
+
console.warn(`[Telegram] Refusing attachment ${candidate.name ?? candidate.fileId}: downloaded size ${buffer.byteLength} exceeds limit ${MAX_TELEGRAM_DOWNLOAD_BYTES}.`);
|
|
240981
|
+
return null;
|
|
240982
|
+
}
|
|
240983
|
+
const responseMimeType = normalizeTelegramMimeType(response.headers.get("content-type") ?? undefined);
|
|
240984
|
+
const fileName = inferAttachmentFileName({
|
|
240985
|
+
candidate,
|
|
240986
|
+
remotePath,
|
|
240987
|
+
responseMimeType
|
|
240988
|
+
});
|
|
240989
|
+
const candidateMimeType = normalizeTelegramMimeType(candidate.mimeType);
|
|
240990
|
+
const mimeType = (isGenericTelegramMimeType(responseMimeType) ? candidateMimeType : responseMimeType) ?? inferMimeTypeFromName(fileName);
|
|
240991
|
+
const kind = inferAttachmentKind({
|
|
240992
|
+
mimeType,
|
|
240993
|
+
fileName,
|
|
240994
|
+
fallback: candidate.kind
|
|
240995
|
+
});
|
|
240996
|
+
const localPath = await saveTelegramAttachment({
|
|
240997
|
+
accountId: params.accountId,
|
|
240998
|
+
fileName,
|
|
240999
|
+
buffer
|
|
241000
|
+
});
|
|
241001
|
+
const attachment = {
|
|
241002
|
+
id: candidate.fileId,
|
|
241003
|
+
name: fileName,
|
|
241004
|
+
mimeType,
|
|
241005
|
+
sizeBytes: buffer.byteLength,
|
|
241006
|
+
kind,
|
|
241007
|
+
localPath,
|
|
241008
|
+
...kind === "image" && canInlineTelegramImage(mimeType) && buffer.byteLength <= MAX_TELEGRAM_INLINE_IMAGE_BYTES ? { imageDataBase64: buffer.toString("base64") } : {}
|
|
241009
|
+
};
|
|
241010
|
+
if (candidate.isVoice && params.transcribeVoice) {
|
|
241011
|
+
const { isTranscriptionConfigured: isTranscriptionConfigured2, transcribeAudioFile: transcribeAudioFile2 } = await Promise.resolve().then(() => (init_transcription(), exports_transcription));
|
|
241012
|
+
if (isTranscriptionConfigured2()) {
|
|
241013
|
+
const result2 = await transcribeAudioFile2(localPath);
|
|
241014
|
+
if (result2.success && result2.text) {
|
|
241015
|
+
attachment.transcription = result2.text;
|
|
241016
|
+
} else if (result2.error) {
|
|
241017
|
+
attachment.transcriptionError = result2.error;
|
|
241018
|
+
console.warn(`[Telegram] Voice transcription failed for ${fileName}:`, result2.error);
|
|
241019
|
+
}
|
|
241020
|
+
} else {
|
|
241021
|
+
attachment.transcriptionError = "OPENAI_API_KEY not set; transcription skipped.";
|
|
241022
|
+
}
|
|
241023
|
+
}
|
|
241024
|
+
return attachment;
|
|
241025
|
+
}
|
|
241026
|
+
async function resolveTelegramInboundAttachments(params) {
|
|
241027
|
+
const deduped = new Map;
|
|
241028
|
+
for (const message of params.messages) {
|
|
241029
|
+
for (const candidate of collectTelegramAttachmentCandidates(message)) {
|
|
241030
|
+
deduped.set(candidate.fileId, candidate);
|
|
241031
|
+
}
|
|
241032
|
+
}
|
|
241033
|
+
if (deduped.size === 0) {
|
|
241034
|
+
return [];
|
|
241035
|
+
}
|
|
241036
|
+
const resolved = await Promise.all(Array.from(deduped.values()).map((candidate) => downloadTelegramAttachment({
|
|
241037
|
+
accountId: params.accountId,
|
|
241038
|
+
token: params.token,
|
|
241039
|
+
bot: params.bot,
|
|
241040
|
+
candidate,
|
|
241041
|
+
transcribeVoice: params.transcribeVoice
|
|
241042
|
+
}).catch((error54) => {
|
|
241043
|
+
const message = error54 instanceof Error ? error54.message : String(error54);
|
|
241044
|
+
console.warn(`[Telegram] Attachment download failed for ${candidate.name ?? candidate.fileId}: ${message}`);
|
|
241045
|
+
return null;
|
|
241046
|
+
})));
|
|
241047
|
+
return resolved.filter((attachment) => Boolean(attachment));
|
|
241048
|
+
}
|
|
241049
|
+
var TELEGRAM_MEDIA_GROUP_FLUSH_MS = 150, TELEGRAM_DOWNLOAD_TIMEOUT_MS = 15000, MAX_TELEGRAM_DOWNLOAD_BYTES, MAX_TELEGRAM_INLINE_IMAGE_BYTES, IMAGE_EXTENSIONS3, ANIMATION_EXTENSIONS, VIDEO_EXTENSIONS, AUDIO_EXTENSIONS, VOICE_EXTENSIONS, STATIC_STICKER_EXTENSIONS;
|
|
241050
|
+
var init_media = __esm(() => {
|
|
241051
|
+
init_config2();
|
|
241052
|
+
MAX_TELEGRAM_DOWNLOAD_BYTES = 50 * 1024 * 1024;
|
|
241053
|
+
MAX_TELEGRAM_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
241054
|
+
IMAGE_EXTENSIONS3 = new Set([".png", ".jpg", ".jpeg"]);
|
|
241055
|
+
ANIMATION_EXTENSIONS = new Set([".gif"]);
|
|
241056
|
+
VIDEO_EXTENSIONS = new Set([".mp4", ".m4v", ".mov", ".webm"]);
|
|
241057
|
+
AUDIO_EXTENSIONS = new Set([".mp3", ".m4a", ".wav"]);
|
|
241058
|
+
VOICE_EXTENSIONS = new Set([".ogg", ".oga", ".opus"]);
|
|
241059
|
+
STATIC_STICKER_EXTENSIONS = new Set([".webp"]);
|
|
241060
|
+
});
|
|
241061
|
+
|
|
241296
241062
|
// src/channels/telegram/startup-helpers.ts
|
|
241297
241063
|
function getStartupTimeoutMs(envName, fallbackMs) {
|
|
241298
241064
|
const raw2 = process.env[envName];
|
|
@@ -241635,19 +241401,7 @@ function createTelegramAdapter(config3) {
|
|
|
241635
241401
|
if (!senderId) {
|
|
241636
241402
|
return;
|
|
241637
241403
|
}
|
|
241638
|
-
const
|
|
241639
|
-
const newTokens = new Set(update3.new_reaction.map((reaction) => getTelegramReactionToken(reaction)).filter((value) => typeof value === "string"));
|
|
241640
|
-
const events = [];
|
|
241641
|
-
for (const emoji3 of oldTokens) {
|
|
241642
|
-
if (!newTokens.has(emoji3)) {
|
|
241643
|
-
events.push({ action: "removed", emoji: emoji3 });
|
|
241644
|
-
}
|
|
241645
|
-
}
|
|
241646
|
-
for (const emoji3 of newTokens) {
|
|
241647
|
-
if (!oldTokens.has(emoji3)) {
|
|
241648
|
-
events.push({ action: "added", emoji: emoji3 });
|
|
241649
|
-
}
|
|
241650
|
-
}
|
|
241404
|
+
const events = diffTelegramReactionUpdate(update3);
|
|
241651
241405
|
for (const event2 of events) {
|
|
241652
241406
|
try {
|
|
241653
241407
|
await adapter.onMessage({
|
|
@@ -242014,29 +241768,19 @@ function createTelegramAdapter(config3) {
|
|
|
242014
241768
|
var init_adapter2 = __esm(() => {
|
|
242015
241769
|
init_lifecycle_error_report();
|
|
242016
241770
|
init_debounce3();
|
|
241771
|
+
init_ingress();
|
|
242017
241772
|
init_media();
|
|
242018
241773
|
init_runtime2();
|
|
242019
241774
|
init_typing_controller();
|
|
242020
241775
|
init_utils5();
|
|
242021
241776
|
});
|
|
242022
241777
|
|
|
242023
|
-
// src/channels/telegram/message-
|
|
242024
|
-
function richPrivateChatDefaultEnabled(route) {
|
|
242025
|
-
const accountId = route.accountId?.trim();
|
|
242026
|
-
if (!accountId) {
|
|
242027
|
-
return true;
|
|
242028
|
-
}
|
|
242029
|
-
const account = getChannelAccount("telegram", accountId);
|
|
242030
|
-
if (!account || !isTelegramChannelAccount(account)) {
|
|
242031
|
-
return true;
|
|
242032
|
-
}
|
|
242033
|
-
return account.richPrivateChatDefault !== false;
|
|
242034
|
-
}
|
|
241778
|
+
// src/channels/telegram/message-action-contract.ts
|
|
242035
241779
|
function shouldSendTelegramRichMessage(params) {
|
|
242036
241780
|
if (params.request.action === "send-rich") {
|
|
242037
241781
|
return true;
|
|
242038
241782
|
}
|
|
242039
|
-
return params.request.action === "send" && params.route.chatType === "direct" && richPrivateChatDefaultEnabled(params.route) && !params.request.mediaPath?.trim();
|
|
241783
|
+
return params.request.action === "send" && params.route.chatType === "direct" && params.richPrivateChatDefaultEnabled(params.route) && !params.request.mediaPath?.trim();
|
|
242040
241784
|
}
|
|
242041
241785
|
function resolveTelegramRouteThreadId(ctx) {
|
|
242042
241786
|
const requestThreadId = ctx.request.threadId?.trim();
|
|
@@ -242052,11 +241796,9 @@ function resolveTelegramRouteThreadId(ctx) {
|
|
|
242052
241796
|
}
|
|
242053
241797
|
return ctx.route.chatId.trim().startsWith("-") ? routeThreadId : null;
|
|
242054
241798
|
}
|
|
242055
|
-
|
|
242056
|
-
|
|
242057
|
-
|
|
242058
|
-
init_types8();
|
|
242059
|
-
telegramMessageActions = {
|
|
241799
|
+
function createTelegramMessageActionAdapter(options3 = {}) {
|
|
241800
|
+
const richPrivateChatDefaultEnabled = options3.richPrivateChatDefaultEnabled ?? (() => true);
|
|
241801
|
+
return {
|
|
242060
241802
|
describeMessageTool() {
|
|
242061
241803
|
return {
|
|
242062
241804
|
actions: ["send", "send-rich", "react", "upload-file"]
|
|
@@ -242103,7 +241845,11 @@ var init_message_actions = __esm(() => {
|
|
|
242103
241845
|
return "Error: Telegram send requires message.";
|
|
242104
241846
|
}
|
|
242105
241847
|
const formatted = formatText(request.message ?? "");
|
|
242106
|
-
const sendRichMessage = shouldSendTelegramRichMessage({
|
|
241848
|
+
const sendRichMessage = shouldSendTelegramRichMessage({
|
|
241849
|
+
request,
|
|
241850
|
+
route,
|
|
241851
|
+
richPrivateChatDefaultEnabled
|
|
241852
|
+
});
|
|
242107
241853
|
const result2 = await adapter.sendMessage({
|
|
242108
241854
|
channel: "telegram",
|
|
242109
241855
|
accountId: route.accountId,
|
|
@@ -242120,6 +241866,27 @@ var init_message_actions = __esm(() => {
|
|
|
242120
241866
|
return request.mediaPath ? `Attachment sent to telegram (message_id: ${result2.messageId})` : `Message sent to telegram (message_id: ${result2.messageId})`;
|
|
242121
241867
|
}
|
|
242122
241868
|
};
|
|
241869
|
+
}
|
|
241870
|
+
|
|
241871
|
+
// src/channels/telegram/message-actions.ts
|
|
241872
|
+
function richPrivateChatDefaultEnabled(route) {
|
|
241873
|
+
const accountId = route.accountId?.trim();
|
|
241874
|
+
if (!accountId) {
|
|
241875
|
+
return true;
|
|
241876
|
+
}
|
|
241877
|
+
const account = getChannelAccount("telegram", accountId);
|
|
241878
|
+
if (!account || !isTelegramChannelAccount(account)) {
|
|
241879
|
+
return true;
|
|
241880
|
+
}
|
|
241881
|
+
return account.richPrivateChatDefault !== false;
|
|
241882
|
+
}
|
|
241883
|
+
var telegramMessageActions;
|
|
241884
|
+
var init_message_actions = __esm(() => {
|
|
241885
|
+
init_accounts();
|
|
241886
|
+
init_types8();
|
|
241887
|
+
telegramMessageActions = createTelegramMessageActionAdapter({
|
|
241888
|
+
richPrivateChatDefaultEnabled
|
|
241889
|
+
});
|
|
242123
241890
|
});
|
|
242124
241891
|
|
|
242125
241892
|
// src/channels/telegram/setup.ts
|
|
@@ -243770,126 +243537,7 @@ var init_approval_controller = __esm(() => {
|
|
|
243770
243537
|
init_utils6();
|
|
243771
243538
|
});
|
|
243772
243539
|
|
|
243773
|
-
// src/channels/slack/attachment-
|
|
243774
|
-
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
243775
|
-
import { mkdir as mkdir9, open as open2, rename as rename2, rm as rm7 } from "node:fs/promises";
|
|
243776
|
-
import { join as join43 } from "node:path";
|
|
243777
|
-
function sanitizeFileName(name) {
|
|
243778
|
-
const normalized = name.trim().replace(/[^\w.-]+/g, "_");
|
|
243779
|
-
return normalized.length > 0 ? normalized : "attachment";
|
|
243780
|
-
}
|
|
243781
|
-
async function readWithIdleTimeout(reader, idleTimeoutMs, signal) {
|
|
243782
|
-
if (signal?.aborted) {
|
|
243783
|
-
throw new SlackAttachmentDownloadError("download_failed", "Slack attachment download was aborted.");
|
|
243784
|
-
}
|
|
243785
|
-
let timeoutHandle;
|
|
243786
|
-
let onAbort;
|
|
243787
|
-
try {
|
|
243788
|
-
return await new Promise((resolve32, reject2) => {
|
|
243789
|
-
timeoutHandle = setTimeout(() => {
|
|
243790
|
-
reject2(new SlackAttachmentDownloadError("download_failed", `Slack attachment download stalled (no data received for ${idleTimeoutMs}ms).`));
|
|
243791
|
-
}, idleTimeoutMs);
|
|
243792
|
-
if (signal) {
|
|
243793
|
-
onAbort = () => reject2(new SlackAttachmentDownloadError("download_failed", "Slack attachment download was aborted."));
|
|
243794
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
243795
|
-
}
|
|
243796
|
-
reader.read().then(resolve32, reject2);
|
|
243797
|
-
});
|
|
243798
|
-
} finally {
|
|
243799
|
-
if (timeoutHandle !== undefined) {
|
|
243800
|
-
clearTimeout(timeoutHandle);
|
|
243801
|
-
}
|
|
243802
|
-
if (signal && onAbort) {
|
|
243803
|
-
signal.removeEventListener("abort", onAbort);
|
|
243804
|
-
}
|
|
243805
|
-
}
|
|
243806
|
-
}
|
|
243807
|
-
async function saveSlackAttachmentStream(params) {
|
|
243808
|
-
const inboundDir = join43(getChannelDir("slack"), "inbound", sanitizeFileName(params.accountId));
|
|
243809
|
-
await mkdir9(inboundDir, { recursive: true });
|
|
243810
|
-
const filePath = join43(inboundDir, `${Date.now()}-${randomUUID15()}-${sanitizeFileName(params.fileName)}`);
|
|
243811
|
-
const temporaryPath = `${filePath}.partial`;
|
|
243812
|
-
const fileHandle = await open2(temporaryPath, "wx");
|
|
243813
|
-
const reader = params.body.getReader();
|
|
243814
|
-
const readIdleTimeoutMs = params.readIdleTimeoutMs ?? SLACK_ATTACHMENT_READ_IDLE_TIMEOUT_MS;
|
|
243815
|
-
let sizeBytes = 0;
|
|
243816
|
-
let completed = false;
|
|
243817
|
-
try {
|
|
243818
|
-
while (true) {
|
|
243819
|
-
const { done, value } = await readWithIdleTimeout(reader, readIdleTimeoutMs, params.signal);
|
|
243820
|
-
if (done) {
|
|
243821
|
-
break;
|
|
243822
|
-
}
|
|
243823
|
-
if (!value?.byteLength) {
|
|
243824
|
-
continue;
|
|
243825
|
-
}
|
|
243826
|
-
sizeBytes += value.byteLength;
|
|
243827
|
-
if (params.maxBytes !== undefined && sizeBytes > params.maxBytes) {
|
|
243828
|
-
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment exceeds automatic download limit (${params.maxBytes} bytes).`);
|
|
243829
|
-
}
|
|
243830
|
-
let offset = 0;
|
|
243831
|
-
while (offset < value.byteLength) {
|
|
243832
|
-
const { bytesWritten } = await fileHandle.write(value, offset, value.byteLength - offset);
|
|
243833
|
-
if (bytesWritten <= 0) {
|
|
243834
|
-
throw new Error("Slack attachment write made no progress.");
|
|
243835
|
-
}
|
|
243836
|
-
offset += bytesWritten;
|
|
243837
|
-
}
|
|
243838
|
-
}
|
|
243839
|
-
completed = true;
|
|
243840
|
-
} finally {
|
|
243841
|
-
if (!completed) {
|
|
243842
|
-
await reader.cancel().catch(() => {
|
|
243843
|
-
return;
|
|
243844
|
-
});
|
|
243845
|
-
}
|
|
243846
|
-
try {
|
|
243847
|
-
reader.releaseLock();
|
|
243848
|
-
} catch {}
|
|
243849
|
-
await fileHandle.close().catch(() => {
|
|
243850
|
-
return;
|
|
243851
|
-
});
|
|
243852
|
-
if (!completed) {
|
|
243853
|
-
await rm7(temporaryPath, { force: true }).catch(() => {
|
|
243854
|
-
return;
|
|
243855
|
-
});
|
|
243856
|
-
}
|
|
243857
|
-
}
|
|
243858
|
-
try {
|
|
243859
|
-
await rename2(temporaryPath, filePath);
|
|
243860
|
-
} catch (error54) {
|
|
243861
|
-
await rm7(temporaryPath, { force: true }).catch(() => {
|
|
243862
|
-
return;
|
|
243863
|
-
});
|
|
243864
|
-
throw error54;
|
|
243865
|
-
}
|
|
243866
|
-
return { localPath: filePath, sizeBytes };
|
|
243867
|
-
}
|
|
243868
|
-
var SlackAttachmentDownloadError, SLACK_ATTACHMENT_READ_IDLE_TIMEOUT_MS = 60000;
|
|
243869
|
-
var init_attachment_stream = __esm(() => {
|
|
243870
|
-
init_config2();
|
|
243871
|
-
SlackAttachmentDownloadError = class SlackAttachmentDownloadError extends Error {
|
|
243872
|
-
reason;
|
|
243873
|
-
constructor(reason, message) {
|
|
243874
|
-
super(message);
|
|
243875
|
-
this.reason = reason;
|
|
243876
|
-
this.name = "SlackAttachmentDownloadError";
|
|
243877
|
-
}
|
|
243878
|
-
};
|
|
243879
|
-
});
|
|
243880
|
-
|
|
243881
|
-
// src/channels/slack/media.ts
|
|
243882
|
-
import { basename as basename14, extname as extname7 } from "node:path";
|
|
243883
|
-
async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId) {
|
|
243884
|
-
const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
|
|
243885
|
-
return {
|
|
243886
|
-
text: resolveSlackThreadMessageText(message),
|
|
243887
|
-
userId: isNonEmptyString6(message.user) ? message.user : undefined,
|
|
243888
|
-
botId: isNonEmptyString6(message.bot_id) ? message.bot_id : undefined,
|
|
243889
|
-
ts: isNonEmptyString6(message.ts) ? message.ts : undefined,
|
|
243890
|
-
...attachments.length > 0 ? { attachments } : {}
|
|
243891
|
-
};
|
|
243892
|
-
}
|
|
243540
|
+
// src/channels/slack/attachment-primitives.ts
|
|
243893
243541
|
function asRecord4(value) {
|
|
243894
243542
|
return value && typeof value === "object" ? value : null;
|
|
243895
243543
|
}
|
|
@@ -243898,9 +243546,8 @@ function isNonEmptyString6(value) {
|
|
|
243898
243546
|
}
|
|
243899
243547
|
function normalizeSlackFileLike(value) {
|
|
243900
243548
|
const record5 = asRecord4(value);
|
|
243901
|
-
if (!record5)
|
|
243549
|
+
if (!record5)
|
|
243902
243550
|
return null;
|
|
243903
|
-
}
|
|
243904
243551
|
return {
|
|
243905
243552
|
id: isNonEmptyString6(record5.id) ? record5.id : undefined,
|
|
243906
243553
|
name: isNonEmptyString6(record5.name) ? record5.name : undefined,
|
|
@@ -243912,61 +243559,75 @@ function normalizeSlackFileLike(value) {
|
|
|
243912
243559
|
}
|
|
243913
243560
|
function normalizeSlackAttachmentLike(value) {
|
|
243914
243561
|
const record5 = asRecord4(value);
|
|
243915
|
-
if (!record5)
|
|
243562
|
+
if (!record5)
|
|
243916
243563
|
return null;
|
|
243917
|
-
}
|
|
243918
243564
|
const files2 = Array.isArray(record5.files) ? record5.files.map((entry) => normalizeSlackFileLike(entry)).filter((entry) => Boolean(entry)) : undefined;
|
|
243919
243565
|
return {
|
|
243920
|
-
text: isNonEmptyString6(record5.text) ? record5.text : undefined,
|
|
243921
|
-
fallback: isNonEmptyString6(record5.fallback) ? record5.fallback : undefined,
|
|
243922
|
-
pretext: isNonEmptyString6(record5.pretext) ? record5.pretext : undefined,
|
|
243923
|
-
author_name: isNonEmptyString6(record5.author_name) ? record5.author_name : undefined,
|
|
243924
|
-
title: isNonEmptyString6(record5.title) ? record5.title : undefined,
|
|
243925
243566
|
image_url: isNonEmptyString6(record5.image_url) ? record5.image_url : undefined,
|
|
243926
243567
|
files: files2
|
|
243927
243568
|
};
|
|
243928
243569
|
}
|
|
243929
|
-
function
|
|
243930
|
-
const
|
|
243931
|
-
|
|
243932
|
-
|
|
243933
|
-
|
|
243934
|
-
|
|
243935
|
-
|
|
243936
|
-
|
|
243937
|
-
|
|
243938
|
-
|
|
243570
|
+
function collectSlackFiles(rawEvent) {
|
|
243571
|
+
const record5 = asRecord4(rawEvent);
|
|
243572
|
+
if (!record5)
|
|
243573
|
+
return [];
|
|
243574
|
+
const deduped = new Map;
|
|
243575
|
+
const push = (file3) => {
|
|
243576
|
+
if (!file3)
|
|
243577
|
+
return;
|
|
243578
|
+
const key2 = file3.id ?? file3.url_private_download ?? file3.url_private ?? `${file3.name ?? "attachment"}:${file3.mimetype ?? ""}`;
|
|
243579
|
+
deduped.set(key2, file3);
|
|
243580
|
+
};
|
|
243581
|
+
if (Array.isArray(record5.files)) {
|
|
243582
|
+
for (const entry of record5.files)
|
|
243583
|
+
push(normalizeSlackFileLike(entry));
|
|
243939
243584
|
}
|
|
243940
|
-
|
|
243585
|
+
if (Array.isArray(record5.attachments)) {
|
|
243586
|
+
record5.attachments.map((entry) => normalizeSlackAttachmentLike(entry)).filter((entry) => Boolean(entry)).forEach((attachment, index) => {
|
|
243587
|
+
for (const file3 of attachment.files ?? [])
|
|
243588
|
+
push(file3);
|
|
243589
|
+
if (attachment.image_url) {
|
|
243590
|
+
push({
|
|
243591
|
+
id: `attachment-image-${index}`,
|
|
243592
|
+
name: `attachment-image-${index}.png`,
|
|
243593
|
+
url_private: attachment.image_url
|
|
243594
|
+
});
|
|
243595
|
+
}
|
|
243596
|
+
});
|
|
243597
|
+
}
|
|
243598
|
+
return Array.from(deduped.values()).slice(0, MAX_SLACK_ATTACHMENTS);
|
|
243941
243599
|
}
|
|
243942
|
-
function
|
|
243943
|
-
const
|
|
243944
|
-
|
|
243945
|
-
attachment.author_name,
|
|
243946
|
-
attachment.title,
|
|
243947
|
-
attachment.text,
|
|
243948
|
-
attachment.fallback
|
|
243949
|
-
]);
|
|
243950
|
-
return parts.join(`
|
|
243951
|
-
`);
|
|
243600
|
+
function nextCursor(page) {
|
|
243601
|
+
const value = page.response_metadata?.next_cursor;
|
|
243602
|
+
return isNonEmptyString6(value) ? value.trim() : undefined;
|
|
243952
243603
|
}
|
|
243953
|
-
function
|
|
243954
|
-
|
|
243955
|
-
|
|
243956
|
-
|
|
243957
|
-
|
|
243958
|
-
|
|
243959
|
-
|
|
243960
|
-
|
|
243961
|
-
|
|
243962
|
-
|
|
243963
|
-
|
|
243964
|
-
|
|
243965
|
-
|
|
243966
|
-
|
|
243604
|
+
async function resolveSlackMessageFiles(params) {
|
|
243605
|
+
if (isNonEmptyString6(params.threadTs)) {
|
|
243606
|
+
let cursor;
|
|
243607
|
+
do {
|
|
243608
|
+
const page2 = await params.client.conversations.replies({
|
|
243609
|
+
channel: params.channelId,
|
|
243610
|
+
ts: params.threadTs,
|
|
243611
|
+
limit: 200,
|
|
243612
|
+
inclusive: true,
|
|
243613
|
+
...cursor ? { cursor } : {}
|
|
243614
|
+
});
|
|
243615
|
+
const message2 = (page2.messages ?? []).find((entry) => entry.ts === params.messageTs);
|
|
243616
|
+
if (message2)
|
|
243617
|
+
return collectSlackFiles(message2);
|
|
243618
|
+
cursor = nextCursor(page2);
|
|
243619
|
+
} while (cursor);
|
|
243620
|
+
return null;
|
|
243967
243621
|
}
|
|
243968
|
-
const
|
|
243969
|
-
|
|
243622
|
+
const page = await params.client.conversations.history({
|
|
243623
|
+
channel: params.channelId,
|
|
243624
|
+
oldest: params.messageTs,
|
|
243625
|
+
latest: params.messageTs,
|
|
243626
|
+
inclusive: true,
|
|
243627
|
+
limit: 1
|
|
243628
|
+
});
|
|
243629
|
+
const message = (page.messages ?? []).find((entry) => entry.ts === params.messageTs);
|
|
243630
|
+
return message ? collectSlackFiles(message) : null;
|
|
243970
243631
|
}
|
|
243971
243632
|
function isAllowedSlackHostname(hostname4) {
|
|
243972
243633
|
const normalized = hostname4.trim().toLowerCase();
|
|
@@ -244015,11 +243676,22 @@ function extensionForMimeType2(mimeType) {
|
|
|
244015
243676
|
return "";
|
|
244016
243677
|
}
|
|
244017
243678
|
}
|
|
243679
|
+
function pathBaseName(pathname) {
|
|
243680
|
+
const trimmed = pathname.replace(/\/+$/, "");
|
|
243681
|
+
const separator = trimmed.lastIndexOf("/");
|
|
243682
|
+
return trimmed.slice(separator + 1);
|
|
243683
|
+
}
|
|
243684
|
+
function extensionName(name) {
|
|
243685
|
+
const base3 = pathBaseName(name);
|
|
243686
|
+
if (base3 === "..")
|
|
243687
|
+
return "";
|
|
243688
|
+
const index = base3.lastIndexOf(".");
|
|
243689
|
+
return index > 0 ? base3.slice(index) : "";
|
|
243690
|
+
}
|
|
244018
243691
|
function resolveMimeType(name, fallback) {
|
|
244019
|
-
if (fallback)
|
|
243692
|
+
if (fallback)
|
|
244020
243693
|
return fallback;
|
|
244021
|
-
|
|
244022
|
-
switch (extname7(name).toLowerCase()) {
|
|
243694
|
+
switch (extensionName(name).toLowerCase()) {
|
|
244023
243695
|
case ".png":
|
|
244024
243696
|
return "image/png";
|
|
244025
243697
|
case ".jpg":
|
|
@@ -244056,6 +243728,272 @@ function isGenericSlackMimeType(mimeType) {
|
|
|
244056
243728
|
const normalized = mimeType?.trim().toLowerCase();
|
|
244057
243729
|
return normalized === "application/octet-stream" || normalized === "binary/octet-stream";
|
|
244058
243730
|
}
|
|
243731
|
+
function resolveSlackFileName(params) {
|
|
243732
|
+
const hintedName = params.file.name ?? (params.url ? pathBaseName(new URL(params.url).pathname) : undefined) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
|
|
243733
|
+
return extensionName(hintedName) || !params.mimeType ? hintedName : `${hintedName}${extensionForMimeType2(params.mimeType)}`;
|
|
243734
|
+
}
|
|
243735
|
+
function resolveSlackFileMimeType(params) {
|
|
243736
|
+
const preferredMimeType = params.responseMimeType && !isGenericSlackMimeType(params.responseMimeType) ? params.responseMimeType : params.file.mimetype && !isGenericSlackMimeType(params.file.mimetype) ? params.file.mimetype : undefined;
|
|
243737
|
+
return resolveMimeType(params.fileName, preferredMimeType);
|
|
243738
|
+
}
|
|
243739
|
+
function resolveSlackFileMetadata(params) {
|
|
243740
|
+
const hintedName = resolveSlackFileName({
|
|
243741
|
+
file: params.file,
|
|
243742
|
+
url: params.url
|
|
243743
|
+
});
|
|
243744
|
+
const mimeType = resolveSlackFileMimeType({
|
|
243745
|
+
file: params.file,
|
|
243746
|
+
fileName: hintedName,
|
|
243747
|
+
responseMimeType: params.responseMimeType
|
|
243748
|
+
});
|
|
243749
|
+
return {
|
|
243750
|
+
fileName: resolveSlackFileName({
|
|
243751
|
+
file: params.file,
|
|
243752
|
+
url: params.url,
|
|
243753
|
+
mimeType
|
|
243754
|
+
}),
|
|
243755
|
+
mimeType
|
|
243756
|
+
};
|
|
243757
|
+
}
|
|
243758
|
+
function parseContentLength(response) {
|
|
243759
|
+
const header = response.headers.get("content-length");
|
|
243760
|
+
if (!header)
|
|
243761
|
+
return;
|
|
243762
|
+
const value = Number(header);
|
|
243763
|
+
return Number.isFinite(value) ? value : undefined;
|
|
243764
|
+
}
|
|
243765
|
+
async function fetchSlackFile(params) {
|
|
243766
|
+
const rawUrl = params.file.url_private_download ?? params.file.url_private;
|
|
243767
|
+
if (!rawUrl) {
|
|
243768
|
+
throw new Error("Slack attachment does not include a private download URL.");
|
|
243769
|
+
}
|
|
243770
|
+
const parsed = assertSlackFileUrl(rawUrl);
|
|
243771
|
+
const fetcher = params.fetcher ?? globalThis.fetch;
|
|
243772
|
+
const authHeaders = { Authorization: `Bearer ${params.token}` };
|
|
243773
|
+
const initial2 = await fetcher(parsed.href, {
|
|
243774
|
+
headers: authHeaders,
|
|
243775
|
+
redirect: "manual",
|
|
243776
|
+
...params.signal ? { signal: params.signal } : {}
|
|
243777
|
+
});
|
|
243778
|
+
let response = initial2;
|
|
243779
|
+
if (initial2.status >= 300 && initial2.status < 400) {
|
|
243780
|
+
const location = initial2.headers.get("location");
|
|
243781
|
+
if (location) {
|
|
243782
|
+
const resolved = new URL(location, parsed.href);
|
|
243783
|
+
response = await fetcher(resolved.href, {
|
|
243784
|
+
...resolved.origin === parsed.origin ? { headers: authHeaders } : {},
|
|
243785
|
+
redirect: "follow",
|
|
243786
|
+
...params.signal ? { signal: params.signal } : {}
|
|
243787
|
+
});
|
|
243788
|
+
}
|
|
243789
|
+
}
|
|
243790
|
+
if (!response.ok) {
|
|
243791
|
+
throw new Error(`Slack attachment fetch failed with HTTP ${response.status}.`);
|
|
243792
|
+
}
|
|
243793
|
+
if (!response.body) {
|
|
243794
|
+
throw new Error("Slack attachment response did not include a body.");
|
|
243795
|
+
}
|
|
243796
|
+
const responseMimeType = response.headers.get("content-type")?.split(";")[0]?.trim() || undefined;
|
|
243797
|
+
const metadata = resolveSlackFileMetadata({
|
|
243798
|
+
file: params.file,
|
|
243799
|
+
url: rawUrl,
|
|
243800
|
+
responseMimeType
|
|
243801
|
+
});
|
|
243802
|
+
return {
|
|
243803
|
+
body: response.body,
|
|
243804
|
+
...metadata,
|
|
243805
|
+
contentLength: parseContentLength(response)
|
|
243806
|
+
};
|
|
243807
|
+
}
|
|
243808
|
+
var MAX_SLACK_ATTACHMENTS = 8, ALLOWED_SLACK_HOST_SUFFIXES;
|
|
243809
|
+
var init_attachment_primitives = __esm(() => {
|
|
243810
|
+
ALLOWED_SLACK_HOST_SUFFIXES = [
|
|
243811
|
+
"slack.com",
|
|
243812
|
+
"slack-edge.com",
|
|
243813
|
+
"slack-files.com"
|
|
243814
|
+
];
|
|
243815
|
+
});
|
|
243816
|
+
|
|
243817
|
+
// src/channels/slack/attachment-stream.ts
|
|
243818
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
243819
|
+
import { mkdir as mkdir9, open as open2, rename as rename2, rm as rm7 } from "node:fs/promises";
|
|
243820
|
+
import { join as join43 } from "node:path";
|
|
243821
|
+
function sanitizeFileName(name) {
|
|
243822
|
+
const normalized = name.trim().replace(/[^\w.-]+/g, "_");
|
|
243823
|
+
return normalized.length > 0 ? normalized : "attachment";
|
|
243824
|
+
}
|
|
243825
|
+
async function readWithIdleTimeout(reader, idleTimeoutMs, signal) {
|
|
243826
|
+
if (signal?.aborted) {
|
|
243827
|
+
throw new SlackAttachmentDownloadError("download_failed", "Slack attachment download was aborted.");
|
|
243828
|
+
}
|
|
243829
|
+
let timeoutHandle;
|
|
243830
|
+
let onAbort;
|
|
243831
|
+
try {
|
|
243832
|
+
return await new Promise((resolve32, reject2) => {
|
|
243833
|
+
timeoutHandle = setTimeout(() => {
|
|
243834
|
+
reject2(new SlackAttachmentDownloadError("download_failed", `Slack attachment download stalled (no data received for ${idleTimeoutMs}ms).`));
|
|
243835
|
+
}, idleTimeoutMs);
|
|
243836
|
+
if (signal) {
|
|
243837
|
+
onAbort = () => reject2(new SlackAttachmentDownloadError("download_failed", "Slack attachment download was aborted."));
|
|
243838
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
243839
|
+
}
|
|
243840
|
+
reader.read().then(resolve32, reject2);
|
|
243841
|
+
});
|
|
243842
|
+
} finally {
|
|
243843
|
+
if (timeoutHandle !== undefined) {
|
|
243844
|
+
clearTimeout(timeoutHandle);
|
|
243845
|
+
}
|
|
243846
|
+
if (signal && onAbort) {
|
|
243847
|
+
signal.removeEventListener("abort", onAbort);
|
|
243848
|
+
}
|
|
243849
|
+
}
|
|
243850
|
+
}
|
|
243851
|
+
async function saveSlackAttachmentStream(params) {
|
|
243852
|
+
const inboundDir = join43(getChannelDir("slack"), "inbound", sanitizeFileName(params.accountId));
|
|
243853
|
+
await mkdir9(inboundDir, { recursive: true });
|
|
243854
|
+
const filePath = join43(inboundDir, `${Date.now()}-${randomUUID15()}-${sanitizeFileName(params.fileName)}`);
|
|
243855
|
+
const temporaryPath = `${filePath}.partial`;
|
|
243856
|
+
const fileHandle = await open2(temporaryPath, "wx");
|
|
243857
|
+
const reader = params.body.getReader();
|
|
243858
|
+
const readIdleTimeoutMs = params.readIdleTimeoutMs ?? SLACK_ATTACHMENT_READ_IDLE_TIMEOUT_MS;
|
|
243859
|
+
let sizeBytes = 0;
|
|
243860
|
+
let completed = false;
|
|
243861
|
+
try {
|
|
243862
|
+
while (true) {
|
|
243863
|
+
const { done, value } = await readWithIdleTimeout(reader, readIdleTimeoutMs, params.signal);
|
|
243864
|
+
if (done) {
|
|
243865
|
+
break;
|
|
243866
|
+
}
|
|
243867
|
+
if (!value?.byteLength) {
|
|
243868
|
+
continue;
|
|
243869
|
+
}
|
|
243870
|
+
sizeBytes += value.byteLength;
|
|
243871
|
+
if (params.maxBytes !== undefined && sizeBytes > params.maxBytes) {
|
|
243872
|
+
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment exceeds automatic download limit (${params.maxBytes} bytes).`);
|
|
243873
|
+
}
|
|
243874
|
+
let offset = 0;
|
|
243875
|
+
while (offset < value.byteLength) {
|
|
243876
|
+
const { bytesWritten } = await fileHandle.write(value, offset, value.byteLength - offset);
|
|
243877
|
+
if (bytesWritten <= 0) {
|
|
243878
|
+
throw new Error("Slack attachment write made no progress.");
|
|
243879
|
+
}
|
|
243880
|
+
offset += bytesWritten;
|
|
243881
|
+
}
|
|
243882
|
+
}
|
|
243883
|
+
completed = true;
|
|
243884
|
+
} finally {
|
|
243885
|
+
if (!completed) {
|
|
243886
|
+
await reader.cancel().catch(() => {
|
|
243887
|
+
return;
|
|
243888
|
+
});
|
|
243889
|
+
}
|
|
243890
|
+
try {
|
|
243891
|
+
reader.releaseLock();
|
|
243892
|
+
} catch {}
|
|
243893
|
+
await fileHandle.close().catch(() => {
|
|
243894
|
+
return;
|
|
243895
|
+
});
|
|
243896
|
+
if (!completed) {
|
|
243897
|
+
await rm7(temporaryPath, { force: true }).catch(() => {
|
|
243898
|
+
return;
|
|
243899
|
+
});
|
|
243900
|
+
}
|
|
243901
|
+
}
|
|
243902
|
+
try {
|
|
243903
|
+
await rename2(temporaryPath, filePath);
|
|
243904
|
+
} catch (error54) {
|
|
243905
|
+
await rm7(temporaryPath, { force: true }).catch(() => {
|
|
243906
|
+
return;
|
|
243907
|
+
});
|
|
243908
|
+
throw error54;
|
|
243909
|
+
}
|
|
243910
|
+
return { localPath: filePath, sizeBytes };
|
|
243911
|
+
}
|
|
243912
|
+
var SlackAttachmentDownloadError, SLACK_ATTACHMENT_READ_IDLE_TIMEOUT_MS = 60000;
|
|
243913
|
+
var init_attachment_stream = __esm(() => {
|
|
243914
|
+
init_config2();
|
|
243915
|
+
SlackAttachmentDownloadError = class SlackAttachmentDownloadError extends Error {
|
|
243916
|
+
reason;
|
|
243917
|
+
constructor(reason, message) {
|
|
243918
|
+
super(message);
|
|
243919
|
+
this.reason = reason;
|
|
243920
|
+
this.name = "SlackAttachmentDownloadError";
|
|
243921
|
+
}
|
|
243922
|
+
};
|
|
243923
|
+
});
|
|
243924
|
+
|
|
243925
|
+
// src/channels/slack/media.ts
|
|
243926
|
+
async function mapSlackThreadMessage(message, attachmentOptions, sourceThreadId) {
|
|
243927
|
+
const attachments = await resolveSlackMessageAttachments(message, attachmentOptions, sourceThreadId);
|
|
243928
|
+
return {
|
|
243929
|
+
text: resolveSlackThreadMessageText(message),
|
|
243930
|
+
userId: isNonEmptyString7(message.user) ? message.user : undefined,
|
|
243931
|
+
botId: isNonEmptyString7(message.bot_id) ? message.bot_id : undefined,
|
|
243932
|
+
ts: isNonEmptyString7(message.ts) ? message.ts : undefined,
|
|
243933
|
+
...attachments.length > 0 ? { attachments } : {}
|
|
243934
|
+
};
|
|
243935
|
+
}
|
|
243936
|
+
function asRecord5(value) {
|
|
243937
|
+
return value && typeof value === "object" ? value : null;
|
|
243938
|
+
}
|
|
243939
|
+
function isNonEmptyString7(value) {
|
|
243940
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
243941
|
+
}
|
|
243942
|
+
function normalizeSlackAttachmentLike2(value) {
|
|
243943
|
+
const record5 = asRecord5(value);
|
|
243944
|
+
if (!record5) {
|
|
243945
|
+
return null;
|
|
243946
|
+
}
|
|
243947
|
+
return {
|
|
243948
|
+
text: isNonEmptyString7(record5.text) ? record5.text : undefined,
|
|
243949
|
+
fallback: isNonEmptyString7(record5.fallback) ? record5.fallback : undefined,
|
|
243950
|
+
pretext: isNonEmptyString7(record5.pretext) ? record5.pretext : undefined,
|
|
243951
|
+
author_name: isNonEmptyString7(record5.author_name) ? record5.author_name : undefined,
|
|
243952
|
+
title: isNonEmptyString7(record5.title) ? record5.title : undefined
|
|
243953
|
+
};
|
|
243954
|
+
}
|
|
243955
|
+
function uniqueNonEmptyStrings(values3) {
|
|
243956
|
+
const seen = new Set;
|
|
243957
|
+
const normalized = [];
|
|
243958
|
+
for (const value of values3) {
|
|
243959
|
+
const text2 = value?.trim();
|
|
243960
|
+
if (!text2 || seen.has(text2)) {
|
|
243961
|
+
continue;
|
|
243962
|
+
}
|
|
243963
|
+
seen.add(text2);
|
|
243964
|
+
normalized.push(text2);
|
|
243965
|
+
}
|
|
243966
|
+
return normalized;
|
|
243967
|
+
}
|
|
243968
|
+
function resolveSlackAttachmentText(attachment) {
|
|
243969
|
+
const parts = uniqueNonEmptyStrings([
|
|
243970
|
+
attachment.pretext,
|
|
243971
|
+
attachment.author_name,
|
|
243972
|
+
attachment.title,
|
|
243973
|
+
attachment.text,
|
|
243974
|
+
attachment.fallback
|
|
243975
|
+
]);
|
|
243976
|
+
return parts.join(`
|
|
243977
|
+
`);
|
|
243978
|
+
}
|
|
243979
|
+
function resolveSlackThreadMessageText(message) {
|
|
243980
|
+
const text2 = typeof message.text === "string" ? message.text.trim() : "";
|
|
243981
|
+
if (text2) {
|
|
243982
|
+
return text2;
|
|
243983
|
+
}
|
|
243984
|
+
const attachmentTexts = Array.isArray(message.attachments) ? message.attachments.map((entry) => normalizeSlackAttachmentLike2(entry)).filter((entry) => Boolean(entry)).map((attachment) => resolveSlackAttachmentText(attachment)).filter(isNonEmptyString7) : [];
|
|
243985
|
+
if (attachmentTexts.length > 0) {
|
|
243986
|
+
return attachmentTexts.join(`
|
|
243987
|
+
|
|
243988
|
+
`);
|
|
243989
|
+
}
|
|
243990
|
+
const files2 = collectSlackFiles(message);
|
|
243991
|
+
if (files2.length === 0) {
|
|
243992
|
+
return "";
|
|
243993
|
+
}
|
|
243994
|
+
const fileNames = files2.map((file3) => file3.name ?? "file").join(", ");
|
|
243995
|
+
return `[attached: ${fileNames}]`;
|
|
243996
|
+
}
|
|
244059
243997
|
function resolveAttachmentKind(mimeType) {
|
|
244060
243998
|
const normalized = mimeType?.toLowerCase();
|
|
244061
243999
|
if (!normalized) {
|
|
@@ -244072,47 +244010,9 @@ function resolveAttachmentKind(mimeType) {
|
|
|
244072
244010
|
}
|
|
244073
244011
|
return "file";
|
|
244074
244012
|
}
|
|
244075
|
-
async function fetchWithSlackAuth(url2, token2, signal) {
|
|
244076
|
-
const parsed = assertSlackFileUrl(url2);
|
|
244077
|
-
const authHeaders = { Authorization: `Bearer ${token2}` };
|
|
244078
|
-
const initial2 = await fetch(parsed.href, {
|
|
244079
|
-
headers: authHeaders,
|
|
244080
|
-
redirect: "manual",
|
|
244081
|
-
...signal ? { signal } : {}
|
|
244082
|
-
});
|
|
244083
|
-
if (initial2.status < 300 || initial2.status >= 400) {
|
|
244084
|
-
return initial2;
|
|
244085
|
-
}
|
|
244086
|
-
const redirectUrl = initial2.headers.get("location");
|
|
244087
|
-
if (!redirectUrl) {
|
|
244088
|
-
return initial2;
|
|
244089
|
-
}
|
|
244090
|
-
const resolved = new URL(redirectUrl, parsed.href);
|
|
244091
|
-
if (resolved.origin === parsed.origin) {
|
|
244092
|
-
return fetch(resolved.href, {
|
|
244093
|
-
headers: authHeaders,
|
|
244094
|
-
redirect: "follow",
|
|
244095
|
-
...signal ? { signal } : {}
|
|
244096
|
-
});
|
|
244097
|
-
}
|
|
244098
|
-
return fetch(resolved.href, {
|
|
244099
|
-
redirect: "follow",
|
|
244100
|
-
...signal ? { signal } : {}
|
|
244101
|
-
});
|
|
244102
|
-
}
|
|
244103
|
-
function resolveSlackAttachmentFileName(params) {
|
|
244104
|
-
const hintedName = params.file.name ?? (params.url ? basename14(new URL(params.url).pathname) : undefined) ?? `${params.file.id ?? "attachment"}${extensionForMimeType2(params.file.mimetype)}`;
|
|
244105
|
-
return extname7(hintedName) || !params.mimeType ? hintedName : `${hintedName}${extensionForMimeType2(params.mimeType)}`;
|
|
244106
|
-
}
|
|
244107
|
-
function resolveSlackAttachmentMimeType(params) {
|
|
244108
|
-
const preferredMimeType = params.responseMimeType && !isGenericSlackMimeType(params.responseMimeType) ? params.responseMimeType : params.file.mimetype && !isGenericSlackMimeType(params.file.mimetype) ? params.file.mimetype : undefined;
|
|
244109
|
-
return resolveMimeType(params.fileName, preferredMimeType);
|
|
244110
|
-
}
|
|
244111
244013
|
function createUndownloadedSlackAttachment(params) {
|
|
244112
|
-
const fileName =
|
|
244113
|
-
|
|
244114
|
-
file: params.file,
|
|
244115
|
-
fileName
|
|
244014
|
+
const { fileName, mimeType } = resolveSlackFileMetadata({
|
|
244015
|
+
file: params.file
|
|
244116
244016
|
});
|
|
244117
244017
|
return {
|
|
244118
244018
|
id: params.file.id,
|
|
@@ -244134,42 +244034,24 @@ async function materializeSlackAttachment(params) {
|
|
|
244134
244034
|
if (!url2) {
|
|
244135
244035
|
throw new SlackAttachmentDownloadError("missing_download_url", "Slack attachment does not include a private download URL.");
|
|
244136
244036
|
}
|
|
244137
|
-
const
|
|
244037
|
+
const fetched = await fetchSlackFile({
|
|
244038
|
+
token: params.token,
|
|
244039
|
+
file: params.file,
|
|
244040
|
+
signal: params.signal
|
|
244041
|
+
}).catch((error54) => {
|
|
244138
244042
|
throw new SlackAttachmentDownloadError("download_failed", error54 instanceof Error ? error54.message : "Slack attachment fetch failed.");
|
|
244139
244043
|
});
|
|
244140
|
-
if (
|
|
244141
|
-
|
|
244142
|
-
}
|
|
244143
|
-
const contentLengthHeader = response.headers.get("content-length");
|
|
244144
|
-
const contentLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
|
|
244145
|
-
if (params.maxBytes !== undefined && contentLength !== undefined && Number.isFinite(contentLength) && contentLength > params.maxBytes) {
|
|
244146
|
-
await response.body?.cancel().catch(() => {
|
|
244044
|
+
if (params.maxBytes !== undefined && fetched.contentLength !== undefined && fetched.contentLength > params.maxBytes) {
|
|
244045
|
+
await fetched.body.cancel().catch(() => {
|
|
244147
244046
|
return;
|
|
244148
244047
|
});
|
|
244149
|
-
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${contentLength} bytes; automatic download limit is ${params.maxBytes} bytes.`);
|
|
244150
|
-
}
|
|
244151
|
-
const responseMimeType = response.headers.get("content-type")?.split(";")[0]?.trim() || undefined;
|
|
244152
|
-
const hintedName = resolveSlackAttachmentFileName({
|
|
244153
|
-
file: params.file,
|
|
244154
|
-
url: url2
|
|
244155
|
-
});
|
|
244156
|
-
const mimeType = resolveSlackAttachmentMimeType({
|
|
244157
|
-
file: params.file,
|
|
244158
|
-
fileName: hintedName,
|
|
244159
|
-
responseMimeType
|
|
244160
|
-
});
|
|
244161
|
-
const fileName = resolveSlackAttachmentFileName({
|
|
244162
|
-
file: params.file,
|
|
244163
|
-
url: url2,
|
|
244164
|
-
mimeType
|
|
244165
|
-
});
|
|
244166
|
-
if (!response.body) {
|
|
244167
|
-
throw new SlackAttachmentDownloadError("download_failed", "Slack attachment response did not include a body.");
|
|
244048
|
+
throw new SlackAttachmentDownloadError("exceeds_auto_download_limit", `Slack attachment is ${fetched.contentLength} bytes; automatic download limit is ${params.maxBytes} bytes.`);
|
|
244168
244049
|
}
|
|
244050
|
+
const { fileName, mimeType } = fetched;
|
|
244169
244051
|
const saved = await saveSlackAttachmentStream({
|
|
244170
244052
|
accountId: params.accountId,
|
|
244171
244053
|
fileName,
|
|
244172
|
-
body:
|
|
244054
|
+
body: fetched.body,
|
|
244173
244055
|
maxBytes: params.maxBytes,
|
|
244174
244056
|
signal: params.signal
|
|
244175
244057
|
});
|
|
@@ -244200,40 +244082,6 @@ async function materializeSlackAttachment(params) {
|
|
|
244200
244082
|
}
|
|
244201
244083
|
return attachment;
|
|
244202
244084
|
}
|
|
244203
|
-
function collectSlackFiles(rawEvent) {
|
|
244204
|
-
const record5 = asRecord4(rawEvent);
|
|
244205
|
-
if (!record5) {
|
|
244206
|
-
return [];
|
|
244207
|
-
}
|
|
244208
|
-
const deduped = new Map;
|
|
244209
|
-
const push = (file3) => {
|
|
244210
|
-
if (!file3) {
|
|
244211
|
-
return;
|
|
244212
|
-
}
|
|
244213
|
-
const key2 = file3.id ?? file3.url_private_download ?? file3.url_private ?? `${file3.name ?? "attachment"}:${file3.mimetype ?? ""}`;
|
|
244214
|
-
deduped.set(key2, file3);
|
|
244215
|
-
};
|
|
244216
|
-
if (Array.isArray(record5.files)) {
|
|
244217
|
-
for (const entry of record5.files) {
|
|
244218
|
-
push(normalizeSlackFileLike(entry));
|
|
244219
|
-
}
|
|
244220
|
-
}
|
|
244221
|
-
if (Array.isArray(record5.attachments)) {
|
|
244222
|
-
record5.attachments.map((entry) => normalizeSlackAttachmentLike(entry)).filter((entry) => Boolean(entry)).forEach((attachment, index) => {
|
|
244223
|
-
for (const file3 of attachment.files ?? []) {
|
|
244224
|
-
push(file3);
|
|
244225
|
-
}
|
|
244226
|
-
if (attachment.image_url) {
|
|
244227
|
-
push({
|
|
244228
|
-
id: `attachment-image-${index}`,
|
|
244229
|
-
name: `attachment-image-${index}.png`,
|
|
244230
|
-
url_private: attachment.image_url
|
|
244231
|
-
});
|
|
244232
|
-
}
|
|
244233
|
-
});
|
|
244234
|
-
}
|
|
244235
|
-
return Array.from(deduped.values()).slice(0, MAX_SLACK_ATTACHMENTS);
|
|
244236
|
-
}
|
|
244237
244085
|
async function resolveSlackFilesAsAttachments(params) {
|
|
244238
244086
|
if (params.files.length === 0) {
|
|
244239
244087
|
return [];
|
|
@@ -244262,7 +244110,7 @@ async function resolveSlackFilesAsAttachments(params) {
|
|
|
244262
244110
|
return resolved;
|
|
244263
244111
|
}
|
|
244264
244112
|
function resolveSlackThreadAttachmentOptions(params) {
|
|
244265
|
-
if (!
|
|
244113
|
+
if (!isNonEmptyString7(params.accountId) || !isNonEmptyString7(params.token)) {
|
|
244266
244114
|
return;
|
|
244267
244115
|
}
|
|
244268
244116
|
return {
|
|
@@ -244289,18 +244137,18 @@ async function resolveSlackMessageAttachments(message, attachmentOptions, source
|
|
|
244289
244137
|
token: attachmentOptions.token,
|
|
244290
244138
|
files: collectSlackFiles(message),
|
|
244291
244139
|
sourceMessageId: message.ts,
|
|
244292
|
-
sourceThreadId: sourceThreadId ?? (
|
|
244140
|
+
sourceThreadId: sourceThreadId ?? (isNonEmptyString7(message.thread_ts) ? message.thread_ts : null),
|
|
244293
244141
|
transcribeVoice: attachmentOptions.transcribeVoice
|
|
244294
244142
|
});
|
|
244295
244143
|
}
|
|
244296
244144
|
async function resolveSlackInboundAttachments(params) {
|
|
244297
|
-
const rawEvent =
|
|
244145
|
+
const rawEvent = asRecord5(params.rawEvent);
|
|
244298
244146
|
return resolveSlackFilesAsAttachments({
|
|
244299
244147
|
accountId: params.accountId,
|
|
244300
244148
|
token: params.token,
|
|
244301
244149
|
files: collectSlackFiles(params.rawEvent),
|
|
244302
|
-
sourceMessageId:
|
|
244303
|
-
sourceThreadId:
|
|
244150
|
+
sourceMessageId: isNonEmptyString7(rawEvent?.ts) ? rawEvent.ts : undefined,
|
|
244151
|
+
sourceThreadId: isNonEmptyString7(rawEvent?.thread_ts) ? rawEvent.thread_ts : null,
|
|
244304
244152
|
transcribeVoice: params.transcribeVoice
|
|
244305
244153
|
});
|
|
244306
244154
|
}
|
|
@@ -244309,28 +244157,24 @@ async function resolveSlackCurrentMessageAttachments(params) {
|
|
|
244309
244157
|
if (!attachmentOptions) {
|
|
244310
244158
|
return [];
|
|
244311
244159
|
}
|
|
244312
|
-
const fetchLimit = 200;
|
|
244313
|
-
let cursor;
|
|
244314
244160
|
try {
|
|
244315
|
-
|
|
244316
|
-
|
|
244317
|
-
|
|
244318
|
-
|
|
244319
|
-
|
|
244320
|
-
|
|
244321
|
-
|
|
244322
|
-
|
|
244323
|
-
|
|
244324
|
-
|
|
244325
|
-
|
|
244326
|
-
|
|
244327
|
-
|
|
244328
|
-
|
|
244329
|
-
} while (cursor);
|
|
244161
|
+
const files2 = await resolveSlackMessageFiles({
|
|
244162
|
+
channelId: params.channelId,
|
|
244163
|
+
threadTs: params.threadTs,
|
|
244164
|
+
messageTs: params.messageTs,
|
|
244165
|
+
client: params.client
|
|
244166
|
+
});
|
|
244167
|
+
return files2 ? resolveSlackFilesAsAttachments({
|
|
244168
|
+
accountId: attachmentOptions.accountId,
|
|
244169
|
+
token: attachmentOptions.token,
|
|
244170
|
+
files: files2,
|
|
244171
|
+
sourceMessageId: params.messageTs,
|
|
244172
|
+
sourceThreadId: params.threadTs,
|
|
244173
|
+
transcribeVoice: attachmentOptions.transcribeVoice
|
|
244174
|
+
}) : [];
|
|
244330
244175
|
} catch {
|
|
244331
244176
|
return [];
|
|
244332
244177
|
}
|
|
244333
|
-
return [];
|
|
244334
244178
|
}
|
|
244335
244179
|
async function resolveSlackThreadStarter(params) {
|
|
244336
244180
|
try {
|
|
@@ -244379,13 +244223,13 @@ async function resolveSlackThreadHistory(params) {
|
|
|
244379
244223
|
if (message.ts === params.threadTs) {
|
|
244380
244224
|
continue;
|
|
244381
244225
|
}
|
|
244382
|
-
const isBotMessage =
|
|
244226
|
+
const isBotMessage = isNonEmptyString7(message.bot_id);
|
|
244383
244227
|
if (params.include === "unrouted-bot") {
|
|
244384
244228
|
if (!isBotMessage) {
|
|
244385
244229
|
retained.length = 0;
|
|
244386
244230
|
continue;
|
|
244387
244231
|
}
|
|
244388
|
-
if (
|
|
244232
|
+
if (isNonEmptyString7(params.excludeBotId) && message.bot_id === params.excludeBotId) {
|
|
244389
244233
|
continue;
|
|
244390
244234
|
}
|
|
244391
244235
|
if (params.acceptMentionedBots === true && hasSlackMention(message.text ?? "", params.routedBotUserId ?? null)) {
|
|
@@ -244393,7 +244237,7 @@ async function resolveSlackThreadHistory(params) {
|
|
|
244393
244237
|
continue;
|
|
244394
244238
|
}
|
|
244395
244239
|
}
|
|
244396
|
-
if (params.include === "bot" && !
|
|
244240
|
+
if (params.include === "bot" && !isNonEmptyString7(message.bot_id)) {
|
|
244397
244241
|
continue;
|
|
244398
244242
|
}
|
|
244399
244243
|
if (!hasSlackThreadMessageContent(message, attachmentOptions)) {
|
|
@@ -244404,8 +244248,8 @@ async function resolveSlackThreadHistory(params) {
|
|
|
244404
244248
|
retained.shift();
|
|
244405
244249
|
}
|
|
244406
244250
|
}
|
|
244407
|
-
const
|
|
244408
|
-
cursor = typeof
|
|
244251
|
+
const nextCursor2 = response.response_metadata?.next_cursor;
|
|
244252
|
+
cursor = typeof nextCursor2 === "string" && nextCursor2.trim().length > 0 ? nextCursor2.trim() : undefined;
|
|
244409
244253
|
} while (cursor);
|
|
244410
244254
|
const mapped3 = await Promise.all(retained.map((message) => mapSlackThreadMessage(message, attachmentOptions, params.threadTs)));
|
|
244411
244255
|
return mapped3.filter(hasHydratedSlackThreadMessageContent);
|
|
@@ -244439,57 +244283,21 @@ async function resolveSlackChannelHistory(params) {
|
|
|
244439
244283
|
return [];
|
|
244440
244284
|
}
|
|
244441
244285
|
}
|
|
244442
|
-
var
|
|
244286
|
+
var MAX_SLACK_ATTACHMENT_BYTES;
|
|
244443
244287
|
var init_media2 = __esm(() => {
|
|
244288
|
+
init_attachment_primitives();
|
|
244444
244289
|
init_attachment_stream();
|
|
244445
244290
|
init_utils6();
|
|
244446
244291
|
MAX_SLACK_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
244447
|
-
ALLOWED_SLACK_HOST_SUFFIXES = [
|
|
244448
|
-
"slack.com",
|
|
244449
|
-
"slack-edge.com",
|
|
244450
|
-
"slack-files.com"
|
|
244451
|
-
];
|
|
244452
244292
|
});
|
|
244453
244293
|
|
|
244454
244294
|
// src/channels/slack/attachment-download.ts
|
|
244455
|
-
function isNonEmptyString7(value) {
|
|
244456
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
244457
|
-
}
|
|
244458
|
-
async function resolveCanonicalSlackMessage(params) {
|
|
244459
|
-
if (isNonEmptyString7(params.threadTs)) {
|
|
244460
|
-
let cursor;
|
|
244461
|
-
do {
|
|
244462
|
-
const response2 = await params.client.conversations.replies({
|
|
244463
|
-
channel: params.channelId,
|
|
244464
|
-
ts: params.threadTs,
|
|
244465
|
-
limit: 200,
|
|
244466
|
-
inclusive: true,
|
|
244467
|
-
...cursor ? { cursor } : {}
|
|
244468
|
-
});
|
|
244469
|
-
const message = (response2.messages ?? []).find((entry) => entry.ts === params.messageTs);
|
|
244470
|
-
if (message) {
|
|
244471
|
-
return message;
|
|
244472
|
-
}
|
|
244473
|
-
const nextCursor = response2.response_metadata?.next_cursor;
|
|
244474
|
-
cursor = isNonEmptyString7(nextCursor) ? nextCursor.trim() : undefined;
|
|
244475
|
-
} while (cursor);
|
|
244476
|
-
return null;
|
|
244477
|
-
}
|
|
244478
|
-
const response = await params.client.conversations.history({
|
|
244479
|
-
channel: params.channelId,
|
|
244480
|
-
oldest: params.messageTs,
|
|
244481
|
-
latest: params.messageTs,
|
|
244482
|
-
inclusive: true,
|
|
244483
|
-
limit: 1
|
|
244484
|
-
});
|
|
244485
|
-
return (response.messages ?? []).find((entry) => entry.ts === params.messageTs) ?? null;
|
|
244486
|
-
}
|
|
244487
244295
|
async function downloadSlackAttachmentById(params) {
|
|
244488
|
-
const
|
|
244489
|
-
if (!
|
|
244296
|
+
const files2 = await resolveSlackMessageFiles(params);
|
|
244297
|
+
if (!files2) {
|
|
244490
244298
|
throw new Error(`Slack message ${params.messageTs} was not found in chat ${params.channelId}.`);
|
|
244491
244299
|
}
|
|
244492
|
-
const file3 =
|
|
244300
|
+
const file3 = files2.find((entry) => entry.id === params.attachmentId);
|
|
244493
244301
|
if (!file3) {
|
|
244494
244302
|
throw new Error(`Slack attachment ${params.attachmentId} is not attached to message ${params.messageTs}.`);
|
|
244495
244303
|
}
|
|
@@ -244503,14 +244311,15 @@ async function downloadSlackAttachmentById(params) {
|
|
|
244503
244311
|
});
|
|
244504
244312
|
}
|
|
244505
244313
|
var init_attachment_download = __esm(() => {
|
|
244314
|
+
init_attachment_primitives();
|
|
244506
244315
|
init_media2();
|
|
244507
244316
|
});
|
|
244508
244317
|
|
|
244509
244318
|
// src/channels/slack/file-upload.ts
|
|
244510
244319
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
244511
|
-
import { basename as
|
|
244320
|
+
import { basename as basename14, extname as extname7 } from "node:path";
|
|
244512
244321
|
function resolveUploadMimeType(filePath) {
|
|
244513
|
-
switch (
|
|
244322
|
+
switch (extname7(filePath).toLowerCase()) {
|
|
244514
244323
|
case ".png":
|
|
244515
244324
|
return "image/png";
|
|
244516
244325
|
case ".jpg":
|
|
@@ -244535,7 +244344,7 @@ async function uploadSlackFile(slackClient, msg) {
|
|
|
244535
244344
|
throw new Error("mediaPath is required for Slack file uploads.");
|
|
244536
244345
|
}
|
|
244537
244346
|
const buffer = await readFile14(msg.mediaPath);
|
|
244538
|
-
const uploadFileName = msg.fileName ??
|
|
244347
|
+
const uploadFileName = msg.fileName ?? basename14(msg.mediaPath);
|
|
244539
244348
|
const uploadTitle = msg.title ?? uploadFileName;
|
|
244540
244349
|
const uploadMimeType = resolveUploadMimeType(uploadFileName);
|
|
244541
244350
|
const uploadUrlResp = await slackClient.files.getUploadURLExternal({
|
|
@@ -246703,6 +246512,7 @@ function createSlackAdapter(config3) {
|
|
|
246703
246512
|
let running = false;
|
|
246704
246513
|
let botUserId = null;
|
|
246705
246514
|
let botId = null;
|
|
246515
|
+
let workspaceName = null;
|
|
246706
246516
|
let adapter;
|
|
246707
246517
|
const agentThreadTracker = createAgentThreadTracker();
|
|
246708
246518
|
const debounce4 = createSlackInboundDebounceController({
|
|
@@ -246730,12 +246540,21 @@ function createSlackAdapter(config3) {
|
|
|
246730
246540
|
async function ensureApp() {
|
|
246731
246541
|
if (app)
|
|
246732
246542
|
return app;
|
|
246543
|
+
const auth = await (await ensureWriteClient()).auth.test();
|
|
246544
|
+
if (!isNonEmptyString4(auth.user_id) || !isNonEmptyString4(auth.bot_id)) {
|
|
246545
|
+
throw new Error("Slack auth.test did not return bot identity fields");
|
|
246546
|
+
}
|
|
246547
|
+
botUserId = auth.user_id;
|
|
246548
|
+
botId = auth.bot_id;
|
|
246549
|
+
workspaceName = isNonEmptyString4(auth.team) ? auth.team : null;
|
|
246733
246550
|
const bolt = await loadSlackBoltModule();
|
|
246734
246551
|
const App2 = resolveSlackAppConstructor(bolt);
|
|
246735
246552
|
const instance = new App2({
|
|
246736
246553
|
token: config3.botToken,
|
|
246737
246554
|
appToken: config3.appToken,
|
|
246738
|
-
socketMode: true
|
|
246555
|
+
socketMode: true,
|
|
246556
|
+
botUserId,
|
|
246557
|
+
botId
|
|
246739
246558
|
});
|
|
246740
246559
|
instance.error(async (error54) => {
|
|
246741
246560
|
console.error("[Slack] Unhandled app error:", error54);
|
|
@@ -246940,13 +246759,9 @@ function createSlackAdapter(config3) {
|
|
|
246940
246759
|
if (running)
|
|
246941
246760
|
return;
|
|
246942
246761
|
const slackApp = await ensureApp();
|
|
246943
|
-
const auth = await slackApp.client.auth.test();
|
|
246944
|
-
const authRecord = auth;
|
|
246945
|
-
botUserId = isNonEmptyString4(authRecord.user_id) ? authRecord.user_id : null;
|
|
246946
|
-
botId = isNonEmptyString4(authRecord.bot_id) ? authRecord.bot_id : null;
|
|
246947
246762
|
await slackApp.start();
|
|
246948
246763
|
running = true;
|
|
246949
|
-
console.log(`[Slack] App started for workspace ${
|
|
246764
|
+
console.log(`[Slack] App started for workspace ${workspaceName ?? "unknown"} (dm_policy: ${config3.dmPolicy})`);
|
|
246950
246765
|
},
|
|
246951
246766
|
async stop() {
|
|
246952
246767
|
if (!app || !running)
|
|
@@ -246959,6 +246774,7 @@ function createSlackAdapter(config3) {
|
|
|
246959
246774
|
writeClientPromise = null;
|
|
246960
246775
|
botUserId = null;
|
|
246961
246776
|
botId = null;
|
|
246777
|
+
workspaceName = null;
|
|
246962
246778
|
status.clear();
|
|
246963
246779
|
approvals.clear();
|
|
246964
246780
|
debounce4.clear();
|
|
@@ -247391,8 +247207,8 @@ async function listSlackChannels(account, existingClient) {
|
|
|
247391
247207
|
name: channel.name
|
|
247392
247208
|
});
|
|
247393
247209
|
}
|
|
247394
|
-
const
|
|
247395
|
-
cursor =
|
|
247210
|
+
const nextCursor2 = response.response_metadata?.next_cursor?.trim();
|
|
247211
|
+
cursor = nextCursor2 ? nextCursor2 : undefined;
|
|
247396
247212
|
} while (cursor);
|
|
247397
247213
|
return channels;
|
|
247398
247214
|
}
|
|
@@ -248198,7 +248014,7 @@ var init_typing_controller2 = __esm(() => {
|
|
|
248198
248014
|
});
|
|
248199
248015
|
|
|
248200
248016
|
// src/channels/discord/adapter.ts
|
|
248201
|
-
import { basename as
|
|
248017
|
+
import { basename as basename15 } from "node:path";
|
|
248202
248018
|
function createDiscordAdapter(config3) {
|
|
248203
248019
|
let client = null;
|
|
248204
248020
|
let running = false;
|
|
@@ -248741,7 +248557,7 @@ function createDiscordAdapter(config3) {
|
|
|
248741
248557
|
files: [
|
|
248742
248558
|
{
|
|
248743
248559
|
attachment: msg.mediaPath,
|
|
248744
|
-
name: msg.fileName ??
|
|
248560
|
+
name: msg.fileName ?? basename15(msg.mediaPath)
|
|
248745
248561
|
}
|
|
248746
248562
|
]
|
|
248747
248563
|
});
|
|
@@ -249101,12 +248917,12 @@ var init_plugin4 = __esm(() => {
|
|
|
249101
248917
|
|
|
249102
248918
|
// src/channels/whatsapp/attachment-policy.ts
|
|
249103
248919
|
import { realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
|
|
249104
|
-
import { extname as
|
|
248920
|
+
import { extname as extname8, isAbsolute as isAbsolute23, relative as relative8, sep as sep6 } from "node:path";
|
|
249105
248921
|
function deny(reason) {
|
|
249106
248922
|
return { allowed: false, reason: `Attachment denied: ${reason}` };
|
|
249107
248923
|
}
|
|
249108
248924
|
function inferMimeType(mediaPath) {
|
|
249109
|
-
return WHATSAPP_ATTACHMENT_MIME_TYPES[
|
|
248925
|
+
return WHATSAPP_ATTACHMENT_MIME_TYPES[extname8(mediaPath).toLowerCase()] ?? "application/octet-stream";
|
|
249110
248926
|
}
|
|
249111
248927
|
function inferWhatsAppAttachmentMimeType(mediaPath) {
|
|
249112
248928
|
return inferMimeType(mediaPath);
|
|
@@ -249259,7 +249075,7 @@ var init_attachment_policy = __esm(() => {
|
|
|
249259
249075
|
// src/channels/whatsapp/media.ts
|
|
249260
249076
|
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
249261
249077
|
import { mkdir as mkdir10, writeFile as writeFile12 } from "node:fs/promises";
|
|
249262
|
-
import { basename as
|
|
249078
|
+
import { basename as basename16, extname as extname9, join as join45 } from "node:path";
|
|
249263
249079
|
function unwrapWhatsAppMessageContent(message) {
|
|
249264
249080
|
if (!message || typeof message !== "object")
|
|
249265
249081
|
return null;
|
|
@@ -249462,8 +249278,8 @@ function buildWhatsAppOutboundPayload(msg, resolvedMedia) {
|
|
|
249462
249278
|
return { text: msg.text };
|
|
249463
249279
|
}
|
|
249464
249280
|
const mediaPath = resolvedMedia?.mediaPath ?? msg.mediaPath;
|
|
249465
|
-
const fileName = resolvedMedia ?
|
|
249466
|
-
const extension = resolvedMedia ?
|
|
249281
|
+
const fileName = resolvedMedia ? basename16(mediaPath) : msg.fileName || basename16(mediaPath);
|
|
249282
|
+
const extension = resolvedMedia ? extname9(mediaPath).toLowerCase() : getWhatsAppOutboundMediaExtension(msg);
|
|
249467
249283
|
const caption = msg.text?.trim() || msg.title?.trim() || undefined;
|
|
249468
249284
|
if (WHATSAPP_IMAGE_EXTENSIONS.has(extension)) {
|
|
249469
249285
|
return { image: { url: mediaPath }, ...caption ? { caption } : {} };
|
|
@@ -249486,8 +249302,8 @@ function buildWhatsAppOutboundPayload(msg, resolvedMedia) {
|
|
|
249486
249302
|
};
|
|
249487
249303
|
}
|
|
249488
249304
|
function getWhatsAppOutboundMediaExtension(msg) {
|
|
249489
|
-
const fileNameExtension =
|
|
249490
|
-
const mediaPathExtension =
|
|
249305
|
+
const fileNameExtension = extname9(msg.fileName ?? "");
|
|
249306
|
+
const mediaPathExtension = extname9(msg.mediaPath ?? "");
|
|
249491
249307
|
return (fileNameExtension || mediaPathExtension).toLowerCase();
|
|
249492
249308
|
}
|
|
249493
249309
|
var DEFAULT_WHATSAPP_MEDIA_MAX_BYTES, WHATSAPP_IMAGE_EXTENSIONS, WHATSAPP_VIDEO_EXTENSIONS, WHATSAPP_VOICE_MEMO_EXTENSIONS;
|
|
@@ -249508,7 +249324,7 @@ var init_media4 = __esm(() => {
|
|
|
249508
249324
|
});
|
|
249509
249325
|
|
|
249510
249326
|
// src/channels/whatsapp/adapter-helpers.ts
|
|
249511
|
-
function
|
|
249327
|
+
function asRecord6(value) {
|
|
249512
249328
|
return value && typeof value === "object" ? value : {};
|
|
249513
249329
|
}
|
|
249514
249330
|
function isWhatsAppReactionMessage(message) {
|
|
@@ -249516,12 +249332,12 @@ function isWhatsAppReactionMessage(message) {
|
|
|
249516
249332
|
return !!content?.reactionMessage;
|
|
249517
249333
|
}
|
|
249518
249334
|
function isWhatsAppConflictDisconnect(update3) {
|
|
249519
|
-
const record5 =
|
|
249335
|
+
const record5 = asRecord6(update3);
|
|
249520
249336
|
if (record5.connection !== "close")
|
|
249521
249337
|
return false;
|
|
249522
|
-
const lastDisconnect =
|
|
249523
|
-
const error54 =
|
|
249524
|
-
const output =
|
|
249338
|
+
const lastDisconnect = asRecord6(record5.lastDisconnect);
|
|
249339
|
+
const error54 = asRecord6(lastDisconnect.error);
|
|
249340
|
+
const output = asRecord6(error54.output);
|
|
249525
249341
|
const statusCode2 = output.statusCode;
|
|
249526
249342
|
const message = typeof error54.message === "string" ? error54.message : "";
|
|
249527
249343
|
return statusCode2 === 440 || /\bconflict\b/i.test(message) || /connection replaced/i.test(message);
|
|
@@ -250057,7 +249873,7 @@ function createLidStore(filePath) {
|
|
|
250057
249873
|
var init_lid_store = () => {};
|
|
250058
249874
|
|
|
250059
249875
|
// src/channels/whatsapp/message-store.ts
|
|
250060
|
-
function
|
|
249876
|
+
function asRecord7(value) {
|
|
250061
249877
|
return value && typeof value === "object" ? value : {};
|
|
250062
249878
|
}
|
|
250063
249879
|
function unrefTimeout(timer) {
|
|
@@ -250133,10 +249949,10 @@ function createWhatsAppMessageStore(canonicalizeChatId) {
|
|
|
250133
249949
|
const stored = messages.get(messageId);
|
|
250134
249950
|
if (!stored)
|
|
250135
249951
|
return false;
|
|
250136
|
-
return
|
|
249952
|
+
return asRecord7(asRecord7(stored).key).fromMe === true;
|
|
250137
249953
|
}
|
|
250138
249954
|
function getStoredTargetKey(targetJid, messageId) {
|
|
250139
|
-
const key2 =
|
|
249955
|
+
const key2 = asRecord7(asRecord7(messages.get(messageId)).key);
|
|
250140
249956
|
if (typeof key2.id !== "string" || key2.id !== messageId)
|
|
250141
249957
|
return null;
|
|
250142
249958
|
const remoteJid = typeof key2.remoteJid === "string" ? stripDeviceSuffix(key2.remoteJid) : "";
|
|
@@ -250955,8 +250771,8 @@ function createWhatsAppAdapter(account, dependencies4 = {}) {
|
|
|
250955
250771
|
if (closingSocket2)
|
|
250956
250772
|
typing.clearOwner(closingSocket2);
|
|
250957
250773
|
clearActiveSocket(false);
|
|
250958
|
-
const lastDisconnect2 =
|
|
250959
|
-
const error55 =
|
|
250774
|
+
const lastDisconnect2 = asRecord6(update3.lastDisconnect);
|
|
250775
|
+
const error55 = asRecord6(lastDisconnect2.error);
|
|
250960
250776
|
running = false;
|
|
250961
250777
|
stopping = true;
|
|
250962
250778
|
clearWhatsAppReconnectTimer();
|
|
@@ -250976,8 +250792,8 @@ function createWhatsAppAdapter(account, dependencies4 = {}) {
|
|
|
250976
250792
|
if (closingSocket)
|
|
250977
250793
|
typing.clearOwner(closingSocket);
|
|
250978
250794
|
clearActiveSocket(false);
|
|
250979
|
-
const lastDisconnect =
|
|
250980
|
-
const error54 =
|
|
250795
|
+
const lastDisconnect = asRecord6(update3.lastDisconnect);
|
|
250796
|
+
const error54 = asRecord6(lastDisconnect.error);
|
|
250981
250797
|
const now2 = reconnectScheduler.now();
|
|
250982
250798
|
while (recentDisconnects.length > 0) {
|
|
250983
250799
|
const oldest = recentDisconnects[0];
|
|
@@ -251044,7 +250860,7 @@ function createWhatsAppAdapter(account, dependencies4 = {}) {
|
|
|
251044
250860
|
try {
|
|
251045
250861
|
if (!isActiveBatch(batchSocket, generation2))
|
|
251046
250862
|
return;
|
|
251047
|
-
const record5 =
|
|
250863
|
+
const record5 = asRecord6(event2);
|
|
251048
250864
|
if (record5.type !== "notify" && record5.type !== "append")
|
|
251049
250865
|
return;
|
|
251050
250866
|
const messages = Array.isArray(record5.messages) ? record5.messages : [];
|
|
@@ -252069,8 +251885,8 @@ import {
|
|
|
252069
251885
|
} from "node:fs";
|
|
252070
251886
|
import { homedir as homedir27 } from "node:os";
|
|
252071
251887
|
import {
|
|
252072
|
-
basename as
|
|
252073
|
-
extname as
|
|
251888
|
+
basename as basename17,
|
|
251889
|
+
extname as extname10,
|
|
252074
251890
|
isAbsolute as isAbsolute25,
|
|
252075
251891
|
join as join48,
|
|
252076
251892
|
relative as relative9,
|
|
@@ -252103,7 +251919,7 @@ function normalizeSignalMimeType(value) {
|
|
|
252103
251919
|
return normalized || undefined;
|
|
252104
251920
|
}
|
|
252105
251921
|
function inferSignalMimeTypeFromName(fileName) {
|
|
252106
|
-
switch (
|
|
251922
|
+
switch (extname10(fileName).toLowerCase()) {
|
|
252107
251923
|
case ".jpg":
|
|
252108
251924
|
case ".jpeg":
|
|
252109
251925
|
return "image/jpeg";
|
|
@@ -252141,7 +251957,7 @@ function inferSignalAttachmentKind(params) {
|
|
|
252141
251957
|
if (params.mimeType?.startsWith("video/")) {
|
|
252142
251958
|
return "video";
|
|
252143
251959
|
}
|
|
252144
|
-
switch (
|
|
251960
|
+
switch (extname10(params.fileName).toLowerCase()) {
|
|
252145
251961
|
case ".jpg":
|
|
252146
251962
|
case ".jpeg":
|
|
252147
251963
|
case ".png":
|
|
@@ -252267,7 +252083,7 @@ function signalMimeTypeMatchesFileName(mimeType, filePath) {
|
|
|
252267
252083
|
if (!mimeType) {
|
|
252268
252084
|
return true;
|
|
252269
252085
|
}
|
|
252270
|
-
const extension =
|
|
252086
|
+
const extension = extname10(filePath).toLowerCase();
|
|
252271
252087
|
if (mimeType.startsWith("image/")) {
|
|
252272
252088
|
return [".jpg", ".jpeg", ".png", ".gif", ".webp"].includes(extension);
|
|
252273
252089
|
}
|
|
@@ -252328,13 +252144,13 @@ function resolveSignalAttachmentFileName(attachment, sourcePath) {
|
|
|
252328
252144
|
if (hintedName && !hintedName.includes("/") && !hintedName.includes("\\")) {
|
|
252329
252145
|
return hintedName;
|
|
252330
252146
|
}
|
|
252331
|
-
return
|
|
252147
|
+
return basename17(sourcePath) || "attachment";
|
|
252332
252148
|
}
|
|
252333
252149
|
function copySignalAttachment(params) {
|
|
252334
252150
|
const sourceStat = statSync13(params.sourcePath);
|
|
252335
252151
|
const sizeBytes = typeof params.attachment.size === "number" && params.attachment.size >= 0 ? params.attachment.size : sourceStat.size;
|
|
252336
252152
|
if (sizeBytes > params.maxBytes || sourceStat.size > params.maxBytes) {
|
|
252337
|
-
console.warn(`[Signal] Skipping attachment ${params.attachment.filename ?? params.attachment.id ??
|
|
252153
|
+
console.warn(`[Signal] Skipping attachment ${params.attachment.filename ?? params.attachment.id ?? basename17(params.sourcePath)}: ${Math.max(sizeBytes, sourceStat.size)} bytes exceeds Signal download limit (${params.maxBytes} bytes).`);
|
|
252338
252154
|
return null;
|
|
252339
252155
|
}
|
|
252340
252156
|
const fileName = resolveSignalAttachmentFileName(params.attachment, params.sourcePath);
|
|
@@ -268889,6 +268705,7 @@ __export(exports_environments2, {
|
|
|
268889
268705
|
teleportToEnvironment: () => teleportToEnvironment,
|
|
268890
268706
|
sendEnvironmentMessage: () => sendEnvironmentMessage,
|
|
268891
268707
|
resolveEnvironmentConnectionId: () => resolveEnvironmentConnectionId,
|
|
268708
|
+
resolveDesktopEnvironmentConnectionId: () => resolveDesktopEnvironmentConnectionId,
|
|
268892
268709
|
resolveAgentSandboxConnectionId: () => resolveAgentSandboxConnectionId,
|
|
268893
268710
|
listEnvironments: () => listEnvironments,
|
|
268894
268711
|
isEnvironmentOnline: () => isEnvironmentOnline,
|
|
@@ -268923,6 +268740,21 @@ function describeEnvironment(environment2) {
|
|
|
268923
268740
|
const status = isEnvironmentOnline(environment2) ? "online" : "offline";
|
|
268924
268741
|
return `${environment2.connectionName} (${environment2.deviceId}, ${status})`;
|
|
268925
268742
|
}
|
|
268743
|
+
async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
|
|
268744
|
+
const response = await list({ limit: 100, onlineOnly: true });
|
|
268745
|
+
const matches3 = response.connections.filter((environment3) => environment3.listenerInstanceId?.startsWith("desktop-direct-cloud:") === true && isEnvironmentOnline(environment3));
|
|
268746
|
+
if (matches3.length === 0) {
|
|
268747
|
+
throw new Error("Desktop Local is unavailable. Open Letta Desktop, enable Remote Access, and wait for its environment to come online.");
|
|
268748
|
+
}
|
|
268749
|
+
if (matches3.length > 1) {
|
|
268750
|
+
throw new Error(`Multiple Desktop environments are online. Run \`letta teleport list\` and choose one by name, device ID, or connection ID. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
|
|
268751
|
+
}
|
|
268752
|
+
const environment2 = matches3[0];
|
|
268753
|
+
if (!environment2?.connectionId) {
|
|
268754
|
+
throw new Error("Desktop Local has no active connection id");
|
|
268755
|
+
}
|
|
268756
|
+
return { connectionId: environment2.connectionId, environment: environment2 };
|
|
268757
|
+
}
|
|
268926
268758
|
async function resolveEnvironmentConnectionId(selector) {
|
|
268927
268759
|
const trimmed = selector.trim();
|
|
268928
268760
|
if (!trimmed) {
|
|
@@ -272183,7 +272015,7 @@ var init_listing_shared = __esm(() => {
|
|
|
272183
272015
|
|
|
272184
272016
|
// node_modules/@letta-ai/trajectory/dist/adapters/claude-code/list.js
|
|
272185
272017
|
import { homedir as homedir29 } from "node:os";
|
|
272186
|
-
import { basename as
|
|
272018
|
+
import { basename as basename18, join as join52 } from "node:path";
|
|
272187
272019
|
async function listClaudeCodeTrajectories(root2) {
|
|
272188
272020
|
const base3 = root2 ?? join52(homedir29(), ".claude", "projects");
|
|
272189
272021
|
const items3 = [];
|
|
@@ -272195,7 +272027,7 @@ async function listClaudeCodeTrajectories(root2) {
|
|
|
272195
272027
|
if (!entry.isFile || !entry.name.endsWith(".jsonl"))
|
|
272196
272028
|
continue;
|
|
272197
272029
|
const path33 = join52(projectPath, entry.name);
|
|
272198
|
-
const listing = listingFromFile(
|
|
272030
|
+
const listing = listingFromFile(basename18(entry.name, ".jsonl"), path33);
|
|
272199
272031
|
if (listing)
|
|
272200
272032
|
items3.push(listing);
|
|
272201
272033
|
}
|
|
@@ -272208,12 +272040,12 @@ var init_list = __esm(() => {
|
|
|
272208
272040
|
|
|
272209
272041
|
// node_modules/@letta-ai/trajectory/dist/adapters/codex/list.js
|
|
272210
272042
|
import { homedir as homedir30 } from "node:os";
|
|
272211
|
-
import { basename as
|
|
272043
|
+
import { basename as basename19, join as join53 } from "node:path";
|
|
272212
272044
|
async function listCodexTrajectories(root2) {
|
|
272213
272045
|
const base3 = root2 ?? join53(homedir30(), ".codex", "sessions");
|
|
272214
272046
|
const items3 = [];
|
|
272215
272047
|
for (const path33 of collectFiles(base3, ".jsonl", 4)) {
|
|
272216
|
-
const listing = listingFromFile(
|
|
272048
|
+
const listing = listingFromFile(basename19(path33, ".jsonl"), path33);
|
|
272217
272049
|
if (listing)
|
|
272218
272050
|
items3.push(listing);
|
|
272219
272051
|
}
|
|
@@ -272320,7 +272152,7 @@ var init_list5 = __esm(() => {
|
|
|
272320
272152
|
// node_modules/@letta-ai/trajectory/dist/adapters/openclaw/list.js
|
|
272321
272153
|
import { existsSync as existsSync42 } from "node:fs";
|
|
272322
272154
|
import { homedir as homedir34 } from "node:os";
|
|
272323
|
-
import { basename as
|
|
272155
|
+
import { basename as basename20, join as join57 } from "node:path";
|
|
272324
272156
|
async function listOpenClawTrajectories(root2) {
|
|
272325
272157
|
const base3 = root2 ?? defaultStateDir();
|
|
272326
272158
|
const items3 = [];
|
|
@@ -272333,7 +272165,7 @@ async function listOpenClawTrajectories(root2) {
|
|
|
272333
272165
|
if (!entry.isFile || !entry.name.endsWith(".jsonl"))
|
|
272334
272166
|
continue;
|
|
272335
272167
|
const path33 = join57(sessionsPath, entry.name);
|
|
272336
|
-
const listing = listingFromFile(
|
|
272168
|
+
const listing = listingFromFile(basename20(entry.name, ".jsonl"), path33);
|
|
272337
272169
|
if (listing)
|
|
272338
272170
|
items3.push(listing);
|
|
272339
272171
|
}
|
|
@@ -274066,9 +273898,9 @@ var init_dream_sources = __esm(() => {
|
|
|
274066
273898
|
// src/cli/subcommands/dream-targets.ts
|
|
274067
273899
|
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
274068
273900
|
import { mkdir as mkdir12, readFile as readFile19, rm as rm8, writeFile as writeFile14 } from "node:fs/promises";
|
|
274069
|
-
import { basename as
|
|
273901
|
+
import { basename as basename21, dirname as dirname26, join as join61 } from "node:path";
|
|
274070
273902
|
function resolveDreamTarget(spec) {
|
|
274071
|
-
const fileName =
|
|
273903
|
+
const fileName = basename21(spec);
|
|
274072
273904
|
if (!fileName) {
|
|
274073
273905
|
throw new Error(`Invalid --to "${spec}": expected a file path`);
|
|
274074
273906
|
}
|
|
@@ -389373,10 +389205,10 @@ ${lanes.join(`
|
|
|
389373
389205
|
}
|
|
389374
389206
|
function getDefaultLibFilePriority(a2) {
|
|
389375
389207
|
if (containsPath(defaultLibraryPath, a2.fileName, false)) {
|
|
389376
|
-
const
|
|
389377
|
-
if (
|
|
389208
|
+
const basename22 = getBaseFileName(a2.fileName);
|
|
389209
|
+
if (basename22 === "lib.d.ts" || basename22 === "lib.es6.d.ts")
|
|
389378
389210
|
return 0;
|
|
389379
|
-
const name = removeSuffix(removePrefix(
|
|
389211
|
+
const name = removeSuffix(removePrefix(basename22, "lib."), ".d.ts");
|
|
389380
389212
|
const index = libs.indexOf(name);
|
|
389381
389213
|
if (index !== -1)
|
|
389382
389214
|
return index + 1;
|
|
@@ -441939,8 +441771,8 @@ ${options3.prefix}` : `
|
|
|
441939
441771
|
}
|
|
441940
441772
|
};
|
|
441941
441773
|
for (const file3 of files2) {
|
|
441942
|
-
const
|
|
441943
|
-
if (
|
|
441774
|
+
const basename22 = getBaseFileName(file3);
|
|
441775
|
+
if (basename22 === "package.json" || basename22 === "bower.json") {
|
|
441944
441776
|
createProjectWatcher(file3, "FileWatcher");
|
|
441945
441777
|
continue;
|
|
441946
441778
|
}
|
|
@@ -444817,8 +444649,8 @@ All files are: ${JSON.stringify(names)}`, "Err");
|
|
|
444817
444649
|
const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
|
|
444818
444650
|
if (!fileOrDirectoryPath)
|
|
444819
444651
|
return;
|
|
444820
|
-
const
|
|
444821
|
-
if (((_a8 = result2.affectedModuleSpecifierCacheProjects) == null ? undefined : _a8.size) && (
|
|
444652
|
+
const basename22 = getBaseFileName(fileOrDirectoryPath);
|
|
444653
|
+
if (((_a8 = result2.affectedModuleSpecifierCacheProjects) == null ? undefined : _a8.size) && (basename22 === "package.json" || basename22 === "node_modules")) {
|
|
444822
444654
|
result2.affectedModuleSpecifierCacheProjects.forEach((project) => {
|
|
444823
444655
|
var _a22;
|
|
444824
444656
|
(_a22 = project.getModuleSpecifierCache()) == null || _a22.clear();
|
|
@@ -452902,26 +452734,25 @@ function resolveModelForUpdate(payload) {
|
|
|
452902
452734
|
}
|
|
452903
452735
|
};
|
|
452904
452736
|
}
|
|
452905
|
-
function formatEffortSuffix(modelLabel, updateArgs) {
|
|
452737
|
+
function formatEffortSuffix(modelLabel, updateArgs, modelHandle) {
|
|
452906
452738
|
if (!updateArgs)
|
|
452907
452739
|
return "";
|
|
452908
452740
|
const effort = updateArgs.reasoning_effort;
|
|
452909
452741
|
if (typeof effort !== "string" || effort.length === 0)
|
|
452910
452742
|
return "";
|
|
452911
|
-
const xhighLabel = modelLabel.includes("Fable 5") || modelLabel.includes("Opus 4.7") || modelLabel.includes("Opus 4.8") ? "Extra-High" : "Max";
|
|
452912
452743
|
const labels = {
|
|
452913
452744
|
none: "No Reasoning",
|
|
452914
452745
|
low: "Low",
|
|
452915
452746
|
medium: "Medium",
|
|
452916
452747
|
high: "High",
|
|
452917
|
-
xhigh:
|
|
452748
|
+
xhigh: formatXhighEffortLabel(catalogHasDistinctMaxTier({ modelLabel, modelHandle })),
|
|
452918
452749
|
max: "Max"
|
|
452919
452750
|
};
|
|
452920
452751
|
return ` (${labels[effort] ?? effort})`;
|
|
452921
452752
|
}
|
|
452922
452753
|
function buildModelUpdateStatusMessage(params) {
|
|
452923
|
-
const { modelLabel, toolsetError, updateArgs } = params;
|
|
452924
|
-
let message = `Model updated to ${modelLabel}${formatEffortSuffix(modelLabel, updateArgs)}.`;
|
|
452754
|
+
const { modelLabel, toolsetError, updateArgs, modelHandle } = params;
|
|
452755
|
+
let message = `Model updated to ${modelLabel}${formatEffortSuffix(modelLabel, updateArgs, modelHandle)}.`;
|
|
452925
452756
|
if (toolsetError) {
|
|
452926
452757
|
message += ` Warning: toolset switch failed (${toolsetError}).`;
|
|
452927
452758
|
return { message, level: "warning" };
|
|
@@ -452992,7 +452823,8 @@ async function applyModelUpdateForRuntime(params) {
|
|
|
452992
452823
|
const { message: statusMessage, level: statusLevel } = buildModelUpdateStatusMessage({
|
|
452993
452824
|
modelLabel: model.label,
|
|
452994
452825
|
toolsetError,
|
|
452995
|
-
updateArgs: model.updateArgs
|
|
452826
|
+
updateArgs: model.updateArgs,
|
|
452827
|
+
modelHandle: model.handle
|
|
452996
452828
|
});
|
|
452997
452829
|
emitStatusDelta(socket, scopedRuntime, {
|
|
452998
452830
|
message: statusMessage,
|
|
@@ -453216,6 +453048,7 @@ var init_model_toolset = __esm(async () => {
|
|
|
453216
453048
|
init_available_models();
|
|
453217
453049
|
init_model();
|
|
453218
453050
|
init_modify();
|
|
453051
|
+
init_reasoning_effort_label();
|
|
453219
453052
|
init_remote_model_catalog();
|
|
453220
453053
|
init_backend2();
|
|
453221
453054
|
init_byok_providers();
|
|
@@ -453866,7 +453699,7 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
|
|
|
453866
453699
|
symlinkSync: symlinkSync2,
|
|
453867
453700
|
unlinkSync: unlinkSync10
|
|
453868
453701
|
} = await import("node:fs");
|
|
453869
|
-
const { basename:
|
|
453702
|
+
const { basename: basename22, join: join67 } = await import("node:path");
|
|
453870
453703
|
const lettaHome = process.env.LETTA_HOME || join67(process.env.HOME || process.env.USERPROFILE || "~", ".letta");
|
|
453871
453704
|
const globalSkillsDir = join67(lettaHome, "skills");
|
|
453872
453705
|
if (parsed.type === "skill_enable") {
|
|
@@ -453890,7 +453723,7 @@ async function handleSkillCommand(parsed, socket, safeSocketSend) {
|
|
|
453890
453723
|
}, "listener_skill_send_failed", "listener_skill_command");
|
|
453891
453724
|
return true;
|
|
453892
453725
|
}
|
|
453893
|
-
const linkName =
|
|
453726
|
+
const linkName = basename22(parsed.skill_path);
|
|
453894
453727
|
const linkPath = join67(globalSkillsDir, linkName);
|
|
453895
453728
|
mkdirSync36(globalSkillsDir, { recursive: true });
|
|
453896
453729
|
if (existsSync50(linkPath)) {
|
|
@@ -456169,6 +456002,65 @@ var init_chunk_log = __esm(() => {
|
|
|
456169
456002
|
chunkLog = new ChunkLog;
|
|
456170
456003
|
});
|
|
456171
456004
|
|
|
456005
|
+
// src/cli/helpers/stream-debug.ts
|
|
456006
|
+
function summarizeStreamForDebug(stream12) {
|
|
456007
|
+
if (!stream12 || typeof stream12 !== "object") {
|
|
456008
|
+
return `type=${typeof stream12}`;
|
|
456009
|
+
}
|
|
456010
|
+
const record5 = stream12;
|
|
456011
|
+
const ctor = stream12.constructor?.name;
|
|
456012
|
+
const controller = record5.controller && typeof record5.controller === "object" ? record5.controller : null;
|
|
456013
|
+
const keys3 = Object.keys(record5).slice(0, 8);
|
|
456014
|
+
return [
|
|
456015
|
+
`ctor=${ctor ?? "unknown"}`,
|
|
456016
|
+
`asyncIterator=${typeof record5[Symbol.asyncIterator]}`,
|
|
456017
|
+
`controller=${typeof record5.controller}`,
|
|
456018
|
+
`controllerAbort=${typeof controller?.abort}`,
|
|
456019
|
+
`controllerSignal=${typeof controller?.signal}`,
|
|
456020
|
+
keys3.length > 0 ? `keys=${keys3.join(",")}` : "keys=(none)"
|
|
456021
|
+
].join(" ");
|
|
456022
|
+
}
|
|
456023
|
+
function summarizeChunkForDebug(chunk2) {
|
|
456024
|
+
if (!chunk2) {
|
|
456025
|
+
return "none";
|
|
456026
|
+
}
|
|
456027
|
+
const record5 = chunk2;
|
|
456028
|
+
const parts = [`message_type=${chunk2.message_type ?? "unknown"}`];
|
|
456029
|
+
for (const key2 of ["run_id", "seq_id", "id", "otid", "tool_call_id"]) {
|
|
456030
|
+
const value = record5[key2];
|
|
456031
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
456032
|
+
parts.push(`${key2}=${value}`);
|
|
456033
|
+
}
|
|
456034
|
+
}
|
|
456035
|
+
if (chunk2.message_type === "stop_reason") {
|
|
456036
|
+
parts.push(`stop_reason=${String(record5.stop_reason ?? "unknown")}`);
|
|
456037
|
+
}
|
|
456038
|
+
const toolCalls = record5.tool_calls;
|
|
456039
|
+
if (Array.isArray(toolCalls)) {
|
|
456040
|
+
parts.push(`tool_calls=${toolCalls.length}`);
|
|
456041
|
+
}
|
|
456042
|
+
return parts.join(" ");
|
|
456043
|
+
}
|
|
456044
|
+
function abortStreamController(stream12, reason) {
|
|
456045
|
+
const controller = stream12.controller;
|
|
456046
|
+
if (!controller || typeof controller !== "object") {
|
|
456047
|
+
debugWarn("drainStream", "stream.controller is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream12));
|
|
456048
|
+
return;
|
|
456049
|
+
}
|
|
456050
|
+
const controllerRecord = controller;
|
|
456051
|
+
if (controllerRecord.signal?.aborted) {
|
|
456052
|
+
return;
|
|
456053
|
+
}
|
|
456054
|
+
if (typeof controllerRecord.abort !== "function") {
|
|
456055
|
+
debugWarn("drainStream", "stream.controller.abort is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream12));
|
|
456056
|
+
return;
|
|
456057
|
+
}
|
|
456058
|
+
controllerRecord.abort();
|
|
456059
|
+
}
|
|
456060
|
+
var init_stream_debug = __esm(() => {
|
|
456061
|
+
init_debug();
|
|
456062
|
+
});
|
|
456063
|
+
|
|
456172
456064
|
// src/cli/helpers/stream-processor.ts
|
|
456173
456065
|
class StreamProcessor {
|
|
456174
456066
|
seenSeqIdThreshold;
|
|
@@ -456377,6 +456269,90 @@ var init_stream_resume = __esm(() => {
|
|
|
456377
456269
|
init_client2();
|
|
456378
456270
|
});
|
|
456379
456271
|
|
|
456272
|
+
// src/cli/helpers/stream-stall-reconciler.ts
|
|
456273
|
+
function getStallReconcileMs() {
|
|
456274
|
+
const raw2 = process.env.LETTA_STREAM_STALL_RECONCILE_MS;
|
|
456275
|
+
if (raw2) {
|
|
456276
|
+
const parsed = Number(raw2);
|
|
456277
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
456278
|
+
return parsed;
|
|
456279
|
+
}
|
|
456280
|
+
}
|
|
456281
|
+
return DEFAULT_STREAM_STALL_RECONCILE_MS;
|
|
456282
|
+
}
|
|
456283
|
+
function createStreamStallReconciler(context3) {
|
|
456284
|
+
let timer = null;
|
|
456285
|
+
let fired = false;
|
|
456286
|
+
let cleared = false;
|
|
456287
|
+
let reconciling = false;
|
|
456288
|
+
const arm = () => {
|
|
456289
|
+
if (cleared || fired) {
|
|
456290
|
+
return;
|
|
456291
|
+
}
|
|
456292
|
+
if (timer) {
|
|
456293
|
+
clearTimeout(timer);
|
|
456294
|
+
}
|
|
456295
|
+
timer = setTimeout(onSilenceElapsed, getStallReconcileMs());
|
|
456296
|
+
};
|
|
456297
|
+
const onSilenceElapsed = () => {
|
|
456298
|
+
timer = null;
|
|
456299
|
+
if (cleared || fired || reconciling) {
|
|
456300
|
+
return;
|
|
456301
|
+
}
|
|
456302
|
+
if (context3.getStopReason() !== null) {
|
|
456303
|
+
return;
|
|
456304
|
+
}
|
|
456305
|
+
const runId = context3.getRunId();
|
|
456306
|
+
if (!runId) {
|
|
456307
|
+
arm();
|
|
456308
|
+
return;
|
|
456309
|
+
}
|
|
456310
|
+
reconciling = true;
|
|
456311
|
+
(async () => {
|
|
456312
|
+
let status;
|
|
456313
|
+
try {
|
|
456314
|
+
status = await context3.retrieveRunStatus(runId);
|
|
456315
|
+
} catch {
|
|
456316
|
+
status = undefined;
|
|
456317
|
+
}
|
|
456318
|
+
reconciling = false;
|
|
456319
|
+
if (cleared || fired || context3.getStopReason() !== null) {
|
|
456320
|
+
return;
|
|
456321
|
+
}
|
|
456322
|
+
if (status == null || ACTIVE_RUN_STATUSES.has(status)) {
|
|
456323
|
+
arm();
|
|
456324
|
+
return;
|
|
456325
|
+
}
|
|
456326
|
+
fired = true;
|
|
456327
|
+
debugWarn("drainStream", "Stall reconciler fired: run %s is %s server-side but the stream went silent before its terminal sequence - aborting HTTP read to trigger resume", runId, status);
|
|
456328
|
+
telemetry.trackError("stream_stall_reconciler_fired", `Stream went silent while run reached server-side status ${status}; aborted the dead read to resume`, "stream_drain", { runId });
|
|
456329
|
+
context3.abortHttpRead();
|
|
456330
|
+
})();
|
|
456331
|
+
};
|
|
456332
|
+
return {
|
|
456333
|
+
arm,
|
|
456334
|
+
clear: () => {
|
|
456335
|
+
cleared = true;
|
|
456336
|
+
if (timer) {
|
|
456337
|
+
clearTimeout(timer);
|
|
456338
|
+
timer = null;
|
|
456339
|
+
}
|
|
456340
|
+
},
|
|
456341
|
+
fired: () => fired
|
|
456342
|
+
};
|
|
456343
|
+
}
|
|
456344
|
+
var DEFAULT_STREAM_STALL_RECONCILE_MS = 60000, ACTIVE_RUN_STATUSES;
|
|
456345
|
+
var init_stream_stall_reconciler = __esm(() => {
|
|
456346
|
+
init_telemetry();
|
|
456347
|
+
init_debug();
|
|
456348
|
+
ACTIVE_RUN_STATUSES = new Set([
|
|
456349
|
+
"created",
|
|
456350
|
+
"not_started",
|
|
456351
|
+
"pending",
|
|
456352
|
+
"running"
|
|
456353
|
+
]);
|
|
456354
|
+
});
|
|
456355
|
+
|
|
456380
456356
|
// src/cli/helpers/stream-terminal-eof-guard.ts
|
|
456381
456357
|
function getTerminalEofGraceMs() {
|
|
456382
456358
|
const raw2 = process.env.LETTA_STREAM_TERMINAL_EOF_GRACE_MS;
|
|
@@ -456422,60 +456398,6 @@ var init_stream_terminal_eof_guard = __esm(() => {
|
|
|
456422
456398
|
});
|
|
456423
456399
|
|
|
456424
456400
|
// src/cli/helpers/stream.ts
|
|
456425
|
-
function summarizeStreamForDebug(stream12) {
|
|
456426
|
-
if (!stream12 || typeof stream12 !== "object") {
|
|
456427
|
-
return `type=${typeof stream12}`;
|
|
456428
|
-
}
|
|
456429
|
-
const record5 = stream12;
|
|
456430
|
-
const ctor = stream12.constructor?.name;
|
|
456431
|
-
const controller = record5.controller && typeof record5.controller === "object" ? record5.controller : null;
|
|
456432
|
-
const keys3 = Object.keys(record5).slice(0, 8);
|
|
456433
|
-
return [
|
|
456434
|
-
`ctor=${ctor ?? "unknown"}`,
|
|
456435
|
-
`asyncIterator=${typeof record5[Symbol.asyncIterator]}`,
|
|
456436
|
-
`controller=${typeof record5.controller}`,
|
|
456437
|
-
`controllerAbort=${typeof controller?.abort}`,
|
|
456438
|
-
`controllerSignal=${typeof controller?.signal}`,
|
|
456439
|
-
keys3.length > 0 ? `keys=${keys3.join(",")}` : "keys=(none)"
|
|
456440
|
-
].join(" ");
|
|
456441
|
-
}
|
|
456442
|
-
function summarizeChunkForDebug(chunk2) {
|
|
456443
|
-
if (!chunk2) {
|
|
456444
|
-
return "none";
|
|
456445
|
-
}
|
|
456446
|
-
const record5 = chunk2;
|
|
456447
|
-
const parts = [`message_type=${chunk2.message_type ?? "unknown"}`];
|
|
456448
|
-
for (const key2 of ["run_id", "seq_id", "id", "otid", "tool_call_id"]) {
|
|
456449
|
-
const value = record5[key2];
|
|
456450
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
456451
|
-
parts.push(`${key2}=${value}`);
|
|
456452
|
-
}
|
|
456453
|
-
}
|
|
456454
|
-
if (chunk2.message_type === "stop_reason") {
|
|
456455
|
-
parts.push(`stop_reason=${String(record5.stop_reason ?? "unknown")}`);
|
|
456456
|
-
}
|
|
456457
|
-
const toolCalls = record5.tool_calls;
|
|
456458
|
-
if (Array.isArray(toolCalls)) {
|
|
456459
|
-
parts.push(`tool_calls=${toolCalls.length}`);
|
|
456460
|
-
}
|
|
456461
|
-
return parts.join(" ");
|
|
456462
|
-
}
|
|
456463
|
-
function abortStreamController(stream12, reason) {
|
|
456464
|
-
const controller = stream12.controller;
|
|
456465
|
-
if (!controller || typeof controller !== "object") {
|
|
456466
|
-
debugWarn("drainStream", "stream.controller is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream12));
|
|
456467
|
-
return;
|
|
456468
|
-
}
|
|
456469
|
-
const controllerRecord = controller;
|
|
456470
|
-
if (controllerRecord.signal?.aborted) {
|
|
456471
|
-
return;
|
|
456472
|
-
}
|
|
456473
|
-
if (typeof controllerRecord.abort !== "function") {
|
|
456474
|
-
debugWarn("drainStream", "stream.controller.abort is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream12));
|
|
456475
|
-
return;
|
|
456476
|
-
}
|
|
456477
|
-
controllerRecord.abort();
|
|
456478
|
-
}
|
|
456479
456401
|
async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, isResumeStream, skipCancelToolsOnError) {
|
|
456480
456402
|
const startTime = performance.now();
|
|
456481
456403
|
const requestStartTime = getStreamRequestStartTime(stream12) ?? startTime;
|
|
@@ -456491,6 +456413,12 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
456491
456413
|
getRunId: () => streamProcessor.lastRunId,
|
|
456492
456414
|
abortHttpRead: () => abortStreamController(stream12, "terminal_eof_guard")
|
|
456493
456415
|
});
|
|
456416
|
+
const stallReconciler = createStreamStallReconciler({
|
|
456417
|
+
getRunId: () => streamProcessor.lastRunId,
|
|
456418
|
+
getStopReason: () => streamProcessor.stopReason,
|
|
456419
|
+
retrieveRunStatus: async (runId) => (await getBackend().retrieveRun(runId)).status,
|
|
456420
|
+
abortHttpRead: () => abortStreamController(stream12, "stall_reconciler")
|
|
456421
|
+
});
|
|
456494
456422
|
const startAbortGen = buffers.abortGeneration || 0;
|
|
456495
456423
|
const abortHandler = () => {
|
|
456496
456424
|
abortedViaListener = true;
|
|
@@ -456507,7 +456435,9 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
456507
456435
|
if (typeof asyncIterator !== "function") {
|
|
456508
456436
|
throw new TypeError(`Stream is not async iterable (${summarizeStreamForDebug(stream12)})`);
|
|
456509
456437
|
}
|
|
456438
|
+
stallReconciler.arm();
|
|
456510
456439
|
for await (const chunk2 of stream12) {
|
|
456440
|
+
stallReconciler.arm();
|
|
456511
456441
|
lastChunkDebugSummary = summarizeChunkForDebug(chunk2);
|
|
456512
456442
|
recordTuiJsonPayload(`stream_chunk:${chunk2.message_type ?? "unknown"}`, chunk2);
|
|
456513
456443
|
if ((buffers.abortGeneration || 0) !== startAbortGen) {
|
|
@@ -456609,6 +456539,7 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
456609
456539
|
queueMicrotask(refresh);
|
|
456610
456540
|
} finally {
|
|
456611
456541
|
terminalEofGuard.clear();
|
|
456542
|
+
stallReconciler.clear();
|
|
456612
456543
|
try {
|
|
456613
456544
|
chunkLog.flush();
|
|
456614
456545
|
} catch {}
|
|
@@ -456626,6 +456557,11 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
456626
456557
|
"Stream did not close after completing, continued without waiting"
|
|
456627
456558
|
]);
|
|
456628
456559
|
}
|
|
456560
|
+
if (stallReconciler.fired()) {
|
|
456561
|
+
upsertStatusLine(buffers, `stall-reconcile-${startTime}`, [
|
|
456562
|
+
"Stream went silent after the run completed, recovering the missed tail"
|
|
456563
|
+
]);
|
|
456564
|
+
}
|
|
456629
456565
|
if (abortedViaListener && !stopReason) {
|
|
456630
456566
|
stopReason = "cancelled";
|
|
456631
456567
|
markIncompleteToolsAsCancelled(buffers, true, "user_interrupt");
|
|
@@ -456680,7 +456616,8 @@ async function drainStream(stream12, buffers, refresh, abortSignal, onFirstMessa
|
|
|
456680
456616
|
lastSeqId: streamProcessor.lastSeqId,
|
|
456681
456617
|
apiDurationMs,
|
|
456682
456618
|
fallbackError,
|
|
456683
|
-
terminalEofGuardFired: terminalEofGuard.fired()
|
|
456619
|
+
terminalEofGuardFired: terminalEofGuard.fired(),
|
|
456620
|
+
stallReconcilerFired: stallReconciler.fired()
|
|
456684
456621
|
};
|
|
456685
456622
|
}
|
|
456686
456623
|
async function drainStreamWithResume(stream12, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed, contextTracker, seenSeqIdThreshold, resumePolicy) {
|
|
@@ -456872,7 +456809,9 @@ var init_stream = __esm(async () => {
|
|
|
456872
456809
|
init_timing();
|
|
456873
456810
|
init_tui_perf();
|
|
456874
456811
|
init_chunk_log();
|
|
456812
|
+
init_stream_debug();
|
|
456875
456813
|
init_stream_resume();
|
|
456814
|
+
init_stream_stall_reconciler();
|
|
456876
456815
|
init_stream_terminal_eof_guard();
|
|
456877
456816
|
await __promiseAll([
|
|
456878
456817
|
init_message(),
|
|
@@ -456916,9 +456855,43 @@ async function getMissingRequiredArgs(toolName, parsedArgs, toolContextId) {
|
|
|
456916
456855
|
const required6 = schema5?.input_schema?.required || [];
|
|
456917
456856
|
return required6.filter((key2) => !(key2 in parsedArgs) || parsedArgs[key2] == null);
|
|
456918
456857
|
}
|
|
456919
|
-
function formatMissingRequiredArgsReason(toolName, parsedArgs, missingRequiredArgs) {
|
|
456858
|
+
function formatMissingRequiredArgsReason(toolName, parsedArgs, missingRequiredArgs, argsParse) {
|
|
456920
456859
|
const received = Object.keys(parsedArgs).join(", ");
|
|
456921
|
-
|
|
456860
|
+
const base3 = `${toolName} tool missing required parameter${missingRequiredArgs.length > 1 ? "s" : ""}: ` + `${missingRequiredArgs.join(", ")}. Received parameters: ${received}`;
|
|
456861
|
+
if (argsParse?.parseFailed) {
|
|
456862
|
+
return `${base3}. The raw arguments (${argsParse.rawLength} chars) were not valid JSON, ` + `so they were lost or truncated in transit. Do not resend an identical call - ` + `re-issue it with the arguments restructured (e.g. write long payloads to a file first).`;
|
|
456863
|
+
}
|
|
456864
|
+
if (argsParse?.argsEmpty) {
|
|
456865
|
+
return `${base3}. The tool call arrived with empty arguments, which usually means they were ` + `dropped in transit rather than omitted by you. Do not resend an identical call - ` + `re-issue it with the arguments restructured (e.g. write long payloads to a file first).`;
|
|
456866
|
+
}
|
|
456867
|
+
return base3;
|
|
456868
|
+
}
|
|
456869
|
+
function parseToolArgs(rawArgs) {
|
|
456870
|
+
const raw2 = rawArgs ?? "";
|
|
456871
|
+
const trimmed = raw2.trim();
|
|
456872
|
+
if (!trimmed) {
|
|
456873
|
+
return {
|
|
456874
|
+
parsedArgs: {},
|
|
456875
|
+
parseFailed: false,
|
|
456876
|
+
argsEmpty: true,
|
|
456877
|
+
rawLength: 0
|
|
456878
|
+
};
|
|
456879
|
+
}
|
|
456880
|
+
const parsed = safeJsonParseOr(trimmed, null);
|
|
456881
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
456882
|
+
return {
|
|
456883
|
+
parsedArgs: {},
|
|
456884
|
+
parseFailed: true,
|
|
456885
|
+
argsEmpty: false,
|
|
456886
|
+
rawLength: raw2.length
|
|
456887
|
+
};
|
|
456888
|
+
}
|
|
456889
|
+
return {
|
|
456890
|
+
parsedArgs: parsed,
|
|
456891
|
+
parseFailed: false,
|
|
456892
|
+
argsEmpty: Object.keys(parsed).length === 0,
|
|
456893
|
+
rawLength: raw2.length
|
|
456894
|
+
};
|
|
456922
456895
|
}
|
|
456923
456896
|
async function classifyApprovals(approvals, opts = {}) {
|
|
456924
456897
|
const needsUserInput = [];
|
|
@@ -456938,11 +456911,15 @@ async function classifyApprovals(approvals, opts = {}) {
|
|
|
456938
456911
|
});
|
|
456939
456912
|
continue;
|
|
456940
456913
|
}
|
|
456941
|
-
const
|
|
456914
|
+
const argsParse = parseToolArgs(approval.toolArgs);
|
|
456915
|
+
const parsedArgs = argsParse.parsedArgs;
|
|
456916
|
+
if (argsParse.parseFailed) {
|
|
456917
|
+
debugWarn("approval-classification", `Tool call ${approval.toolCallId} (${toolName}) had unparseable arguments ` + `(${argsParse.rawLength} chars); treating as empty`);
|
|
456918
|
+
}
|
|
456942
456919
|
if (opts.requireArgsForAutoApprove) {
|
|
456943
456920
|
const missingRequiredArgs = await getMissingRequiredArgs(toolName, parsedArgs, opts.toolContextId);
|
|
456944
456921
|
if (missingRequiredArgs.length > 0) {
|
|
456945
|
-
const denyReason = opts.missingArgsReason ? opts.missingArgsReason(missingRequiredArgs) : formatMissingRequiredArgsReason(toolName, parsedArgs, missingRequiredArgs);
|
|
456922
|
+
const denyReason = opts.missingArgsReason ? opts.missingArgsReason(missingRequiredArgs) : formatMissingRequiredArgsReason(toolName, parsedArgs, missingRequiredArgs, argsParse);
|
|
456946
456923
|
autoDenied.push({
|
|
456947
456924
|
approval,
|
|
456948
456925
|
permission: { decision: "deny", reason: denyReason },
|
|
@@ -456988,6 +456965,7 @@ async function classifyApprovals(approvals, opts = {}) {
|
|
|
456988
456965
|
return { needsUserInput, autoAllowed, autoDenied };
|
|
456989
456966
|
}
|
|
456990
456967
|
var init_approval_classification = __esm(async () => {
|
|
456968
|
+
init_debug();
|
|
456991
456969
|
await init_manager4();
|
|
456992
456970
|
});
|
|
456993
456971
|
|
|
@@ -457833,38 +457811,6 @@ var init_approval_recovery = __esm(() => {
|
|
|
457833
457811
|
init_turn_recovery_policy();
|
|
457834
457812
|
});
|
|
457835
457813
|
|
|
457836
|
-
// src/websocket/listener/provider-fallback.ts
|
|
457837
|
-
function createProviderFallbackState(agent2, overrideModel) {
|
|
457838
|
-
const llmConfig = agent2?.llm_config;
|
|
457839
|
-
const model = llmConfig?.model;
|
|
457840
|
-
if (!model) {
|
|
457841
|
-
return { sourceModelId: null, attempted: false, overrideModel };
|
|
457842
|
-
}
|
|
457843
|
-
const modelInfo = getModelInfoForLlmConfig(model, llmConfig) ?? getModelInfo(model);
|
|
457844
|
-
return {
|
|
457845
|
-
sourceModelId: modelInfo?.id ?? model,
|
|
457846
|
-
attempted: false,
|
|
457847
|
-
overrideModel
|
|
457848
|
-
};
|
|
457849
|
-
}
|
|
457850
|
-
function maybeApplyProviderFallback(state, attempt2) {
|
|
457851
|
-
if (!state || state.attempted || attempt2 < 2 || !state.sourceModelId) {
|
|
457852
|
-
return null;
|
|
457853
|
-
}
|
|
457854
|
-
const fallbackId = PROVIDER_FALLBACK_MAP[state.sourceModelId];
|
|
457855
|
-
const fallbackHandle = fallbackId ? getModelInfo(fallbackId)?.handle : null;
|
|
457856
|
-
if (!fallbackHandle) {
|
|
457857
|
-
return null;
|
|
457858
|
-
}
|
|
457859
|
-
state.attempted = true;
|
|
457860
|
-
state.overrideModel = fallbackHandle;
|
|
457861
|
-
return fallbackHandle;
|
|
457862
|
-
}
|
|
457863
|
-
var init_provider_fallback = __esm(() => {
|
|
457864
|
-
init_model();
|
|
457865
|
-
init_constants3();
|
|
457866
|
-
});
|
|
457867
|
-
|
|
457868
457814
|
// src/websocket/listener/skill-injection.ts
|
|
457869
457815
|
function injectQueuedSkillContent(messages, context3) {
|
|
457870
457816
|
const skillContents = consumeQueuedSkillContent();
|
|
@@ -458158,13 +458104,12 @@ async function resolveStaleApprovals(runtime, socket, turnLease, deps = {}) {
|
|
|
458158
458104
|
}
|
|
458159
458105
|
return null;
|
|
458160
458106
|
}
|
|
458161
|
-
async function sendMessageStreamWithRetry(conversationId, messages, opts, socket, runtime, turnLease
|
|
458107
|
+
async function sendMessageStreamWithRetry(conversationId, messages, opts, socket, runtime, turnLease) {
|
|
458162
458108
|
const abortSignal = turnLease.signal;
|
|
458163
458109
|
let transientRetries = 0;
|
|
458164
458110
|
let conversationBusyRetries = 0;
|
|
458165
458111
|
let preStreamRecoveryAttempts = 0;
|
|
458166
458112
|
const MAX_CONVERSATION_BUSY_RETRIES = 3;
|
|
458167
|
-
let currentOpts = opts;
|
|
458168
458113
|
const retriedAfterBlockingRunSettled = new Set;
|
|
458169
458114
|
while (true) {
|
|
458170
458115
|
if (abortSignal?.aborted) {
|
|
@@ -458175,7 +458120,7 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
458175
458120
|
conversation_id: conversationId
|
|
458176
458121
|
});
|
|
458177
458122
|
try {
|
|
458178
|
-
return await sendMessageStream(conversationId, messages,
|
|
458123
|
+
return await sendMessageStream(conversationId, messages, opts, abortSignal ? { maxRetries: 0, signal: abortSignal } : { maxRetries: 0 });
|
|
458179
458124
|
} catch (preStreamError) {
|
|
458180
458125
|
if (abortSignal?.aborted) {
|
|
458181
458126
|
throw new Error("Cancelled by user");
|
|
@@ -458214,21 +458159,6 @@ async function sendMessageStreamWithRetry(conversationId, messages, opts, socket
|
|
|
458214
458159
|
});
|
|
458215
458160
|
const attempt2 = transientRetries + 1;
|
|
458216
458161
|
transientRetries = attempt2;
|
|
458217
|
-
const fallbackHandle = maybeApplyProviderFallback(retryOptions.providerFallback, attempt2);
|
|
458218
|
-
if (fallbackHandle) {
|
|
458219
|
-
currentOpts = { ...currentOpts, overrideModel: fallbackHandle };
|
|
458220
|
-
emitRecoverableRetryNotice(socket, runtime, {
|
|
458221
|
-
kind: "transient_provider_retry",
|
|
458222
|
-
message: PROVIDER_FALLBACK_NOTICE,
|
|
458223
|
-
reason: "llm_api_error",
|
|
458224
|
-
attempt: attempt2,
|
|
458225
|
-
maxAttempts: LLM_API_ERROR_MAX_RETRIES,
|
|
458226
|
-
delayMs: 0,
|
|
458227
|
-
agentId: runtime.agentId ?? undefined,
|
|
458228
|
-
conversationId
|
|
458229
|
-
});
|
|
458230
|
-
continue;
|
|
458231
|
-
}
|
|
458232
458162
|
const retryAfterMs = preStreamError instanceof APIError ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
|
|
458233
458163
|
const delayMs = getRetryDelayMs2({
|
|
458234
458164
|
category: "transient_provider",
|
|
@@ -458314,7 +458244,6 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
458314
458244
|
let conversationBusyRetries = 0;
|
|
458315
458245
|
let preStreamRecoveryAttempts = 0;
|
|
458316
458246
|
const MAX_CONVERSATION_BUSY_RETRIES = 3;
|
|
458317
|
-
let currentOpts = opts;
|
|
458318
458247
|
const retriedAfterBlockingRunSettled = new Set;
|
|
458319
458248
|
while (true) {
|
|
458320
458249
|
if (abortSignal?.aborted) {
|
|
@@ -458325,7 +458254,7 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
458325
458254
|
conversation_id: conversationId
|
|
458326
458255
|
});
|
|
458327
458256
|
try {
|
|
458328
|
-
const stream12 = await sendMessageStream(conversationId, messages,
|
|
458257
|
+
const stream12 = await sendMessageStream(conversationId, messages, opts, abortSignal ? { maxRetries: 0, signal: abortSignal } : { maxRetries: 0 });
|
|
458329
458258
|
return { kind: "stream", stream: stream12 };
|
|
458330
458259
|
} catch (preStreamError) {
|
|
458331
458260
|
if (abortSignal?.aborted) {
|
|
@@ -458361,21 +458290,6 @@ async function sendApprovalContinuationWithRetry(conversationId, messages, opts,
|
|
|
458361
458290
|
});
|
|
458362
458291
|
const attempt2 = transientRetries + 1;
|
|
458363
458292
|
transientRetries = attempt2;
|
|
458364
|
-
const fallbackHandle = maybeApplyProviderFallback(retryOptions.providerFallback, attempt2);
|
|
458365
|
-
if (fallbackHandle) {
|
|
458366
|
-
currentOpts = { ...currentOpts, overrideModel: fallbackHandle };
|
|
458367
|
-
emitRecoverableRetryNotice(socket, runtime, {
|
|
458368
|
-
kind: "transient_provider_retry",
|
|
458369
|
-
message: PROVIDER_FALLBACK_NOTICE,
|
|
458370
|
-
reason: "llm_api_error",
|
|
458371
|
-
attempt: attempt2,
|
|
458372
|
-
maxAttempts: LLM_API_ERROR_MAX_RETRIES,
|
|
458373
|
-
delayMs: 0,
|
|
458374
|
-
agentId: runtime.agentId ?? undefined,
|
|
458375
|
-
conversationId
|
|
458376
|
-
});
|
|
458377
|
-
continue;
|
|
458378
|
-
}
|
|
458379
458293
|
const retryAfterMs = preStreamError instanceof APIError ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
|
|
458380
458294
|
const delayMs = getRetryDelayMs2({
|
|
458381
458295
|
category: "transient_provider",
|
|
@@ -458468,8 +458382,6 @@ var init_send = __esm(async () => {
|
|
|
458468
458382
|
init_cwd();
|
|
458469
458383
|
init_permission_mode();
|
|
458470
458384
|
init_protocol_outbound();
|
|
458471
|
-
init_provider_fallback();
|
|
458472
|
-
init_recoverable_notices();
|
|
458473
458385
|
init_skill_injection();
|
|
458474
458386
|
init_turn_input_state();
|
|
458475
458387
|
init_turn_status();
|
|
@@ -459459,7 +459371,7 @@ __export(exports_diff, {
|
|
|
459459
459371
|
ADV_DIFF_IGNORE_WHITESPACE: () => ADV_DIFF_IGNORE_WHITESPACE,
|
|
459460
459372
|
ADV_DIFF_CONTEXT_LINES: () => ADV_DIFF_CONTEXT_LINES
|
|
459461
459373
|
});
|
|
459462
|
-
import { basename as
|
|
459374
|
+
import { basename as basename22 } from "node:path";
|
|
459463
459375
|
function readFileOrNull(p2) {
|
|
459464
459376
|
try {
|
|
459465
459377
|
return __require("node:fs").readFileSync(p2, "utf-8");
|
|
@@ -459483,7 +459395,7 @@ function applyAllOccurrences(content, oldStr, newStr) {
|
|
|
459483
459395
|
return { ok: true, out: content.split(oldStr).join(newStr) };
|
|
459484
459396
|
}
|
|
459485
459397
|
function computeAdvancedDiff(input, opts) {
|
|
459486
|
-
const fileName =
|
|
459398
|
+
const fileName = basename22(input.filePath || "");
|
|
459487
459399
|
const fileContent = opts?.oldStrOverride !== undefined ? opts.oldStrOverride : readFileOrNull(input.filePath);
|
|
459488
459400
|
if (fileContent === null && input.kind !== "write") {
|
|
459489
459401
|
return { mode: "fallback", reason: "File not readable" };
|
|
@@ -459549,7 +459461,7 @@ function computeAdvancedDiff(input, opts) {
|
|
|
459549
459461
|
return { mode: "advanced", fileName, oldStr, newStr, hunks };
|
|
459550
459462
|
}
|
|
459551
459463
|
function parsePatchToAdvancedDiff(patchLines, filePath) {
|
|
459552
|
-
const fileName =
|
|
459464
|
+
const fileName = basename22(filePath);
|
|
459553
459465
|
const hunks = [];
|
|
459554
459466
|
let currentHunk = null;
|
|
459555
459467
|
let oldLine = 1;
|
|
@@ -459827,8 +459739,8 @@ function isFormatterSegment(tokens) {
|
|
|
459827
459739
|
}
|
|
459828
459740
|
}
|
|
459829
459741
|
function isShellExecutor2(token2) {
|
|
459830
|
-
const
|
|
459831
|
-
return ["bash", "sh", "zsh", "dash", "ksh"].includes(
|
|
459742
|
+
const basename23 = token2.split("/").pop() ?? token2;
|
|
459743
|
+
return ["bash", "sh", "zsh", "dash", "ksh"].includes(basename23.toLowerCase());
|
|
459832
459744
|
}
|
|
459833
459745
|
function normalizeRawCommand(command) {
|
|
459834
459746
|
if (Array.isArray(command)) {
|
|
@@ -460609,7 +460521,7 @@ var init_format_args_display = __esm(async () => {
|
|
|
460609
460521
|
});
|
|
460610
460522
|
|
|
460611
460523
|
// src/helpers/diff-preview.ts
|
|
460612
|
-
import path41, { basename as
|
|
460524
|
+
import path41, { basename as basename23 } from "node:path";
|
|
460613
460525
|
function parseHunkLinePrefix(raw2) {
|
|
460614
460526
|
if (raw2.length === 0) {
|
|
460615
460527
|
return { type: "context", content: "" };
|
|
@@ -460715,7 +460627,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = getCur
|
|
|
460715
460627
|
filePath: resolvedFilePath,
|
|
460716
460628
|
content: toolArgs.content || ""
|
|
460717
460629
|
});
|
|
460718
|
-
previews.push(toDiffPreview(result2,
|
|
460630
|
+
previews.push(toDiffPreview(result2, basename23(filePath)));
|
|
460719
460631
|
}
|
|
460720
460632
|
} else if (isFileEditTool3(toolName)) {
|
|
460721
460633
|
const filePath = toolArgs.file_path;
|
|
@@ -460727,7 +460639,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = getCur
|
|
|
460727
460639
|
filePath: resolvedFilePath,
|
|
460728
460640
|
edits: toolArgs.edits
|
|
460729
460641
|
});
|
|
460730
|
-
previews.push(toDiffPreview(result2,
|
|
460642
|
+
previews.push(toDiffPreview(result2, basename23(filePath)));
|
|
460731
460643
|
} else {
|
|
460732
460644
|
const result2 = computeAdvancedDiff2({
|
|
460733
460645
|
kind: "edit",
|
|
@@ -460736,7 +460648,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = getCur
|
|
|
460736
460648
|
newString: toolArgs.new_string || "",
|
|
460737
460649
|
replaceAll: toolArgs.replace_all
|
|
460738
460650
|
});
|
|
460739
|
-
previews.push(toDiffPreview(result2,
|
|
460651
|
+
previews.push(toDiffPreview(result2, basename23(filePath)));
|
|
460740
460652
|
}
|
|
460741
460653
|
}
|
|
460742
460654
|
} else if (isPatchTool2(toolName) && toolArgs.input) {
|
|
@@ -460745,7 +460657,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = getCur
|
|
|
460745
460657
|
if (op.kind === "add" || op.kind === "update") {
|
|
460746
460658
|
const result2 = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
460747
460659
|
if (result2) {
|
|
460748
|
-
previews.push(toDiffPreview(result2,
|
|
460660
|
+
previews.push(toDiffPreview(result2, basename23(op.path)));
|
|
460749
460661
|
}
|
|
460750
460662
|
}
|
|
460751
460663
|
}
|
|
@@ -460755,7 +460667,7 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = getCur
|
|
|
460755
460667
|
if (op.kind === "add" || op.kind === "update") {
|
|
460756
460668
|
const result2 = parsePatchToAdvancedDiff2(op.patchLines, op.path);
|
|
460757
460669
|
if (result2) {
|
|
460758
|
-
previews.push(toDiffPreview(result2,
|
|
460670
|
+
previews.push(toDiffPreview(result2, basename23(op.path)));
|
|
460759
460671
|
}
|
|
460760
460672
|
}
|
|
460761
460673
|
}
|
|
@@ -460798,7 +460710,6 @@ async function handleApprovalStop(params) {
|
|
|
460798
460710
|
turnLease,
|
|
460799
460711
|
processOwnedTurn = false,
|
|
460800
460712
|
buildSendOptions,
|
|
460801
|
-
providerFallback,
|
|
460802
460713
|
dependencies: dependencies4
|
|
460803
460714
|
} = params;
|
|
460804
460715
|
const abortSignal = turnLease.signal;
|
|
@@ -461122,7 +461033,7 @@ async function handleApprovalStop(params) {
|
|
|
461122
461033
|
...continuationActingUserId ? { actingUserId: continuationActingUserId } : {},
|
|
461123
461034
|
...imageFailureModesByMessageOtid ? { imageFailureModesByMessageOtid } : {},
|
|
461124
461035
|
...continuationWasFullyAutoHandled ? { allowResponseStateReuse: true } : {}
|
|
461125
|
-
}, socket, runtime, turnLease
|
|
461036
|
+
}, socket, runtime, turnLease);
|
|
461126
461037
|
} catch (error54) {
|
|
461127
461038
|
if (shouldInterrupt()) {
|
|
461128
461039
|
return interruptTermination(nextTurnInput, continuationBatchId);
|
|
@@ -461746,11 +461657,11 @@ function createTurnInputSender(params) {
|
|
|
461746
461657
|
return {
|
|
461747
461658
|
async send(input) {
|
|
461748
461659
|
if (isApprovalOnlyInput(input)) {
|
|
461749
|
-
return sendApprovalContinuationWithRetry(params.conversationId, input, params.buildSendOptions(), params.socket, params.runtime, params.turnLease
|
|
461660
|
+
return sendApprovalContinuationWithRetry(params.conversationId, input, params.buildSendOptions(), params.socket, params.runtime, params.turnLease);
|
|
461750
461661
|
}
|
|
461751
461662
|
return {
|
|
461752
461663
|
kind: "stream",
|
|
461753
|
-
stream: await sendMessageStreamWithRetry(params.conversationId, input, params.buildSendOptions(), params.socket, params.runtime, params.turnLease
|
|
461664
|
+
stream: await sendMessageStreamWithRetry(params.conversationId, input, params.buildSendOptions(), params.socket, params.runtime, params.turnLease)
|
|
461754
461665
|
};
|
|
461755
461666
|
},
|
|
461756
461667
|
accept(result2) {
|
|
@@ -463007,7 +462918,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463007
462918
|
}
|
|
463008
462919
|
let turnInput = setup.turnInput;
|
|
463009
462920
|
const inboundUserTranscriptLines = setup.inboundUserTranscriptLines;
|
|
463010
|
-
const
|
|
462921
|
+
const overrideModel = setup.overrideModel;
|
|
463011
462922
|
let pendingNormalizationInterruptedToolCallIds = setup.pendingNormalizationInterruptedToolCallIds;
|
|
463012
462923
|
const preparedToolContext = setup.preparedToolContext;
|
|
463013
462924
|
const buildSendOptions = () => ({
|
|
@@ -463021,7 +462932,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463021
462932
|
...turnInput.imageFailureModesByMessageOtid ? {
|
|
463022
462933
|
imageFailureModesByMessageOtid: turnInput.imageFailureModesByMessageOtid
|
|
463023
462934
|
} : {},
|
|
463024
|
-
...
|
|
462935
|
+
...overrideModel ? { overrideModel } : {},
|
|
463025
462936
|
...msg.actingUserId ? { actingUserId: msg.actingUserId } : {},
|
|
463026
462937
|
...pendingNormalizationInterruptedToolCallIds.length > 0 ? {
|
|
463027
462938
|
approvalNormalization: {
|
|
@@ -463035,7 +462946,6 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463035
462946
|
socket,
|
|
463036
462947
|
runtime,
|
|
463037
462948
|
turnLease,
|
|
463038
|
-
providerFallback,
|
|
463039
462949
|
buildSendOptions,
|
|
463040
462950
|
onTerminal: noteFinalization,
|
|
463041
462951
|
getTurnId: () => activeDequeuedBatchId
|
|
@@ -463278,13 +463188,12 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463278
463188
|
if (retriable && llmApiErrorRetries < LLM_API_ERROR_MAX_RETRIES) {
|
|
463279
463189
|
llmApiErrorRetries += 1;
|
|
463280
463190
|
const attempt2 = llmApiErrorRetries;
|
|
463281
|
-
const
|
|
463282
|
-
const delayMs = fallbackHandle ? 0 : getRetryDelayMs2({
|
|
463191
|
+
const delayMs = getRetryDelayMs2({
|
|
463283
463192
|
category: "transient_provider",
|
|
463284
463193
|
attempt: attempt2,
|
|
463285
463194
|
detail: errorDetail2
|
|
463286
463195
|
});
|
|
463287
|
-
const retryMessage =
|
|
463196
|
+
const retryMessage = getRetryStatusMessage(errorDetail2) || `LLM API error encountered, retrying (attempt ${attempt2}/${LLM_API_ERROR_MAX_RETRIES})...`;
|
|
463288
463197
|
emitRecoverableRetryNotice(socket, runtime, {
|
|
463289
463198
|
kind: "transient_provider_retry",
|
|
463290
463199
|
message: retryMessage,
|
|
@@ -463296,9 +463205,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463296
463205
|
agentId,
|
|
463297
463206
|
conversationId
|
|
463298
463207
|
});
|
|
463299
|
-
|
|
463300
|
-
await new Promise((resolve35) => setTimeout(resolve35, delayMs));
|
|
463301
|
-
}
|
|
463208
|
+
await new Promise((resolve35) => setTimeout(resolve35, delayMs));
|
|
463302
463209
|
if (turnAbortSignal.aborted) {
|
|
463303
463210
|
throw new Error("Cancelled by user");
|
|
463304
463211
|
}
|
|
@@ -463381,8 +463288,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
|
|
|
463381
463288
|
turnToolContextId,
|
|
463382
463289
|
turnLease,
|
|
463383
463290
|
processOwnedTurn: msg.processOwnedTurn === true,
|
|
463384
|
-
buildSendOptions
|
|
463385
|
-
providerFallback
|
|
463291
|
+
buildSendOptions
|
|
463386
463292
|
});
|
|
463387
463293
|
if (approvalResult.kind === "error") {
|
|
463388
463294
|
const terminalRunId = runId || runtime.activeRunId;
|
|
@@ -463571,7 +463477,6 @@ var init_turn = __esm(async () => {
|
|
|
463571
463477
|
init_interrupts();
|
|
463572
463478
|
init_permission_mode();
|
|
463573
463479
|
init_protocol_outbound();
|
|
463574
|
-
init_provider_fallback();
|
|
463575
463480
|
init_recoverable_notices();
|
|
463576
463481
|
init_runtime();
|
|
463577
463482
|
init_skill_injection();
|
|
@@ -465437,7 +465342,7 @@ __export(exports_custom, {
|
|
|
465437
465342
|
});
|
|
465438
465343
|
import { existsSync as existsSync52 } from "node:fs";
|
|
465439
465344
|
import { readdir as readdir11, readFile as readFile22 } from "node:fs/promises";
|
|
465440
|
-
import { basename as
|
|
465345
|
+
import { basename as basename25, dirname as dirname30, join as join68 } from "node:path";
|
|
465441
465346
|
async function getCustomCommands() {
|
|
465442
465347
|
if (cachedCommands !== null) {
|
|
465443
465348
|
return cachedCommands;
|
|
@@ -465497,7 +465402,7 @@ async function findCommandFiles(currentPath, rootPath, commands, source2) {
|
|
|
465497
465402
|
async function parseCommandFile(filePath, rootPath, source2) {
|
|
465498
465403
|
const content = await readFile22(filePath, "utf-8");
|
|
465499
465404
|
const { frontmatter, body: body3 } = parseFrontmatter(content);
|
|
465500
|
-
const id2 =
|
|
465405
|
+
const id2 = basename25(filePath, ".md");
|
|
465501
465406
|
const relativePath = dirname30(filePath).slice(rootPath.length);
|
|
465502
465407
|
const namespace = relativePath.replace(/^[/\\]/, "") || undefined;
|
|
465503
465408
|
let description = getStringField(frontmatter, "description");
|
|
@@ -465655,7 +465560,7 @@ var init_init_command = __esm(() => {
|
|
|
465655
465560
|
|
|
465656
465561
|
// src/cli/helpers/skill-name-frontmatter-repair.ts
|
|
465657
465562
|
import { readdir as readdir12, readFile as readFile23, stat as stat15, writeFile as writeFile16 } from "node:fs/promises";
|
|
465658
|
-
import { basename as
|
|
465563
|
+
import { basename as basename26, dirname as dirname31, join as join69, relative as relative14 } from "node:path";
|
|
465659
465564
|
async function pathExists(path45) {
|
|
465660
465565
|
try {
|
|
465661
465566
|
await stat15(path45);
|
|
@@ -465762,7 +465667,7 @@ async function repairMissingSkillNameFrontmatter(memoryDir) {
|
|
|
465762
465667
|
result2.scanned++;
|
|
465763
465668
|
try {
|
|
465764
465669
|
const content = await readFile23(skillFile, "utf8");
|
|
465765
|
-
const repair3 = repairSkillNameFrontmatterContent(content,
|
|
465670
|
+
const repair3 = repairSkillNameFrontmatterContent(content, basename26(dirname31(skillFile)));
|
|
465766
465671
|
if (repair3.reason) {
|
|
465767
465672
|
result2.skipped.push({ path: displayPath, reason: repair3.reason });
|
|
465768
465673
|
continue;
|
|
@@ -466724,7 +466629,7 @@ var init_boot_working_directory = __esm(() => {
|
|
|
466724
466629
|
|
|
466725
466630
|
// src/providers/chatgpt-usage-service.ts
|
|
466726
466631
|
import { hostname as hostname4 } from "node:os";
|
|
466727
|
-
function
|
|
466632
|
+
function asRecord8(value) {
|
|
466728
466633
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
466729
466634
|
}
|
|
466730
466635
|
function getValue(record5, keys3) {
|
|
@@ -466738,13 +466643,13 @@ function getValue(record5, keys3) {
|
|
|
466738
466643
|
return;
|
|
466739
466644
|
}
|
|
466740
466645
|
function getRecord(record5, keys3) {
|
|
466741
|
-
return
|
|
466646
|
+
return asRecord8(getValue(record5, keys3));
|
|
466742
466647
|
}
|
|
466743
466648
|
function getRecordArray(record5, keys3) {
|
|
466744
466649
|
const value = getValue(record5, keys3);
|
|
466745
466650
|
if (!Array.isArray(value))
|
|
466746
466651
|
return [];
|
|
466747
|
-
return value.map(
|
|
466652
|
+
return value.map(asRecord8).filter((item) => !!item);
|
|
466748
466653
|
}
|
|
466749
466654
|
function getNumber(record5, keys3) {
|
|
466750
466655
|
const value = getValue(record5, keys3);
|
|
@@ -466787,7 +466692,7 @@ function getTimestampSeconds(record5, keys3) {
|
|
|
466787
466692
|
return normalizeTimestampSeconds(getValue(record5, keys3));
|
|
466788
466693
|
}
|
|
466789
466694
|
function normalizeUsageWindow(value, label, nowMs) {
|
|
466790
|
-
const record5 =
|
|
466695
|
+
const record5 = asRecord8(value);
|
|
466791
466696
|
if (!record5)
|
|
466792
466697
|
return null;
|
|
466793
466698
|
const usedPercent = getNumber(record5, [
|
|
@@ -466889,7 +466794,7 @@ function normalizeIndividualLimit(raw2, nowMs) {
|
|
|
466889
466794
|
};
|
|
466890
466795
|
}
|
|
466891
466796
|
function normalizeCloudUsageWindow(value, fallbackLabel, nowMs) {
|
|
466892
|
-
const record5 =
|
|
466797
|
+
const record5 = asRecord8(value);
|
|
466893
466798
|
if (!record5)
|
|
466894
466799
|
return null;
|
|
466895
466800
|
return normalizeUsageWindow(record5, getString(record5, ["label", "name"]) ?? fallbackLabel, nowMs);
|
|
@@ -466920,7 +466825,7 @@ function getRateLimitReachedType(raw2) {
|
|
|
466920
466825
|
]);
|
|
466921
466826
|
if (typeof value === "string" && value.trim())
|
|
466922
466827
|
return value.trim();
|
|
466923
|
-
const record5 =
|
|
466828
|
+
const record5 = asRecord8(value);
|
|
466924
466829
|
return getString(record5, ["type", "kind"]);
|
|
466925
466830
|
}
|
|
466926
466831
|
function formatPercent(value) {
|
|
@@ -467013,7 +466918,7 @@ function formatChatGPTUsageQuotaRows(snapshot, now2 = new Date) {
|
|
|
467013
466918
|
return rows.length > 0 ? rows : [snapshot.summary.replace(/^Usage:\s*/, "")];
|
|
467014
466919
|
}
|
|
467015
466920
|
function normalizeWhamUsageResponse(input) {
|
|
467016
|
-
const raw2 =
|
|
466921
|
+
const raw2 = asRecord8(input.raw);
|
|
467017
466922
|
const nowMs = input.nowMs ?? Date.now();
|
|
467018
466923
|
const fetchedAt = new Date(nowMs).toISOString();
|
|
467019
466924
|
const rateLimit = getRecord(raw2, ["rate_limit", "rateLimit", "rate_limits", "rateLimits"]) ?? raw2;
|
|
@@ -467051,7 +466956,7 @@ function normalizeWhamUsageResponse(input) {
|
|
|
467051
466956
|
};
|
|
467052
466957
|
}
|
|
467053
466958
|
function normalizeCloudChatGPTUsageResponse(input) {
|
|
467054
|
-
const raw2 =
|
|
466959
|
+
const raw2 = asRecord8(input.raw);
|
|
467055
466960
|
if (!raw2)
|
|
467056
466961
|
return null;
|
|
467057
466962
|
const nowMs = input.nowMs ?? Date.now();
|
|
@@ -467097,7 +467002,7 @@ function retryAfterMsFromBody(raw2) {
|
|
|
467097
467002
|
}
|
|
467098
467003
|
async function readJsonRecord(response) {
|
|
467099
467004
|
try {
|
|
467100
|
-
return
|
|
467005
|
+
return asRecord8(await response.json()) ?? null;
|
|
467101
467006
|
} catch {
|
|
467102
467007
|
return null;
|
|
467103
467008
|
}
|
|
@@ -470856,7 +470761,7 @@ var init_app_server_openai_common = __esm(() => {
|
|
|
470856
470761
|
});
|
|
470857
470762
|
|
|
470858
470763
|
// src/websocket/app-server-openai-tools.ts
|
|
470859
|
-
function
|
|
470764
|
+
function asRecord9(value) {
|
|
470860
470765
|
return value !== null && typeof value === "object" ? value : null;
|
|
470861
470766
|
}
|
|
470862
470767
|
function stringValue3(value) {
|
|
@@ -470869,7 +470774,7 @@ function extractToolCallFragments(record5) {
|
|
|
470869
470774
|
const rawToolCalls = Array.isArray(record5.tool_calls) ? record5.tool_calls : record5.tool_call ? [record5.tool_call] : [];
|
|
470870
470775
|
const fragments = [];
|
|
470871
470776
|
for (const rawToolCall of rawToolCalls) {
|
|
470872
|
-
const toolCall =
|
|
470777
|
+
const toolCall = asRecord9(rawToolCall);
|
|
470873
470778
|
if (!toolCall) {
|
|
470874
470779
|
continue;
|
|
470875
470780
|
}
|
|
@@ -470914,7 +470819,7 @@ function extractToolReturns(record5) {
|
|
|
470914
470819
|
const toolReturnsValue = record5.tool_returns;
|
|
470915
470820
|
if (Array.isArray(toolReturnsValue)) {
|
|
470916
470821
|
for (const raw2 of toolReturnsValue) {
|
|
470917
|
-
const rec =
|
|
470822
|
+
const rec = asRecord9(raw2);
|
|
470918
470823
|
if (!rec) {
|
|
470919
470824
|
continue;
|
|
470920
470825
|
}
|
|
@@ -472922,7 +472827,9 @@ async function runListenSubcommand(argv) {
|
|
|
472922
472827
|
},
|
|
472923
472828
|
onUnexpectedExit: (error54) => {
|
|
472924
472829
|
console.error(`[${formatTimestamp3()}] ${error54.message}`);
|
|
472925
|
-
|
|
472830
|
+
if (values3.channels) {
|
|
472831
|
+
exitWithTelemetry(1, "listener_channel_gateway_exited");
|
|
472832
|
+
}
|
|
472926
472833
|
},
|
|
472927
472834
|
onServiceEvent: (event2) => {
|
|
472928
472835
|
if (event2.kind === "protocol") {
|
|
@@ -476136,7 +476043,7 @@ var init_sandbox_files = __esm(() => {
|
|
|
476136
476043
|
|
|
476137
476044
|
// src/cli/subcommands/sandbox.ts
|
|
476138
476045
|
import { readFile as readFile25, stat as stat17, writeFile as writeFile18 } from "node:fs/promises";
|
|
476139
|
-
import { basename as
|
|
476046
|
+
import { basename as basename27, resolve as resolve36 } from "node:path";
|
|
476140
476047
|
import { parseArgs as parseArgs13 } from "node:util";
|
|
476141
476048
|
function printUsage11() {
|
|
476142
476049
|
console.log(`
|
|
@@ -476219,13 +476126,13 @@ async function runSandboxSubcommand(argv, deps = {}) {
|
|
|
476219
476126
|
throw new Error(`${localPath2} is not a file`);
|
|
476220
476127
|
const data2 = await (deps.readLocalFile ?? readFile25)(localPath2);
|
|
476221
476128
|
const sandbox2 = await ensureSandbox(session.agentId, session.conversationId);
|
|
476222
|
-
const result2 = await (deps.uploadFile ?? uploadFileToSandbox)(sandbox2.sandboxId, { blob: new Blob([data2]), name:
|
|
476129
|
+
const result2 = await (deps.uploadFile ?? uploadFileToSandbox)(sandbox2.sandboxId, { blob: new Blob([data2]), name: basename27(localPath2) });
|
|
476223
476130
|
console.log(JSON.stringify(result2, null, 2));
|
|
476224
476131
|
return 0;
|
|
476225
476132
|
}
|
|
476226
476133
|
const sandbox = await ensureSandbox(session.agentId, session.conversationId);
|
|
476227
476134
|
const data = await (deps.downloadFile ?? downloadFileFromSandbox)(sandbox.sandboxId, path48);
|
|
476228
|
-
const localPath = resolve36(parsed.values.to ??
|
|
476135
|
+
const localPath = resolve36(parsed.values.to ?? basename27(path48));
|
|
476229
476136
|
await (deps.writeLocalFile ?? writeFile18)(localPath, data);
|
|
476230
476137
|
console.log(JSON.stringify({ path: localPath, sandboxPath: path48, size: data.byteLength }, null, 2));
|
|
476231
476138
|
return 0;
|
|
@@ -478635,7 +478542,7 @@ import {
|
|
|
478635
478542
|
} from "node:fs";
|
|
478636
478543
|
import { mkdir as mkdir15, readdir as readdir14 } from "node:fs/promises";
|
|
478637
478544
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
478638
|
-
import { basename as
|
|
478545
|
+
import { basename as basename28, dirname as dirname34, join as join75, normalize as normalize5, resolve as resolve37, sep as sep8 } from "node:path";
|
|
478639
478546
|
import { parseArgs as parseArgs16, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
|
|
478640
478547
|
function printUsage14() {
|
|
478641
478548
|
console.log(`
|
|
@@ -478830,7 +478737,7 @@ function parseDirectSkillFileUrlSpecifier(input) {
|
|
|
478830
478737
|
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && isLocalhostHostname(url2.hostname))) {
|
|
478831
478738
|
return null;
|
|
478832
478739
|
}
|
|
478833
|
-
if (
|
|
478740
|
+
if (basename28(url2.pathname).toLowerCase() !== "skill.md")
|
|
478834
478741
|
return null;
|
|
478835
478742
|
return { url: url2.toString() };
|
|
478836
478743
|
}
|
|
@@ -479078,7 +478985,7 @@ function getSkillName(sourceDir) {
|
|
|
479078
478985
|
const skillMd = readFileSync40(join75(sourceDir, "SKILL.md"), "utf8");
|
|
479079
478986
|
const { frontmatter } = parseFrontmatter(skillMd);
|
|
479080
478987
|
const frontmatterName = frontmatter.name;
|
|
479081
|
-
const name = typeof frontmatterName === "string" && frontmatterName.trim() ? frontmatterName :
|
|
478988
|
+
const name = typeof frontmatterName === "string" && frontmatterName.trim() ? frontmatterName : basename28(sourceDir);
|
|
479082
478989
|
return sanitizeSkillName(name);
|
|
479083
478990
|
}
|
|
479084
478991
|
async function installSkillDirectory(params) {
|
|
@@ -479104,7 +479011,7 @@ async function installSkillDirectory(params) {
|
|
|
479104
479011
|
await mkdir15(skillsDir, { recursive: true });
|
|
479105
479012
|
cpSync2(sourceDir, targetPath, {
|
|
479106
479013
|
recursive: true,
|
|
479107
|
-
filter: (source2) =>
|
|
479014
|
+
filter: (source2) => basename28(source2) !== ".git"
|
|
479108
479015
|
});
|
|
479109
479016
|
return { name, path: normalize5(targetPath) };
|
|
479110
479017
|
}
|
|
@@ -479522,6 +479429,7 @@ function printUsage15() {
|
|
|
479522
479429
|
Usage:
|
|
479523
479430
|
letta teleport list
|
|
479524
479431
|
letta teleport cloud
|
|
479432
|
+
letta teleport local
|
|
479525
479433
|
letta teleport <environment>
|
|
479526
479434
|
|
|
479527
479435
|
Notes:
|
|
@@ -479531,10 +479439,10 @@ Notes:
|
|
|
479531
479439
|
- Requires a Letta Cloud agent and a non-virtual conversation.
|
|
479532
479440
|
- list: prints accessible online remote environments as JSON.
|
|
479533
479441
|
- cloud: teleports to the agent's Cloud sandbox.
|
|
479442
|
+
- local: teleports to the one online Desktop environment. Desktop Remote
|
|
479443
|
+
Access must be enabled; if several are online, choose one explicitly.
|
|
479534
479444
|
- <environment>: teleports to a specific remote environment by name,
|
|
479535
479445
|
device-id, connection-id, or environment id.
|
|
479536
|
-
- Desktop Local is not a teleport target yet. Use the Desktop environment
|
|
479537
|
-
picker to switch back to Local.
|
|
479538
479446
|
- Output is JSON only.
|
|
479539
479447
|
`.trim());
|
|
479540
479448
|
}
|
|
@@ -479599,7 +479507,7 @@ function isTeleportableRemoteEnvironment(environment2) {
|
|
|
479599
479507
|
}
|
|
479600
479508
|
function assertTeleportableRemoteEnvironment(environment2) {
|
|
479601
479509
|
if (!isTeleportableRemoteEnvironment(environment2)) {
|
|
479602
|
-
throw new Error("Desktop
|
|
479510
|
+
throw new Error("The Desktop-local connection is not Cloud-routable. Use `letta teleport local` to resolve its Remote Access environment.");
|
|
479603
479511
|
}
|
|
479604
479512
|
}
|
|
479605
479513
|
async function initializeTeleportSettings() {
|
|
@@ -479637,8 +479545,12 @@ async function runTeleportSubcommand(argv, deps = {}) {
|
|
|
479637
479545
|
conversationId: session.conversationId
|
|
479638
479546
|
});
|
|
479639
479547
|
targetConnectionId = result3.connectionId;
|
|
479548
|
+
} else if (action3 === "local") {
|
|
479549
|
+
const resolve38 = deps.resolveDesktopEnvironmentConnectionId ?? resolveDesktopEnvironmentConnectionId;
|
|
479550
|
+
const result3 = await resolve38();
|
|
479551
|
+
targetConnectionId = result3.connectionId;
|
|
479640
479552
|
} else if (action3 === "back") {
|
|
479641
|
-
throw new Error("Teleport back is not supported
|
|
479553
|
+
throw new Error("Teleport back is not supported. Use `letta teleport local` or choose an explicit environment.");
|
|
479642
479554
|
} else {
|
|
479643
479555
|
const resolve38 = deps.resolveEnvironmentConnectionId ?? resolveEnvironmentConnectionId;
|
|
479644
479556
|
const resolved = await resolve38(action3);
|
|
@@ -479762,7 +479674,7 @@ import {
|
|
|
479762
479674
|
stat as stat19,
|
|
479763
479675
|
writeFile as writeFile19
|
|
479764
479676
|
} from "node:fs/promises";
|
|
479765
|
-
import { basename as
|
|
479677
|
+
import { basename as basename29, join as join77 } from "node:path";
|
|
479766
479678
|
function fileTimestamp(startedAt) {
|
|
479767
479679
|
if (!startedAt)
|
|
479768
479680
|
return "unknown-date";
|
|
@@ -479930,10 +479842,10 @@ async function runTrajectoryExport(options3) {
|
|
|
479930
479842
|
if (!supported.includes(explicit.source)) {
|
|
479931
479843
|
throw new Error(`Unknown source "${explicit.source}" in --transcript. The installed trajectory package supports: ${supported.join(", ")}.`);
|
|
479932
479844
|
}
|
|
479933
|
-
await exportTranscript(explicit.source,
|
|
479845
|
+
await exportTranscript(explicit.source, basename29(explicit.path).replace(/\.[^.]+$/, ""), explicit.path, () => readFile27(explicit.path, "utf-8"));
|
|
479934
479846
|
}
|
|
479935
479847
|
for (const checkpoint2 of options3.deepagents ?? []) {
|
|
479936
|
-
await exportCheckpoint(checkpoint2, `${
|
|
479848
|
+
await exportCheckpoint(checkpoint2, `${basename29(checkpoint2.path)}-${checkpoint2.threadId}`);
|
|
479937
479849
|
}
|
|
479938
479850
|
manifest2.sessions.sort((a2, b3) => (a2.startedAt ?? "").localeCompare(b3.startedAt ?? ""));
|
|
479939
479851
|
await writeFile19(join77(options3.outDir, MANIFEST_NAME), JSON.stringify(manifest2, null, 2), "utf-8");
|
|
@@ -481786,7 +481698,7 @@ class ChannelRichDraftStreamerImpl {
|
|
|
481786
481698
|
if (this.disposed) {
|
|
481787
481699
|
return;
|
|
481788
481700
|
}
|
|
481789
|
-
const record5 =
|
|
481701
|
+
const record5 = asRecord10(chunk2);
|
|
481790
481702
|
const messageType = stringValue4(record5?.message_type);
|
|
481791
481703
|
if (messageType === "tool_return_message") {
|
|
481792
481704
|
const toolCallId = stringValue4(record5?.tool_call_id);
|
|
@@ -482009,15 +481921,15 @@ function extractRetryAfterMs(error54) {
|
|
|
482009
481921
|
return null;
|
|
482010
481922
|
}
|
|
482011
481923
|
function findRetryAfterCandidates(error54) {
|
|
482012
|
-
const record5 =
|
|
481924
|
+
const record5 = asRecord10(error54);
|
|
482013
481925
|
if (!record5) {
|
|
482014
481926
|
return [];
|
|
482015
481927
|
}
|
|
482016
481928
|
return [
|
|
482017
|
-
|
|
482018
|
-
|
|
482019
|
-
|
|
482020
|
-
|
|
481929
|
+
asRecord10(record5.parameters)?.retry_after,
|
|
481930
|
+
asRecord10(record5.response)?.parameters && asRecord10(asRecord10(record5.response)?.parameters)?.retry_after,
|
|
481931
|
+
asRecord10(record5.payload)?.parameters && asRecord10(asRecord10(record5.payload)?.parameters)?.retry_after,
|
|
481932
|
+
asRecord10(record5.error)?.parameters && asRecord10(asRecord10(record5.error)?.parameters)?.retry_after
|
|
482021
481933
|
];
|
|
482022
481934
|
}
|
|
482023
481935
|
function extractChannelSendRichDraftIntent(argumentsText, source2, options3 = {}) {
|
|
@@ -482081,7 +481993,7 @@ function extractToolCallFragments2(record5) {
|
|
|
482081
481993
|
const rawToolCalls = Array.isArray(record5.tool_calls) ? record5.tool_calls : record5.tool_call ? [record5.tool_call] : [];
|
|
482082
481994
|
const fragments = [];
|
|
482083
481995
|
for (const rawToolCall of rawToolCalls) {
|
|
482084
|
-
const toolCall =
|
|
481996
|
+
const toolCall = asRecord10(rawToolCall);
|
|
482085
481997
|
const toolCallId = stringValue4(toolCall?.tool_call_id);
|
|
482086
481998
|
if (!toolCallId) {
|
|
482087
481999
|
continue;
|
|
@@ -482206,7 +482118,7 @@ function buildDraftId(seed) {
|
|
|
482206
482118
|
const positive = hash4 >>> 1;
|
|
482207
482119
|
return positive === 0 ? 1 : positive;
|
|
482208
482120
|
}
|
|
482209
|
-
function
|
|
482121
|
+
function asRecord10(value) {
|
|
482210
482122
|
return value && typeof value === "object" ? value : null;
|
|
482211
482123
|
}
|
|
482212
482124
|
function stringValue4(value) {
|
|
@@ -483020,11 +482932,11 @@ class ChannelGateway {
|
|
|
483020
482932
|
}
|
|
483021
482933
|
async performRuntimeRegistration(state, delivery) {
|
|
483022
482934
|
const tool2 = await this.hooks.buildExternalTool(delivery.runtime, delivery.sources);
|
|
483023
|
-
const
|
|
482935
|
+
const conversationTags2 = channelTagsForSources(delivery.sources);
|
|
483024
482936
|
const signature = JSON.stringify({
|
|
483025
482937
|
mode: delivery.defaultPermissionMode ?? null,
|
|
483026
482938
|
tool: tool2,
|
|
483027
|
-
conversationTags
|
|
482939
|
+
conversationTags: conversationTags2
|
|
483028
482940
|
});
|
|
483029
482941
|
if (state.registrationSignature === signature && state.registration) {
|
|
483030
482942
|
return state.registration;
|
|
@@ -483032,7 +482944,7 @@ class ChannelGateway {
|
|
|
483032
482944
|
const registration = this.client.runtimeStart({
|
|
483033
482945
|
agent_id: delivery.runtime.agent_id,
|
|
483034
482946
|
conversation_id: delivery.runtime.conversation_id,
|
|
483035
|
-
...
|
|
482947
|
+
...conversationTags2.length > 0 ? { conversation_source_tags: conversationTags2 } : {},
|
|
483036
482948
|
...delivery.defaultPermissionMode ? { mode: delivery.defaultPermissionMode } : {},
|
|
483037
482949
|
recover_approvals: true,
|
|
483038
482950
|
force_device_status: false,
|
|
@@ -488314,10 +488226,10 @@ class Protocol {
|
|
|
488314
488226
|
});
|
|
488315
488227
|
this.setRequestHandler(ListTasksRequestSchema, async (request2, extra) => {
|
|
488316
488228
|
try {
|
|
488317
|
-
const { tasks: tasks2, nextCursor } = await this._taskStore.listTasks(request2.params?.cursor, extra.sessionId);
|
|
488229
|
+
const { tasks: tasks2, nextCursor: nextCursor2 } = await this._taskStore.listTasks(request2.params?.cursor, extra.sessionId);
|
|
488318
488230
|
return {
|
|
488319
488231
|
tasks: tasks2,
|
|
488320
|
-
nextCursor,
|
|
488232
|
+
nextCursor: nextCursor2,
|
|
488321
488233
|
_meta: {}
|
|
488322
488234
|
};
|
|
488323
488235
|
} catch (error54) {
|
|
@@ -497645,7 +497557,7 @@ var init_mcp_client = __esm(() => {
|
|
|
497645
497557
|
init_streamableHttp();
|
|
497646
497558
|
DEFAULT_CLIENT_INFO = {
|
|
497647
497559
|
name: "letta-code",
|
|
497648
|
-
version: "0.30.
|
|
497560
|
+
version: "0.30.26"
|
|
497649
497561
|
};
|
|
497650
497562
|
});
|
|
497651
497563
|
|
|
@@ -498068,7 +497980,7 @@ var init_mcp_runtime = __esm(async () => {
|
|
|
498068
497980
|
|
|
498069
497981
|
// src/skills/builtin/creating-skills/scripts/validate-skill.ts
|
|
498070
497982
|
import { existsSync as existsSync62, readFileSync as readFileSync41 } from "node:fs";
|
|
498071
|
-
import { basename as
|
|
497983
|
+
import { basename as basename30, join as join81, resolve as resolve38 } from "node:path";
|
|
498072
497984
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
498073
497985
|
function parseQuotedScalar(value) {
|
|
498074
497986
|
if (value.startsWith('"')) {
|
|
@@ -498228,7 +498140,7 @@ function validateSkill(skillPath) {
|
|
|
498228
498140
|
message: `Name is too long (${trimmedName.length} characters). Maximum is ${MAX_SKILL_NAME_LENGTH} characters.`
|
|
498229
498141
|
};
|
|
498230
498142
|
}
|
|
498231
|
-
const dirName =
|
|
498143
|
+
const dirName = basename30(skillPath);
|
|
498232
498144
|
if (trimmedName !== dirName) {
|
|
498233
498145
|
warnings.push(`Name '${trimmedName}' doesn't match directory name '${dirName}'. For portability, these should match.`);
|
|
498234
498146
|
}
|
|
@@ -500037,8 +499949,6 @@ ${loadedContents.join(`
|
|
|
500037
499949
|
let llmApiErrorRetries = 0;
|
|
500038
499950
|
let emptyResponseRetries = 0;
|
|
500039
499951
|
let conversationBusyRetries = 0;
|
|
500040
|
-
let providerFallbackAttempted = false;
|
|
500041
|
-
let overrideModelHandle;
|
|
500042
499952
|
markMilestone("HEADLESS_FIRST_STREAM_START");
|
|
500043
499953
|
measureSinceMilestone("headless-setup-total", "HEADLESS_CLIENT_READY");
|
|
500044
499954
|
const checkMaxTurns = async () => {
|
|
@@ -500106,7 +500016,7 @@ ${loadedContents.join(`
|
|
|
500106
500016
|
const turnToolContext = await prepareHeadlessToolExecutionContext({
|
|
500107
500017
|
agentId: agent2.id,
|
|
500108
500018
|
conversationId,
|
|
500109
|
-
overrideModel:
|
|
500019
|
+
overrideModel: preparedEffectiveModel,
|
|
500110
500020
|
cachedAgent,
|
|
500111
500021
|
modContext: createHeadlessModContext({
|
|
500112
500022
|
agent: agent2,
|
|
@@ -500120,7 +500030,6 @@ ${loadedContents.join(`
|
|
|
500120
500030
|
availableTools = turnToolContext.availableTools;
|
|
500121
500031
|
stream12 = await sendMessageStream(conversationId, currentInput, {
|
|
500122
500032
|
agentId: agent2.id,
|
|
500123
|
-
overrideModel: overrideModelHandle,
|
|
500124
500033
|
preparedToolContext: turnToolContext.preparedToolContext.preparedToolContext
|
|
500125
500034
|
}, { maxRetries: 0, signal: sigintSignal });
|
|
500126
500035
|
turnToolContextId = getStreamToolContextId(stream12);
|
|
@@ -500187,26 +500096,6 @@ ${loadedContents.join(`
|
|
|
500187
500096
|
if (preStreamAction === "retry_transient") {
|
|
500188
500097
|
const attempt2 = llmApiErrorRetries + 1;
|
|
500189
500098
|
llmApiErrorRetries = attempt2;
|
|
500190
|
-
if (attempt2 >= 2 && !providerFallbackAttempted && model) {
|
|
500191
|
-
const fallbackId = PROVIDER_FALLBACK_MAP2[model];
|
|
500192
|
-
const fallbackHandle = fallbackId ? getModelInfo(fallbackId)?.handle : undefined;
|
|
500193
|
-
if (fallbackHandle) {
|
|
500194
|
-
providerFallbackAttempted = true;
|
|
500195
|
-
overrideModelHandle = fallbackHandle;
|
|
500196
|
-
if (outputFormat === "stream-json") {
|
|
500197
|
-
console.log(JSON.stringify({
|
|
500198
|
-
type: "status",
|
|
500199
|
-
message: "Anthropic API error; falling back to Bedrock...",
|
|
500200
|
-
session_id: sessionId,
|
|
500201
|
-
uuid: `fallback-${randomUUID35()}`
|
|
500202
|
-
}));
|
|
500203
|
-
} else {
|
|
500204
|
-
console.error("Anthropic API error; falling back to Bedrock...");
|
|
500205
|
-
}
|
|
500206
|
-
conversationBusyRetries = 0;
|
|
500207
|
-
continue;
|
|
500208
|
-
}
|
|
500209
|
-
}
|
|
500210
500099
|
const retryAfterMs2 = preStreamError instanceof APIError ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
|
|
500211
500100
|
const delayMs = getRetryDelayMs2({
|
|
500212
500101
|
category: "transient_provider",
|
|
@@ -500430,26 +500319,6 @@ ${loadedContents.join(`
|
|
|
500430
500319
|
if (llmApiErrorRetries < LLM_API_ERROR_MAX_RETRIES2) {
|
|
500431
500320
|
const attempt2 = llmApiErrorRetries + 1;
|
|
500432
500321
|
llmApiErrorRetries = attempt2;
|
|
500433
|
-
if (attempt2 >= 2 && !providerFallbackAttempted && model) {
|
|
500434
|
-
const fallbackId = PROVIDER_FALLBACK_MAP2[model];
|
|
500435
|
-
const fallbackHandle = fallbackId ? getModelInfo(fallbackId)?.handle : undefined;
|
|
500436
|
-
if (fallbackHandle) {
|
|
500437
|
-
providerFallbackAttempted = true;
|
|
500438
|
-
overrideModelHandle = fallbackHandle;
|
|
500439
|
-
if (outputFormat === "stream-json") {
|
|
500440
|
-
console.log(JSON.stringify({
|
|
500441
|
-
type: "status",
|
|
500442
|
-
message: "Anthropic API error; falling back to Bedrock...",
|
|
500443
|
-
session_id: sessionId,
|
|
500444
|
-
uuid: `fallback-${randomUUID35()}`
|
|
500445
|
-
}));
|
|
500446
|
-
} else {
|
|
500447
|
-
console.error("Anthropic API error; falling back to Bedrock...");
|
|
500448
|
-
}
|
|
500449
|
-
currentInput = refreshInputOtidsForNewRequest(currentInput);
|
|
500450
|
-
continue;
|
|
500451
|
-
}
|
|
500452
|
-
}
|
|
500453
500322
|
const delayMs = getRetryDelayMs2({
|
|
500454
500323
|
category: "transient_provider",
|
|
500455
500324
|
attempt: attempt2,
|
|
@@ -501806,7 +501675,7 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
|
|
|
501806
501675
|
setMessageQueueAdder(null);
|
|
501807
501676
|
await exitBidirectional(0, "headless_bidirectional_stdin_closed");
|
|
501808
501677
|
}
|
|
501809
|
-
var LLM_API_ERROR_MAX_RETRIES2 = 3, EMPTY_RESPONSE_MAX_RETRIES2 = 2, HEADLESS_STREAM_RESUME_POLICY,
|
|
501678
|
+
var LLM_API_ERROR_MAX_RETRIES2 = 3, EMPTY_RESPONSE_MAX_RETRIES2 = 2, HEADLESS_STREAM_RESUME_POLICY, CONVERSATION_BUSY_MAX_RETRIES = 3, __headlessTestUtils;
|
|
501810
501679
|
var init_headless = __esm(async () => {
|
|
501811
501680
|
init_error();
|
|
501812
501681
|
init_telemetry();
|
|
@@ -501863,29 +501732,6 @@ var init_headless = __esm(async () => {
|
|
|
501863
501732
|
maxAttempts: 20,
|
|
501864
501733
|
maxDelayMs: 2000
|
|
501865
501734
|
};
|
|
501866
|
-
PROVIDER_FALLBACK_MAP2 = {
|
|
501867
|
-
"opus-4.7-low": "bedrock-opus-4.7",
|
|
501868
|
-
"opus-4.7-medium": "bedrock-opus-4.7",
|
|
501869
|
-
"opus-4.7-high": "bedrock-opus-4.7",
|
|
501870
|
-
"opus-4.7-xhigh": "bedrock-opus-4.7",
|
|
501871
|
-
"opus-4.7-max": "bedrock-opus-4.7",
|
|
501872
|
-
"opus-4.6-no-reasoning": "bedrock-opus-4.6",
|
|
501873
|
-
"opus-4.6-low": "bedrock-opus-4.6",
|
|
501874
|
-
"opus-4.6-medium": "bedrock-opus-4.6",
|
|
501875
|
-
"opus-4.6-high": "bedrock-opus-4.6",
|
|
501876
|
-
"opus-4.6-xhigh": "bedrock-opus-4.6",
|
|
501877
|
-
sonnet: "bedrock-sonnet-5",
|
|
501878
|
-
"sonnet-5-no-reasoning": "bedrock-sonnet-5",
|
|
501879
|
-
"sonnet-5-low": "bedrock-sonnet-5",
|
|
501880
|
-
"sonnet-5-medium": "bedrock-sonnet-5",
|
|
501881
|
-
"sonnet-5-xhigh": "bedrock-sonnet-5",
|
|
501882
|
-
"sonnet-4.6": "bedrock-sonnet-4.6",
|
|
501883
|
-
"sonnet-1m": "bedrock-sonnet-4.6",
|
|
501884
|
-
"sonnet-4.6-no-reasoning": "bedrock-sonnet-4.6",
|
|
501885
|
-
"sonnet-4.6-low": "bedrock-sonnet-4.6",
|
|
501886
|
-
"sonnet-4.6-medium": "bedrock-sonnet-4.6",
|
|
501887
|
-
"sonnet-4.6-xhigh": "bedrock-sonnet-4.6"
|
|
501888
|
-
};
|
|
501889
501735
|
__headlessTestUtils = {
|
|
501890
501736
|
trackTelemetryUserInputFromContent,
|
|
501891
501737
|
shouldTrackTelemetryForQueuedMessage,
|
|
@@ -501915,7 +501761,7 @@ function buildConversationModelCarryoverUpdate(params) {
|
|
|
501915
501761
|
const updateArgs = {
|
|
501916
501762
|
...modelInfo?.updateArgs ?? {}
|
|
501917
501763
|
};
|
|
501918
|
-
const reasoningEffort = carryoverLlmConfig?.reasoning_effort;
|
|
501764
|
+
const reasoningEffort = normalizeReasoningEffortForModel(modelHandle, carryoverLlmConfig?.reasoning_effort);
|
|
501919
501765
|
if (typeof reasoningEffort === "string" && updateArgs.reasoning_effort === undefined) {
|
|
501920
501766
|
updateArgs.reasoning_effort = reasoningEffort;
|
|
501921
501767
|
}
|
|
@@ -501936,6 +501782,7 @@ function buildConversationModelCarryoverUpdate(params) {
|
|
|
501936
501782
|
var init_conversation_model_carryover = __esm(() => {
|
|
501937
501783
|
init_model();
|
|
501938
501784
|
init_model_handles();
|
|
501785
|
+
init_openai_reasoning_effort();
|
|
501939
501786
|
});
|
|
501940
501787
|
|
|
501941
501788
|
// src/agent/reconcile-existing-agent-state.ts
|
|
@@ -502303,7 +502150,7 @@ var BYTES_PER_TOKEN = 4;
|
|
|
502303
502150
|
|
|
502304
502151
|
// src/cli/helpers/window-title-config.ts
|
|
502305
502152
|
import { homedir as homedir45 } from "node:os";
|
|
502306
|
-
import { basename as
|
|
502153
|
+
import { basename as basename31, resolve as resolve40 } from "node:path";
|
|
502307
502154
|
function isWindowTitleField(value) {
|
|
502308
502155
|
return WINDOW_TITLE_FIELDS.includes(value);
|
|
502309
502156
|
}
|
|
@@ -502462,7 +502309,7 @@ function terminalTitleProjectName(data) {
|
|
|
502462
502309
|
if (!directory)
|
|
502463
502310
|
return null;
|
|
502464
502311
|
const resolved = resolve40(directory);
|
|
502465
|
-
const name =
|
|
502312
|
+
const name = basename31(resolved) || formatDirectoryDisplay(resolved) || resolved;
|
|
502466
502313
|
return truncateTerminalTitlePart(name, 24);
|
|
502467
502314
|
}
|
|
502468
502315
|
function titleDirectory(data) {
|
|
@@ -545518,31 +545365,8 @@ var init_AppView = __esm(async () => {
|
|
|
545518
545365
|
});
|
|
545519
545366
|
|
|
545520
545367
|
// src/cli/app/constants.ts
|
|
545521
|
-
var CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, TEMP_QUOTA_OVERRIDE_MODEL = "letta/auto",
|
|
545368
|
+
var CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, TEMP_QUOTA_OVERRIDE_MODEL = "letta/auto", CONVERSATION_BUSY_MAX_RETRIES2 = 3, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", PROVIDER_STATUS_PAGES, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12, SHELL_PREVIEW_MAX_LINES = 3;
|
|
545522
545369
|
var init_constants7 = __esm(() => {
|
|
545523
|
-
PROVIDER_FALLBACK_MAP3 = {
|
|
545524
|
-
"opus-4.7-low": "bedrock-opus-4.7",
|
|
545525
|
-
"opus-4.7-medium": "bedrock-opus-4.7",
|
|
545526
|
-
"opus-4.7-high": "bedrock-opus-4.7",
|
|
545527
|
-
"opus-4.7-xhigh": "bedrock-opus-4.7",
|
|
545528
|
-
"opus-4.7-max": "bedrock-opus-4.7",
|
|
545529
|
-
"opus-4.6-no-reasoning": "bedrock-opus-4.6",
|
|
545530
|
-
"opus-4.6-low": "bedrock-opus-4.6",
|
|
545531
|
-
"opus-4.6-medium": "bedrock-opus-4.6",
|
|
545532
|
-
"opus-4.6-high": "bedrock-opus-4.6",
|
|
545533
|
-
"opus-4.6-xhigh": "bedrock-opus-4.6",
|
|
545534
|
-
sonnet: "bedrock-sonnet-5",
|
|
545535
|
-
"sonnet-5-no-reasoning": "bedrock-sonnet-5",
|
|
545536
|
-
"sonnet-5-low": "bedrock-sonnet-5",
|
|
545537
|
-
"sonnet-5-medium": "bedrock-sonnet-5",
|
|
545538
|
-
"sonnet-5-xhigh": "bedrock-sonnet-5",
|
|
545539
|
-
"sonnet-4.6": "bedrock-sonnet-4.6",
|
|
545540
|
-
"sonnet-1m": "bedrock-sonnet-4.6",
|
|
545541
|
-
"sonnet-4.6-no-reasoning": "bedrock-sonnet-4.6",
|
|
545542
|
-
"sonnet-4.6-low": "bedrock-sonnet-4.6",
|
|
545543
|
-
"sonnet-4.6-medium": "bedrock-sonnet-4.6",
|
|
545544
|
-
"sonnet-4.6-xhigh": "bedrock-sonnet-4.6"
|
|
545545
|
-
};
|
|
545546
545370
|
PROVIDER_STATUS_PAGES = {
|
|
545547
545371
|
anthropic: {
|
|
545548
545372
|
name: "Anthropic",
|
|
@@ -545675,13 +545499,11 @@ function getErrorHintForStopReason(stopReason, currentModelId, modelEndpointType
|
|
|
545675
545499
|
}
|
|
545676
545500
|
const isAutoModel = currentModelId?.startsWith("auto") ?? false;
|
|
545677
545501
|
const statusInfo = modelEndpointType && !isAutoModel ? PROVIDER_STATUS_PAGES[modelEndpointType] : undefined;
|
|
545678
|
-
const bedrockOpusSuggestion = modelEndpointType === "anthropic" && currentModelId?.startsWith("opus-4.7") && getModelInfo("bedrock-opus-4.7") ? "Opus 4.7 via Amazon Bedrock" : modelEndpointType === "anthropic" && currentModelId?.startsWith("opus-4.6") && getModelInfo("bedrock-opus-4.6") ? "Opus 4.6 via Amazon Bedrock" : null;
|
|
545679
|
-
const modelSwapSuffix = bedrockOpusSuggestion ? ` (e.g. ${bedrockOpusSuggestion})` : "";
|
|
545680
545502
|
if (statusInfo) {
|
|
545681
545503
|
return [
|
|
545682
545504
|
`Downstream provider (${statusInfo.name}) is experiencing errors — check ${statusInfo.url} for additional information`,
|
|
545683
545505
|
`(note that the official status page may not be reliable / up-to-date).`,
|
|
545684
|
-
`Use /model to swap to a model from a different provider
|
|
545506
|
+
`Use /model to swap to a model from a different provider, or try again later.`
|
|
545685
545507
|
].join(" ");
|
|
545686
545508
|
}
|
|
545687
545509
|
return `Downstream provider is experiencing errors. Use /model to swap to a model from a different provider, or try again later.`;
|
|
@@ -547742,7 +547564,6 @@ function useConversationLoop(ctx) {
|
|
|
547742
547564
|
precomputedDiffsRef,
|
|
547743
547565
|
prepareScopedToolExecutionContext,
|
|
547744
547566
|
processingConversationRef,
|
|
547745
|
-
providerFallbackAttemptedRef,
|
|
547746
547567
|
queueApprovalResults,
|
|
547747
547568
|
queueSnapshotRef,
|
|
547748
547569
|
quotaAutoSwapAttemptedRef,
|
|
@@ -547946,7 +547767,6 @@ function useConversationLoop(ctx) {
|
|
|
547946
547767
|
emptyResponseRetriesRef.current = 0;
|
|
547947
547768
|
conversationBusyRetriesRef.current = 0;
|
|
547948
547769
|
quotaAutoSwapAttemptedRef.current = false;
|
|
547949
|
-
providerFallbackAttemptedRef.current = false;
|
|
547950
547770
|
}
|
|
547951
547771
|
let currentRunId;
|
|
547952
547772
|
let preserveTranscriptStartForApproval = false;
|
|
@@ -548149,26 +547969,6 @@ function useConversationLoop(ctx) {
|
|
|
548149
547969
|
if (preStreamAction === "retry_transient") {
|
|
548150
547970
|
llmApiErrorRetriesRef.current += 1;
|
|
548151
547971
|
const attempt2 = llmApiErrorRetriesRef.current;
|
|
548152
|
-
if (attempt2 >= 2 && !providerFallbackAttemptedRef.current && currentModelId) {
|
|
548153
|
-
const fallbackId = PROVIDER_FALLBACK_MAP3[currentModelId];
|
|
548154
|
-
const fallbackHandle = fallbackId ? getModelInfo(fallbackId)?.handle : undefined;
|
|
548155
|
-
if (fallbackHandle) {
|
|
548156
|
-
providerFallbackAttemptedRef.current = true;
|
|
548157
|
-
setTempModelOverride(fallbackHandle);
|
|
548158
|
-
const statusId = uid("status");
|
|
548159
|
-
buffersRef.current.byId.set(statusId, {
|
|
548160
|
-
kind: "status",
|
|
548161
|
-
id: statusId,
|
|
548162
|
-
lines: ["Anthropic API error; falling back to Bedrock..."]
|
|
548163
|
-
});
|
|
548164
|
-
buffersRef.current.order.push(statusId);
|
|
548165
|
-
refreshDerived();
|
|
548166
|
-
buffersRef.current.interrupted = false;
|
|
548167
|
-
conversationBusyRetriesRef.current = 0;
|
|
548168
|
-
restorePinnedPermissionMode();
|
|
548169
|
-
continue;
|
|
548170
|
-
}
|
|
548171
|
-
}
|
|
548172
547972
|
const retryAfterMs2 = preStreamError instanceof APIError ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
|
|
548173
547973
|
const delayMs = getRetryDelayMs2({
|
|
548174
547974
|
category: "transient_provider",
|
|
@@ -548376,7 +548176,6 @@ function useConversationLoop(ctx) {
|
|
|
548376
548176
|
llmApiErrorRetriesRef.current = 0;
|
|
548377
548177
|
emptyResponseRetriesRef.current = 0;
|
|
548378
548178
|
conversationBusyRetriesRef.current = 0;
|
|
548379
|
-
providerFallbackAttemptedRef.current = false;
|
|
548380
548179
|
lastDequeuedMessageRef.current = null;
|
|
548381
548180
|
lastSentInputRef.current = null;
|
|
548382
548181
|
pendingInterruptRecoveryConversationIdRef.current = null;
|
|
@@ -549004,26 +548803,6 @@ ${feedback}
|
|
|
549004
548803
|
if (retriable && llmApiErrorRetriesRef.current < LLM_API_ERROR_MAX_RETRIES3) {
|
|
549005
548804
|
llmApiErrorRetriesRef.current += 1;
|
|
549006
548805
|
const attempt2 = llmApiErrorRetriesRef.current;
|
|
549007
|
-
if (attempt2 >= 2 && !providerFallbackAttemptedRef.current && currentModelId) {
|
|
549008
|
-
const fallbackId = PROVIDER_FALLBACK_MAP3[currentModelId];
|
|
549009
|
-
const fallbackHandle = fallbackId ? getModelInfo(fallbackId)?.handle : undefined;
|
|
549010
|
-
if (fallbackHandle) {
|
|
549011
|
-
providerFallbackAttemptedRef.current = true;
|
|
549012
|
-
setTempModelOverride(fallbackHandle);
|
|
549013
|
-
const statusId = uid("status");
|
|
549014
|
-
buffersRef.current.byId.set(statusId, {
|
|
549015
|
-
kind: "status",
|
|
549016
|
-
id: statusId,
|
|
549017
|
-
lines: ["Anthropic API error; falling back to Bedrock..."]
|
|
549018
|
-
});
|
|
549019
|
-
buffersRef.current.order.push(statusId);
|
|
549020
|
-
refreshDerived();
|
|
549021
|
-
currentInput = refreshInputOtidsForNewRequest(currentInput);
|
|
549022
|
-
highestSeqIdSeen = null;
|
|
549023
|
-
buffersRef.current.interrupted = false;
|
|
549024
|
-
continue;
|
|
549025
|
-
}
|
|
549026
|
-
}
|
|
549027
548806
|
const delayMs = getRetryDelayMs2({
|
|
549028
548807
|
category: "transient_provider",
|
|
549029
548808
|
attempt: attempt2,
|
|
@@ -554520,7 +554299,7 @@ __export(exports_worktree_diff_list, {
|
|
|
554520
554299
|
listWorktreeDiffOptions: () => listWorktreeDiffOptions
|
|
554521
554300
|
});
|
|
554522
554301
|
import { execFile as execFileCb9 } from "node:child_process";
|
|
554523
|
-
import { basename as
|
|
554302
|
+
import { basename as basename32 } from "node:path";
|
|
554524
554303
|
import { promisify as promisify19 } from "node:util";
|
|
554525
554304
|
async function runGit9(cwd2, args) {
|
|
554526
554305
|
try {
|
|
@@ -554569,7 +554348,7 @@ function parseWorktreeList(output, currentPath) {
|
|
|
554569
554348
|
if (current?.path) {
|
|
554570
554349
|
worktrees.push({
|
|
554571
554350
|
path: current.path,
|
|
554572
|
-
name:
|
|
554351
|
+
name: basename32(current.path),
|
|
554573
554352
|
branch: current.branch ?? "detached",
|
|
554574
554353
|
head: current.head ?? "",
|
|
554575
554354
|
isCurrent: current.path === currentPath,
|
|
@@ -554595,7 +554374,7 @@ function parseWorktreeList(output, currentPath) {
|
|
|
554595
554374
|
if (current?.path) {
|
|
554596
554375
|
worktrees.push({
|
|
554597
554376
|
path: current.path,
|
|
554598
|
-
name:
|
|
554377
|
+
name: basename32(current.path),
|
|
554599
554378
|
branch: current.branch ?? "detached",
|
|
554600
554379
|
head: current.head ?? "",
|
|
554601
554380
|
isCurrent: current.path === currentPath,
|
|
@@ -558077,7 +557856,6 @@ function App2({
|
|
|
558077
557856
|
const userCancelledRef = import_react121.useRef(false);
|
|
558078
557857
|
const llmApiErrorRetriesRef = import_react121.useRef(0);
|
|
558079
557858
|
const quotaAutoSwapAttemptedRef = import_react121.useRef(false);
|
|
558080
|
-
const providerFallbackAttemptedRef = import_react121.useRef(false);
|
|
558081
557859
|
const emptyResponseRetriesRef = import_react121.useRef(0);
|
|
558082
557860
|
const conversationBusyRetriesRef = import_react121.useRef(0);
|
|
558083
557861
|
const [queueDisplay, setQueueDisplay] = import_react121.useState([]);
|
|
@@ -559596,7 +559374,6 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
559596
559374
|
precomputedDiffsRef,
|
|
559597
559375
|
prepareScopedToolExecutionContext,
|
|
559598
559376
|
processingConversationRef,
|
|
559599
|
-
providerFallbackAttemptedRef,
|
|
559600
559377
|
queueApprovalResults,
|
|
559601
559378
|
queueSnapshotRef,
|
|
559602
559379
|
quotaAutoSwapAttemptedRef,
|
|
@@ -560991,7 +560768,7 @@ SUBCOMMANDS
|
|
|
560991
560768
|
letta agents list [--query <text> | --name <name> | --tags <tags>]
|
|
560992
560769
|
letta environments list [--online-only]
|
|
560993
560770
|
letta environments current
|
|
560994
|
-
letta teleport list|cloud|<environment>
|
|
560771
|
+
letta teleport list|cloud|local|<environment>
|
|
560995
560772
|
letta messages search --query <text> [--all-agents]
|
|
560996
560773
|
letta messages list [--agent <id>]
|
|
560997
560774
|
letta messages transcript --conversation <id> [--out <path>]
|
|
@@ -564679,4 +564456,4 @@ function registerBunOAuthFlows() {
|
|
|
564679
564456
|
registerBunOAuthFlows();
|
|
564680
564457
|
await init_src5().then(() => exports_src2);
|
|
564681
564458
|
|
|
564682
|
-
//# debugId=
|
|
564459
|
+
//# debugId=BBC1C9C009AB28B764756E2164756E21
|