@letta-ai/letta-code 0.14.15 → 0.14.16
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/types/protocol.d.ts +48 -3
- package/dist/types/protocol.d.ts.map +1 -1
- package/letta.js +740 -210
- package/package.json +1 -1
package/letta.js
CHANGED
|
@@ -3122,7 +3122,7 @@ var package_default;
|
|
|
3122
3122
|
var init_package = __esm(() => {
|
|
3123
3123
|
package_default = {
|
|
3124
3124
|
name: "@letta-ai/letta-code",
|
|
3125
|
-
version: "0.14.
|
|
3125
|
+
version: "0.14.16",
|
|
3126
3126
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3127
3127
|
type: "module",
|
|
3128
3128
|
bin: {
|
|
@@ -38464,6 +38464,10 @@ var init_EnterPlanMode2 = __esm(() => {
|
|
|
38464
38464
|
|
|
38465
38465
|
// src/tools/impl/ExitPlanMode.ts
|
|
38466
38466
|
async function exit_plan_mode() {
|
|
38467
|
+
if (permissionMode2.getMode() === "plan") {
|
|
38468
|
+
const restoredMode = permissionMode2.getModeBeforePlan() ?? "default";
|
|
38469
|
+
permissionMode2.setMode(restoredMode);
|
|
38470
|
+
}
|
|
38467
38471
|
return {
|
|
38468
38472
|
message: `User has approved your plan. You can now start coding.
|
|
38469
38473
|
` + `Start with updating your todo list if applicable.
|
|
@@ -38471,6 +38475,9 @@ async function exit_plan_mode() {
|
|
|
38471
38475
|
` + "Tip: If this plan will be referenced in the future by your future-self, " + "other agents, or humans, consider renaming the plan file to something easily " + "identifiable with a timestamp (e.g., `2026-01-auth-refactor.md`) rather than the random name."
|
|
38472
38476
|
};
|
|
38473
38477
|
}
|
|
38478
|
+
var init_ExitPlanMode2 = __esm(() => {
|
|
38479
|
+
init_mode();
|
|
38480
|
+
});
|
|
38474
38481
|
|
|
38475
38482
|
// src/tools/impl/Glob.ts
|
|
38476
38483
|
import { execFile } from "node:child_process";
|
|
@@ -55625,7 +55632,7 @@ var init_EnterPlanMode3 = __esm(() => {
|
|
|
55625
55632
|
|
|
55626
55633
|
// src/tools/schemas/ExitPlanMode.json
|
|
55627
55634
|
var ExitPlanMode_default2;
|
|
55628
|
-
var
|
|
55635
|
+
var init_ExitPlanMode3 = __esm(() => {
|
|
55629
55636
|
ExitPlanMode_default2 = {
|
|
55630
55637
|
type: "object",
|
|
55631
55638
|
properties: {},
|
|
@@ -56576,6 +56583,7 @@ var init_toolDefinitions = __esm(async () => {
|
|
|
56576
56583
|
init_BashOutput2();
|
|
56577
56584
|
init_Edit2();
|
|
56578
56585
|
init_EnterPlanMode2();
|
|
56586
|
+
init_ExitPlanMode2();
|
|
56579
56587
|
init_Glob2();
|
|
56580
56588
|
init_GlobGemini2();
|
|
56581
56589
|
init_Grep2();
|
|
@@ -56600,7 +56608,7 @@ var init_toolDefinitions = __esm(async () => {
|
|
|
56600
56608
|
init_BashOutput3();
|
|
56601
56609
|
init_Edit3();
|
|
56602
56610
|
init_EnterPlanMode3();
|
|
56603
|
-
|
|
56611
|
+
init_ExitPlanMode3();
|
|
56604
56612
|
init_Glob3();
|
|
56605
56613
|
init_GlobGemini3();
|
|
56606
56614
|
init_Grep3();
|
|
@@ -59127,25 +59135,32 @@ var init_filter = __esm(() => {
|
|
|
59127
59135
|
var exports_manager2 = {};
|
|
59128
59136
|
__export(exports_manager2, {
|
|
59129
59137
|
waitForToolsetReady: () => waitForToolsetReady,
|
|
59138
|
+
setExternalToolExecutor: () => setExternalToolExecutor,
|
|
59130
59139
|
savePermissionRule: () => savePermissionRule2,
|
|
59131
59140
|
requiresApproval: () => requiresApproval,
|
|
59141
|
+
registerExternalTools: () => registerExternalTools,
|
|
59132
59142
|
loadTools: () => loadTools,
|
|
59133
59143
|
loadSpecificTools: () => loadSpecificTools,
|
|
59134
59144
|
isToolsetSwitchInProgress: () => isToolsetSwitchInProgress,
|
|
59135
59145
|
isOpenAIModel: () => isOpenAIModel,
|
|
59136
59146
|
isGeminiModel: () => isGeminiModel,
|
|
59147
|
+
isExternalTool: () => isExternalTool,
|
|
59137
59148
|
getToolSchemas: () => getToolSchemas,
|
|
59138
59149
|
getToolSchema: () => getToolSchema,
|
|
59139
59150
|
getToolPermissions: () => getToolPermissions,
|
|
59140
59151
|
getToolNames: () => getToolNames,
|
|
59141
59152
|
getServerToolName: () => getServerToolName,
|
|
59142
59153
|
getInternalToolName: () => getInternalToolName,
|
|
59154
|
+
getExternalToolsAsClientTools: () => getExternalToolsAsClientTools,
|
|
59155
|
+
getExternalToolDefinition: () => getExternalToolDefinition,
|
|
59143
59156
|
getClientToolsFromRegistry: () => getClientToolsFromRegistry,
|
|
59144
59157
|
getAllLettaToolNames: () => getAllLettaToolNames,
|
|
59145
59158
|
executeTool: () => executeTool,
|
|
59159
|
+
executeExternalTool: () => executeExternalTool,
|
|
59146
59160
|
clipToolReturn: () => clipToolReturn,
|
|
59147
59161
|
clearToolsWithLock: () => clearToolsWithLock,
|
|
59148
59162
|
clearTools: () => clearTools,
|
|
59163
|
+
clearExternalTools: () => clearExternalTools,
|
|
59149
59164
|
checkToolPermission: () => checkToolPermission,
|
|
59150
59165
|
analyzeToolApproval: () => analyzeToolApproval,
|
|
59151
59166
|
TOOL_NAMES: () => TOOL_NAMES,
|
|
@@ -59219,8 +59234,65 @@ function resolveInternalToolName(name) {
|
|
|
59219
59234
|
}
|
|
59220
59235
|
return;
|
|
59221
59236
|
}
|
|
59237
|
+
function getExternalToolsRegistry() {
|
|
59238
|
+
const global2 = globalThis;
|
|
59239
|
+
if (!global2[EXTERNAL_TOOLS_KEY]) {
|
|
59240
|
+
global2[EXTERNAL_TOOLS_KEY] = new Map;
|
|
59241
|
+
}
|
|
59242
|
+
return global2[EXTERNAL_TOOLS_KEY];
|
|
59243
|
+
}
|
|
59244
|
+
function registerExternalTools(tools) {
|
|
59245
|
+
const registry = getExternalToolsRegistry();
|
|
59246
|
+
for (const tool of tools) {
|
|
59247
|
+
registry.set(tool.name, tool);
|
|
59248
|
+
}
|
|
59249
|
+
}
|
|
59250
|
+
function setExternalToolExecutor(executor) {
|
|
59251
|
+
globalThis[EXTERNAL_EXECUTOR_KEY] = executor;
|
|
59252
|
+
}
|
|
59253
|
+
function clearExternalTools() {
|
|
59254
|
+
getExternalToolsRegistry().clear();
|
|
59255
|
+
delete globalThis[EXTERNAL_EXECUTOR_KEY];
|
|
59256
|
+
}
|
|
59257
|
+
function isExternalTool(name) {
|
|
59258
|
+
return getExternalToolsRegistry().has(name);
|
|
59259
|
+
}
|
|
59260
|
+
function getExternalToolDefinition(name) {
|
|
59261
|
+
return getExternalToolsRegistry().get(name);
|
|
59262
|
+
}
|
|
59263
|
+
function getExternalToolsAsClientTools() {
|
|
59264
|
+
return Array.from(getExternalToolsRegistry().values()).map((tool) => ({
|
|
59265
|
+
name: tool.name,
|
|
59266
|
+
description: tool.description,
|
|
59267
|
+
parameters: tool.parameters
|
|
59268
|
+
}));
|
|
59269
|
+
}
|
|
59270
|
+
async function executeExternalTool(toolCallId, toolName, input) {
|
|
59271
|
+
const executor = globalThis[EXTERNAL_EXECUTOR_KEY];
|
|
59272
|
+
if (!executor) {
|
|
59273
|
+
return {
|
|
59274
|
+
toolReturn: `External tool executor not set for tool: ${toolName}`,
|
|
59275
|
+
status: "error"
|
|
59276
|
+
};
|
|
59277
|
+
}
|
|
59278
|
+
try {
|
|
59279
|
+
const result = await executor(toolCallId, toolName, input);
|
|
59280
|
+
const textContent = result.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join(`
|
|
59281
|
+
`);
|
|
59282
|
+
return {
|
|
59283
|
+
toolReturn: textContent || JSON.stringify(result.content),
|
|
59284
|
+
status: result.isError ? "error" : "success"
|
|
59285
|
+
};
|
|
59286
|
+
} catch (error) {
|
|
59287
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
59288
|
+
return {
|
|
59289
|
+
toolReturn: `External tool execution error: ${errorMessage}`,
|
|
59290
|
+
status: "error"
|
|
59291
|
+
};
|
|
59292
|
+
}
|
|
59293
|
+
}
|
|
59222
59294
|
function getClientToolsFromRegistry() {
|
|
59223
|
-
|
|
59295
|
+
const builtInTools = Array.from(toolRegistry.entries()).map(([name, tool]) => {
|
|
59224
59296
|
const serverName = getServerToolName(name);
|
|
59225
59297
|
return {
|
|
59226
59298
|
name: serverName,
|
|
@@ -59228,6 +59300,8 @@ function getClientToolsFromRegistry() {
|
|
|
59228
59300
|
parameters: tool.schema.input_schema
|
|
59229
59301
|
};
|
|
59230
59302
|
});
|
|
59303
|
+
const externalTools = getExternalToolsAsClientTools();
|
|
59304
|
+
return [...builtInTools, ...externalTools];
|
|
59231
59305
|
}
|
|
59232
59306
|
function getToolPermissions(toolName) {
|
|
59233
59307
|
return TOOL_PERMISSIONS[toolName] || { requiresApproval: false };
|
|
@@ -59489,6 +59563,9 @@ ${files.join(`
|
|
|
59489
59563
|
return JSON.stringify(result);
|
|
59490
59564
|
}
|
|
59491
59565
|
async function executeTool(name, args, options) {
|
|
59566
|
+
if (isExternalTool(name)) {
|
|
59567
|
+
return executeExternalTool(options?.toolCallId ?? `ext-${Date.now()}`, name, args);
|
|
59568
|
+
}
|
|
59492
59569
|
const internalName = resolveInternalToolName(name);
|
|
59493
59570
|
if (!internalName) {
|
|
59494
59571
|
return {
|
|
@@ -59655,7 +59732,7 @@ function clearToolsWithLock() {
|
|
|
59655
59732
|
releaseSwitchLock();
|
|
59656
59733
|
}
|
|
59657
59734
|
}
|
|
59658
|
-
var TOOL_NAMES, STREAMING_SHELL_TOOLS, TOOL_NAME_MAPPINGS, ANTHROPIC_DEFAULT_TOOLS, OPENAI_DEFAULT_TOOLS, GEMINI_DEFAULT_TOOLS, OPENAI_PASCAL_TOOLS, GEMINI_PASCAL_TOOLS, TOOL_PERMISSIONS, REGISTRY_KEY, SWITCH_LOCK_KEY, toolRegistry;
|
|
59735
|
+
var TOOL_NAMES, STREAMING_SHELL_TOOLS, TOOL_NAME_MAPPINGS, ANTHROPIC_DEFAULT_TOOLS, OPENAI_DEFAULT_TOOLS, GEMINI_DEFAULT_TOOLS, OPENAI_PASCAL_TOOLS, GEMINI_PASCAL_TOOLS, TOOL_PERMISSIONS, REGISTRY_KEY, SWITCH_LOCK_KEY, toolRegistry, EXTERNAL_TOOLS_KEY, EXTERNAL_EXECUTOR_KEY;
|
|
59659
59736
|
var init_manager3 = __esm(async () => {
|
|
59660
59737
|
init_model();
|
|
59661
59738
|
init_subagents();
|
|
@@ -59817,6 +59894,8 @@ var init_manager3 = __esm(async () => {
|
|
|
59817
59894
|
REGISTRY_KEY = Symbol.for("@letta/toolRegistry");
|
|
59818
59895
|
SWITCH_LOCK_KEY = Symbol.for("@letta/toolSwitchLock");
|
|
59819
59896
|
toolRegistry = getRegistry();
|
|
59897
|
+
EXTERNAL_TOOLS_KEY = Symbol.for("@letta/externalTools");
|
|
59898
|
+
EXTERNAL_EXECUTOR_KEY = Symbol.for("@letta/externalToolExecutor");
|
|
59820
59899
|
});
|
|
59821
59900
|
|
|
59822
59901
|
// src/agent/approval-execution.ts
|
|
@@ -62112,6 +62191,23 @@ function isConversationBusyError(detail) {
|
|
|
62112
62191
|
return false;
|
|
62113
62192
|
return detail.toLowerCase().includes(CONVERSATION_BUSY_DETAIL_FRAGMENT);
|
|
62114
62193
|
}
|
|
62194
|
+
function classifyPreStreamConflict(detail) {
|
|
62195
|
+
if (isApprovalPendingError(detail))
|
|
62196
|
+
return "approval_pending";
|
|
62197
|
+
if (isConversationBusyError(detail))
|
|
62198
|
+
return "conversation_busy";
|
|
62199
|
+
return null;
|
|
62200
|
+
}
|
|
62201
|
+
function getPreStreamErrorAction(detail, conversationBusyRetries, maxConversationBusyRetries) {
|
|
62202
|
+
const kind = classifyPreStreamConflict(detail);
|
|
62203
|
+
if (kind === "approval_pending") {
|
|
62204
|
+
return "resolve_approval_pending";
|
|
62205
|
+
}
|
|
62206
|
+
if (kind === "conversation_busy" && conversationBusyRetries < maxConversationBusyRetries) {
|
|
62207
|
+
return "retry_conversation_busy";
|
|
62208
|
+
}
|
|
62209
|
+
return "rethrow";
|
|
62210
|
+
}
|
|
62115
62211
|
async function fetchRunErrorDetail(runId) {
|
|
62116
62212
|
if (!runId)
|
|
62117
62213
|
return null;
|
|
@@ -62124,7 +62220,7 @@ async function fetchRunErrorDetail(runId) {
|
|
|
62124
62220
|
return null;
|
|
62125
62221
|
}
|
|
62126
62222
|
}
|
|
62127
|
-
var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "
|
|
62223
|
+
var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "waiting for approval", CONVERSATION_BUSY_DETAIL_FRAGMENT = "another request is currently being processed";
|
|
62128
62224
|
var init_approval_recovery = __esm(async () => {
|
|
62129
62225
|
await init_client2();
|
|
62130
62226
|
});
|
|
@@ -62356,7 +62452,7 @@ function buildModelSettings(modelHandle, updateArgs) {
|
|
|
62356
62452
|
} else {
|
|
62357
62453
|
settings = {};
|
|
62358
62454
|
}
|
|
62359
|
-
if (typeof updateArgs?.max_output_tokens === "number") {
|
|
62455
|
+
if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
|
|
62360
62456
|
settings.max_output_tokens = updateArgs.max_output_tokens;
|
|
62361
62457
|
}
|
|
62362
62458
|
return settings;
|
|
@@ -62369,7 +62465,10 @@ async function updateAgentLLMConfig(agentId, modelHandle, updateArgs) {
|
|
|
62369
62465
|
await client.agents.update(agentId, {
|
|
62370
62466
|
model: modelHandle,
|
|
62371
62467
|
...hasModelSettings && { model_settings: modelSettings },
|
|
62372
|
-
...contextWindow && { context_window_limit: contextWindow }
|
|
62468
|
+
...contextWindow && { context_window_limit: contextWindow },
|
|
62469
|
+
...typeof updateArgs?.max_output_tokens === "number" && {
|
|
62470
|
+
max_tokens: updateArgs.max_output_tokens
|
|
62471
|
+
}
|
|
62373
62472
|
});
|
|
62374
62473
|
const finalAgent = await client.agents.retrieve(agentId);
|
|
62375
62474
|
return finalAgent.llm_config;
|
|
@@ -63249,6 +63348,181 @@ function findLastSafeSplitPoint(content) {
|
|
|
63249
63348
|
}
|
|
63250
63349
|
var MIN_SPLIT_LENGTH = 1500;
|
|
63251
63350
|
|
|
63351
|
+
// src/tools/interactivePolicy.ts
|
|
63352
|
+
function isInteractiveApprovalTool(toolName) {
|
|
63353
|
+
return INTERACTIVE_APPROVAL_TOOLS.has(toolName);
|
|
63354
|
+
}
|
|
63355
|
+
function isHeadlessAutoAllowTool(toolName) {
|
|
63356
|
+
return HEADLESS_AUTO_ALLOW_TOOLS.has(toolName);
|
|
63357
|
+
}
|
|
63358
|
+
var INTERACTIVE_APPROVAL_TOOLS, RUNTIME_USER_INPUT_TOOLS, HEADLESS_AUTO_ALLOW_TOOLS;
|
|
63359
|
+
var init_interactivePolicy = __esm(() => {
|
|
63360
|
+
INTERACTIVE_APPROVAL_TOOLS = new Set([
|
|
63361
|
+
"AskUserQuestion",
|
|
63362
|
+
"EnterPlanMode",
|
|
63363
|
+
"ExitPlanMode"
|
|
63364
|
+
]);
|
|
63365
|
+
RUNTIME_USER_INPUT_TOOLS = new Set(["AskUserQuestion", "ExitPlanMode"]);
|
|
63366
|
+
HEADLESS_AUTO_ALLOW_TOOLS = new Set(["EnterPlanMode"]);
|
|
63367
|
+
});
|
|
63368
|
+
|
|
63369
|
+
// src/tools/toolset.ts
|
|
63370
|
+
var exports_toolset = {};
|
|
63371
|
+
__export(exports_toolset, {
|
|
63372
|
+
switchToolsetForModel: () => switchToolsetForModel,
|
|
63373
|
+
reattachMemoryTool: () => reattachMemoryTool,
|
|
63374
|
+
forceToolsetSwitch: () => forceToolsetSwitch,
|
|
63375
|
+
ensureCorrectMemoryTool: () => ensureCorrectMemoryTool,
|
|
63376
|
+
detachMemoryTools: () => detachMemoryTools,
|
|
63377
|
+
MEMORY_TOOL_NAMES: () => MEMORY_TOOL_NAMES
|
|
63378
|
+
});
|
|
63379
|
+
async function ensureCorrectMemoryTool(agentId, modelIdentifier, useMemoryPatch) {
|
|
63380
|
+
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
63381
|
+
const client = await getClient2();
|
|
63382
|
+
const shouldUsePatch = useMemoryPatch !== undefined ? useMemoryPatch : isOpenAIModel(resolvedModel);
|
|
63383
|
+
try {
|
|
63384
|
+
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
63385
|
+
include: ["agent.tools"]
|
|
63386
|
+
});
|
|
63387
|
+
const currentTools = agentWithTools.tools || [];
|
|
63388
|
+
const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
|
|
63389
|
+
const hasAnyMemoryTool = mapByName.has("memory") || mapByName.has("memory_apply_patch");
|
|
63390
|
+
if (!hasAnyMemoryTool) {
|
|
63391
|
+
return;
|
|
63392
|
+
}
|
|
63393
|
+
const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
|
|
63394
|
+
const otherMemoryTool = desiredMemoryTool === "memory" ? "memory_apply_patch" : "memory";
|
|
63395
|
+
let desiredId = mapByName.get(desiredMemoryTool);
|
|
63396
|
+
if (!desiredId) {
|
|
63397
|
+
const resp = await client.tools.list({ name: desiredMemoryTool });
|
|
63398
|
+
desiredId = resp.items[0]?.id;
|
|
63399
|
+
}
|
|
63400
|
+
if (!desiredId) {
|
|
63401
|
+
return;
|
|
63402
|
+
}
|
|
63403
|
+
const otherId = mapByName.get(otherMemoryTool);
|
|
63404
|
+
if (mapByName.has(desiredMemoryTool) && !otherId) {
|
|
63405
|
+
return;
|
|
63406
|
+
}
|
|
63407
|
+
const currentIds = currentTools.map((t) => t.id).filter((id) => typeof id === "string");
|
|
63408
|
+
const newIds = new Set(currentIds);
|
|
63409
|
+
if (otherId)
|
|
63410
|
+
newIds.delete(otherId);
|
|
63411
|
+
newIds.add(desiredId);
|
|
63412
|
+
const updatedRules = (agentWithTools.tool_rules || []).map((r) => r.tool_name === otherMemoryTool ? { ...r, tool_name: desiredMemoryTool } : r);
|
|
63413
|
+
await client.agents.update(agentId, {
|
|
63414
|
+
tool_ids: Array.from(newIds),
|
|
63415
|
+
tool_rules: updatedRules
|
|
63416
|
+
});
|
|
63417
|
+
} catch (err) {
|
|
63418
|
+
console.warn(`Warning: Failed to sync memory tool: ${err instanceof Error ? err.message : String(err)}`);
|
|
63419
|
+
}
|
|
63420
|
+
}
|
|
63421
|
+
async function detachMemoryTools(agentId) {
|
|
63422
|
+
const client = await getClient2();
|
|
63423
|
+
try {
|
|
63424
|
+
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
63425
|
+
include: ["agent.tools"]
|
|
63426
|
+
});
|
|
63427
|
+
const currentTools = agentWithTools.tools || [];
|
|
63428
|
+
let detachedAny = false;
|
|
63429
|
+
for (const tool of currentTools) {
|
|
63430
|
+
if (tool.name && MEMORY_TOOL_NAMES.has(tool.name)) {
|
|
63431
|
+
if (tool.id) {
|
|
63432
|
+
await client.agents.tools.detach(tool.id, { agent_id: agentId });
|
|
63433
|
+
detachedAny = true;
|
|
63434
|
+
}
|
|
63435
|
+
}
|
|
63436
|
+
}
|
|
63437
|
+
return detachedAny;
|
|
63438
|
+
} catch (err) {
|
|
63439
|
+
console.warn(`Warning: Failed to detach memory tools: ${err instanceof Error ? err.message : String(err)}`);
|
|
63440
|
+
return false;
|
|
63441
|
+
}
|
|
63442
|
+
}
|
|
63443
|
+
async function reattachMemoryTool(agentId, modelIdentifier) {
|
|
63444
|
+
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
63445
|
+
const client = await getClient2();
|
|
63446
|
+
const shouldUsePatch = isOpenAIModel(resolvedModel);
|
|
63447
|
+
try {
|
|
63448
|
+
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
63449
|
+
include: ["agent.tools"]
|
|
63450
|
+
});
|
|
63451
|
+
const currentTools = agentWithTools.tools || [];
|
|
63452
|
+
const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
|
|
63453
|
+
const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
|
|
63454
|
+
if (mapByName.has(desiredMemoryTool)) {
|
|
63455
|
+
return;
|
|
63456
|
+
}
|
|
63457
|
+
const resp = await client.tools.list({ name: desiredMemoryTool });
|
|
63458
|
+
const toolId = resp.items[0]?.id;
|
|
63459
|
+
if (!toolId) {
|
|
63460
|
+
console.warn(`Memory tool "${desiredMemoryTool}" not found on server`);
|
|
63461
|
+
return;
|
|
63462
|
+
}
|
|
63463
|
+
await client.agents.tools.attach(toolId, { agent_id: agentId });
|
|
63464
|
+
} catch (err) {
|
|
63465
|
+
console.warn(`Warning: Failed to reattach memory tool: ${err instanceof Error ? err.message : String(err)}`);
|
|
63466
|
+
}
|
|
63467
|
+
}
|
|
63468
|
+
async function forceToolsetSwitch(toolsetName, agentId) {
|
|
63469
|
+
let modelForLoading;
|
|
63470
|
+
if (toolsetName === "none") {
|
|
63471
|
+
clearToolsWithLock();
|
|
63472
|
+
return;
|
|
63473
|
+
} else if (toolsetName === "codex") {
|
|
63474
|
+
await loadSpecificTools([...CODEX_TOOLS]);
|
|
63475
|
+
modelForLoading = "openai/gpt-4";
|
|
63476
|
+
} else if (toolsetName === "codex_snake") {
|
|
63477
|
+
await loadTools("openai/gpt-4");
|
|
63478
|
+
modelForLoading = "openai/gpt-4";
|
|
63479
|
+
} else if (toolsetName === "gemini") {
|
|
63480
|
+
await loadSpecificTools([...GEMINI_TOOLS]);
|
|
63481
|
+
modelForLoading = "google_ai/gemini-3-pro-preview";
|
|
63482
|
+
} else if (toolsetName === "gemini_snake") {
|
|
63483
|
+
await loadTools("google_ai/gemini-3-pro-preview");
|
|
63484
|
+
modelForLoading = "google_ai/gemini-3-pro-preview";
|
|
63485
|
+
} else {
|
|
63486
|
+
await loadTools("anthropic/claude-sonnet-4");
|
|
63487
|
+
modelForLoading = "anthropic/claude-sonnet-4";
|
|
63488
|
+
}
|
|
63489
|
+
const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake";
|
|
63490
|
+
await ensureCorrectMemoryTool(agentId, modelForLoading, useMemoryPatch);
|
|
63491
|
+
}
|
|
63492
|
+
async function switchToolsetForModel(modelIdentifier, agentId) {
|
|
63493
|
+
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
63494
|
+
await loadTools(resolvedModel);
|
|
63495
|
+
const loadedAfterPrimary = getToolNames().length;
|
|
63496
|
+
if (loadedAfterPrimary === 0 && !toolFilter.isActive()) {
|
|
63497
|
+
await loadTools();
|
|
63498
|
+
if (getToolNames().length === 0) {
|
|
63499
|
+
throw new Error(`Failed to load any Letta tools for model "${resolvedModel}".`);
|
|
63500
|
+
}
|
|
63501
|
+
}
|
|
63502
|
+
await ensureCorrectMemoryTool(agentId, resolvedModel);
|
|
63503
|
+
const { isGeminiModel: isGeminiModel3 } = await init_manager3().then(() => exports_manager2);
|
|
63504
|
+
const toolsetName = isOpenAIModel(resolvedModel) ? "codex" : isGeminiModel3(resolvedModel) ? "gemini" : "default";
|
|
63505
|
+
return toolsetName;
|
|
63506
|
+
}
|
|
63507
|
+
var CODEX_TOOLS, GEMINI_TOOLS, MEMORY_TOOL_NAMES;
|
|
63508
|
+
var init_toolset = __esm(async () => {
|
|
63509
|
+
init_model();
|
|
63510
|
+
init_filter();
|
|
63511
|
+
await __promiseAll([
|
|
63512
|
+
init_client2(),
|
|
63513
|
+
init_manager3()
|
|
63514
|
+
]);
|
|
63515
|
+
CODEX_TOOLS = OPENAI_PASCAL_TOOLS;
|
|
63516
|
+
GEMINI_TOOLS = GEMINI_PASCAL_TOOLS;
|
|
63517
|
+
MEMORY_TOOL_NAMES = new Set([
|
|
63518
|
+
"memory",
|
|
63519
|
+
"memory_apply_patch",
|
|
63520
|
+
"memory_insert",
|
|
63521
|
+
"memory_replace",
|
|
63522
|
+
"memory_rethink"
|
|
63523
|
+
]);
|
|
63524
|
+
});
|
|
63525
|
+
|
|
63252
63526
|
// src/cli/helpers/toolNameMapping.ts
|
|
63253
63527
|
function getDisplayToolName(rawName) {
|
|
63254
63528
|
if (rawName === "write")
|
|
@@ -63351,10 +63625,10 @@ function isPlanTool(rawName, displayName) {
|
|
|
63351
63625
|
return rawName === "update_plan" || rawName === "UpdatePlan" || displayName === "Planning";
|
|
63352
63626
|
}
|
|
63353
63627
|
function alwaysRequiresUserInput(name) {
|
|
63354
|
-
return name
|
|
63628
|
+
return isInteractiveApprovalTool(name);
|
|
63355
63629
|
}
|
|
63356
63630
|
function isMemoryTool(name) {
|
|
63357
|
-
return name
|
|
63631
|
+
return MEMORY_TOOL_NAMES.has(name);
|
|
63358
63632
|
}
|
|
63359
63633
|
function isFileEditTool(name) {
|
|
63360
63634
|
return name === "edit" || name === "Edit" || name === "multi_edit" || name === "MultiEdit" || name === "Replace" || name === "replace";
|
|
@@ -63378,6 +63652,10 @@ function isSearchTool(name) {
|
|
|
63378
63652
|
function isGlobTool(name) {
|
|
63379
63653
|
return name === "glob" || name === "Glob" || name === "glob_gemini" || name === "GlobGemini";
|
|
63380
63654
|
}
|
|
63655
|
+
var init_toolNameMapping = __esm(async () => {
|
|
63656
|
+
init_interactivePolicy();
|
|
63657
|
+
await init_toolset();
|
|
63658
|
+
});
|
|
63381
63659
|
|
|
63382
63660
|
// src/cli/helpers/accumulator.ts
|
|
63383
63661
|
function appendStreamingOutput(state, chunk, startTime, isStderr = false) {
|
|
@@ -63837,6 +64115,11 @@ function onChunk(b, chunk, ctx) {
|
|
|
63837
64115
|
eventData: eventChunk.event_data || {},
|
|
63838
64116
|
phase: "running"
|
|
63839
64117
|
}));
|
|
64118
|
+
if (eventType === "compaction") {
|
|
64119
|
+
runPreCompactHooks(ctx?.lastContextTokens, undefined, b.agentId, undefined).catch((error) => {
|
|
64120
|
+
debugLog("hooks", "PreCompact hook error (accumulator)", error);
|
|
64121
|
+
});
|
|
64122
|
+
}
|
|
63840
64123
|
break;
|
|
63841
64124
|
}
|
|
63842
64125
|
break;
|
|
@@ -63881,7 +64164,10 @@ var init_accumulator = __esm(async () => {
|
|
|
63881
64164
|
init_constants();
|
|
63882
64165
|
init_debug();
|
|
63883
64166
|
init_backfill();
|
|
63884
|
-
await
|
|
64167
|
+
await __promiseAll([
|
|
64168
|
+
init_hooks(),
|
|
64169
|
+
init_toolNameMapping()
|
|
64170
|
+
]);
|
|
63885
64171
|
CANCEL_REASON_TEXT = {
|
|
63886
64172
|
user_interrupt: INTERRUPTED_BY_USER,
|
|
63887
64173
|
stream_error: "Stream error",
|
|
@@ -64102,8 +64388,69 @@ function isCreditExhaustedError(e, reasons) {
|
|
|
64102
64388
|
return false;
|
|
64103
64389
|
return hasErrorReason(e, "not-enough-credits", reasons);
|
|
64104
64390
|
}
|
|
64391
|
+
function findEncryptedContentDetail(e) {
|
|
64392
|
+
if (typeof e !== "object" || e === null)
|
|
64393
|
+
return;
|
|
64394
|
+
const obj = e;
|
|
64395
|
+
if (typeof obj.detail === "string" && obj.detail.includes("invalid_encrypted_content")) {
|
|
64396
|
+
return obj.detail;
|
|
64397
|
+
}
|
|
64398
|
+
if (obj.error && typeof obj.error === "object") {
|
|
64399
|
+
const errObj = obj.error;
|
|
64400
|
+
if (errObj.error && typeof errObj.error === "object") {
|
|
64401
|
+
const inner = errObj.error;
|
|
64402
|
+
if (typeof inner.detail === "string" && inner.detail.includes("invalid_encrypted_content")) {
|
|
64403
|
+
return inner.detail;
|
|
64404
|
+
}
|
|
64405
|
+
}
|
|
64406
|
+
if (typeof errObj.detail === "string" && errObj.detail.includes("invalid_encrypted_content")) {
|
|
64407
|
+
return errObj.detail;
|
|
64408
|
+
}
|
|
64409
|
+
}
|
|
64410
|
+
return;
|
|
64411
|
+
}
|
|
64412
|
+
function checkEncryptedContentError(e) {
|
|
64413
|
+
const detail = findEncryptedContentDetail(e);
|
|
64414
|
+
if (!detail) {
|
|
64415
|
+
try {
|
|
64416
|
+
const errorStr = typeof e === "string" ? e : JSON.stringify(e);
|
|
64417
|
+
if (!errorStr.includes("invalid_encrypted_content"))
|
|
64418
|
+
return;
|
|
64419
|
+
} catch {
|
|
64420
|
+
return;
|
|
64421
|
+
}
|
|
64422
|
+
return "OpenAI error: Encrypted content could not be verified — organization mismatch." + ENCRYPTED_CONTENT_HINT;
|
|
64423
|
+
}
|
|
64424
|
+
try {
|
|
64425
|
+
const jsonStart = detail.indexOf("{");
|
|
64426
|
+
if (jsonStart >= 0) {
|
|
64427
|
+
const parsed = JSON.parse(detail.slice(jsonStart));
|
|
64428
|
+
const innerError = parsed.error || parsed;
|
|
64429
|
+
if (innerError.code === "invalid_encrypted_content") {
|
|
64430
|
+
const msg = String(innerError.message || "Encrypted content verification failed.").replaceAll('"', "\\\"");
|
|
64431
|
+
return [
|
|
64432
|
+
"OpenAI error:",
|
|
64433
|
+
" {",
|
|
64434
|
+
` type: "${innerError.type || "invalid_request_error"}",`,
|
|
64435
|
+
` code: "${innerError.code}",`,
|
|
64436
|
+
` message: "${msg}"`,
|
|
64437
|
+
" }",
|
|
64438
|
+
ENCRYPTED_CONTENT_HINT
|
|
64439
|
+
].join(`
|
|
64440
|
+
`);
|
|
64441
|
+
}
|
|
64442
|
+
}
|
|
64443
|
+
} catch {}
|
|
64444
|
+
return "OpenAI error: Encrypted content could not be verified — organization mismatch." + ENCRYPTED_CONTENT_HINT;
|
|
64445
|
+
}
|
|
64446
|
+
function isEncryptedContentError(e) {
|
|
64447
|
+
return findEncryptedContentDetail(e) !== undefined;
|
|
64448
|
+
}
|
|
64105
64449
|
function formatErrorDetails(e, agentId, conversationId) {
|
|
64106
64450
|
let runId;
|
|
64451
|
+
const encryptedContentMsg = checkEncryptedContentError(e);
|
|
64452
|
+
if (encryptedContentMsg)
|
|
64453
|
+
return encryptedContentMsg;
|
|
64107
64454
|
if (e instanceof APIError2) {
|
|
64108
64455
|
const reasons = getErrorReasons(e);
|
|
64109
64456
|
const rateLimitResetMs = getRateLimitResetMs(e);
|
|
@@ -64202,10 +64549,18 @@ function createAgentLink(runId, agentId, conversationId) {
|
|
|
64202
64549
|
const url = `https://app.letta.com/agents/${agentId}${conversationId ? `?conversation=${conversationId}` : ""}`;
|
|
64203
64550
|
return `View agent: \x1B]8;;${url}\x1B\\${agentId}\x1B]8;;\x1B\\ (run: ${runId})`;
|
|
64204
64551
|
}
|
|
64205
|
-
var LETTA_USAGE_URL = "https://app.letta.com/settings/organization/usage", LETTA_AGENTS_URL = "https://app.letta.com/projects/default-project/agents";
|
|
64552
|
+
var LETTA_USAGE_URL = "https://app.letta.com/settings/organization/usage", LETTA_AGENTS_URL = "https://app.letta.com/projects/default-project/agents", ENCRYPTED_CONTENT_HINT;
|
|
64206
64553
|
var init_errorFormatter = __esm(() => {
|
|
64207
64554
|
init_error();
|
|
64208
64555
|
init_errorContext();
|
|
64556
|
+
ENCRYPTED_CONTENT_HINT = [
|
|
64557
|
+
"",
|
|
64558
|
+
"This occurs when the conversation contains messages with encrypted",
|
|
64559
|
+
"reasoning from a different OpenAI authentication scope (e.g. switching",
|
|
64560
|
+
"between ChatGPT OAuth and an OpenAI API key).",
|
|
64561
|
+
"Use /clear to start a new conversation."
|
|
64562
|
+
].join(`
|
|
64563
|
+
`);
|
|
64209
64564
|
});
|
|
64210
64565
|
|
|
64211
64566
|
// src/cli/helpers/streamProcessor.ts
|
|
@@ -64478,155 +64833,6 @@ var init_stream = __esm(async () => {
|
|
|
64478
64833
|
]);
|
|
64479
64834
|
});
|
|
64480
64835
|
|
|
64481
|
-
// src/tools/toolset.ts
|
|
64482
|
-
var exports_toolset = {};
|
|
64483
|
-
__export(exports_toolset, {
|
|
64484
|
-
switchToolsetForModel: () => switchToolsetForModel,
|
|
64485
|
-
reattachMemoryTool: () => reattachMemoryTool,
|
|
64486
|
-
forceToolsetSwitch: () => forceToolsetSwitch,
|
|
64487
|
-
ensureCorrectMemoryTool: () => ensureCorrectMemoryTool,
|
|
64488
|
-
detachMemoryTools: () => detachMemoryTools
|
|
64489
|
-
});
|
|
64490
|
-
async function ensureCorrectMemoryTool(agentId, modelIdentifier, useMemoryPatch) {
|
|
64491
|
-
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
64492
|
-
const client = await getClient2();
|
|
64493
|
-
const shouldUsePatch = useMemoryPatch !== undefined ? useMemoryPatch : isOpenAIModel(resolvedModel);
|
|
64494
|
-
try {
|
|
64495
|
-
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
64496
|
-
include: ["agent.tools"]
|
|
64497
|
-
});
|
|
64498
|
-
const currentTools = agentWithTools.tools || [];
|
|
64499
|
-
const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
|
|
64500
|
-
const hasAnyMemoryTool = mapByName.has("memory") || mapByName.has("memory_apply_patch");
|
|
64501
|
-
if (!hasAnyMemoryTool) {
|
|
64502
|
-
return;
|
|
64503
|
-
}
|
|
64504
|
-
const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
|
|
64505
|
-
const otherMemoryTool = desiredMemoryTool === "memory" ? "memory_apply_patch" : "memory";
|
|
64506
|
-
let desiredId = mapByName.get(desiredMemoryTool);
|
|
64507
|
-
if (!desiredId) {
|
|
64508
|
-
const resp = await client.tools.list({ name: desiredMemoryTool });
|
|
64509
|
-
desiredId = resp.items[0]?.id;
|
|
64510
|
-
}
|
|
64511
|
-
if (!desiredId) {
|
|
64512
|
-
return;
|
|
64513
|
-
}
|
|
64514
|
-
const otherId = mapByName.get(otherMemoryTool);
|
|
64515
|
-
if (mapByName.has(desiredMemoryTool) && !otherId) {
|
|
64516
|
-
return;
|
|
64517
|
-
}
|
|
64518
|
-
const currentIds = currentTools.map((t) => t.id).filter((id) => typeof id === "string");
|
|
64519
|
-
const newIds = new Set(currentIds);
|
|
64520
|
-
if (otherId)
|
|
64521
|
-
newIds.delete(otherId);
|
|
64522
|
-
newIds.add(desiredId);
|
|
64523
|
-
const updatedRules = (agentWithTools.tool_rules || []).map((r) => r.tool_name === otherMemoryTool ? { ...r, tool_name: desiredMemoryTool } : r);
|
|
64524
|
-
await client.agents.update(agentId, {
|
|
64525
|
-
tool_ids: Array.from(newIds),
|
|
64526
|
-
tool_rules: updatedRules
|
|
64527
|
-
});
|
|
64528
|
-
} catch (err) {
|
|
64529
|
-
console.warn(`Warning: Failed to sync memory tool: ${err instanceof Error ? err.message : String(err)}`);
|
|
64530
|
-
}
|
|
64531
|
-
}
|
|
64532
|
-
async function detachMemoryTools(agentId) {
|
|
64533
|
-
const client = await getClient2();
|
|
64534
|
-
try {
|
|
64535
|
-
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
64536
|
-
include: ["agent.tools"]
|
|
64537
|
-
});
|
|
64538
|
-
const currentTools = agentWithTools.tools || [];
|
|
64539
|
-
let detachedAny = false;
|
|
64540
|
-
for (const tool of currentTools) {
|
|
64541
|
-
if (tool.name === "memory" || tool.name === "memory_apply_patch") {
|
|
64542
|
-
if (tool.id) {
|
|
64543
|
-
await client.agents.tools.detach(tool.id, { agent_id: agentId });
|
|
64544
|
-
detachedAny = true;
|
|
64545
|
-
}
|
|
64546
|
-
}
|
|
64547
|
-
}
|
|
64548
|
-
return detachedAny;
|
|
64549
|
-
} catch (err) {
|
|
64550
|
-
console.warn(`Warning: Failed to detach memory tools: ${err instanceof Error ? err.message : String(err)}`);
|
|
64551
|
-
return false;
|
|
64552
|
-
}
|
|
64553
|
-
}
|
|
64554
|
-
async function reattachMemoryTool(agentId, modelIdentifier) {
|
|
64555
|
-
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
64556
|
-
const client = await getClient2();
|
|
64557
|
-
const shouldUsePatch = isOpenAIModel(resolvedModel);
|
|
64558
|
-
try {
|
|
64559
|
-
const agentWithTools = await client.agents.retrieve(agentId, {
|
|
64560
|
-
include: ["agent.tools"]
|
|
64561
|
-
});
|
|
64562
|
-
const currentTools = agentWithTools.tools || [];
|
|
64563
|
-
const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
|
|
64564
|
-
const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
|
|
64565
|
-
if (mapByName.has(desiredMemoryTool)) {
|
|
64566
|
-
return;
|
|
64567
|
-
}
|
|
64568
|
-
const resp = await client.tools.list({ name: desiredMemoryTool });
|
|
64569
|
-
const toolId = resp.items[0]?.id;
|
|
64570
|
-
if (!toolId) {
|
|
64571
|
-
console.warn(`Memory tool "${desiredMemoryTool}" not found on server`);
|
|
64572
|
-
return;
|
|
64573
|
-
}
|
|
64574
|
-
await client.agents.tools.attach(toolId, { agent_id: agentId });
|
|
64575
|
-
} catch (err) {
|
|
64576
|
-
console.warn(`Warning: Failed to reattach memory tool: ${err instanceof Error ? err.message : String(err)}`);
|
|
64577
|
-
}
|
|
64578
|
-
}
|
|
64579
|
-
async function forceToolsetSwitch(toolsetName, agentId) {
|
|
64580
|
-
let modelForLoading;
|
|
64581
|
-
if (toolsetName === "none") {
|
|
64582
|
-
clearToolsWithLock();
|
|
64583
|
-
return;
|
|
64584
|
-
} else if (toolsetName === "codex") {
|
|
64585
|
-
await loadSpecificTools([...CODEX_TOOLS]);
|
|
64586
|
-
modelForLoading = "openai/gpt-4";
|
|
64587
|
-
} else if (toolsetName === "codex_snake") {
|
|
64588
|
-
await loadTools("openai/gpt-4");
|
|
64589
|
-
modelForLoading = "openai/gpt-4";
|
|
64590
|
-
} else if (toolsetName === "gemini") {
|
|
64591
|
-
await loadSpecificTools([...GEMINI_TOOLS]);
|
|
64592
|
-
modelForLoading = "google_ai/gemini-3-pro-preview";
|
|
64593
|
-
} else if (toolsetName === "gemini_snake") {
|
|
64594
|
-
await loadTools("google_ai/gemini-3-pro-preview");
|
|
64595
|
-
modelForLoading = "google_ai/gemini-3-pro-preview";
|
|
64596
|
-
} else {
|
|
64597
|
-
await loadTools("anthropic/claude-sonnet-4");
|
|
64598
|
-
modelForLoading = "anthropic/claude-sonnet-4";
|
|
64599
|
-
}
|
|
64600
|
-
const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake";
|
|
64601
|
-
await ensureCorrectMemoryTool(agentId, modelForLoading, useMemoryPatch);
|
|
64602
|
-
}
|
|
64603
|
-
async function switchToolsetForModel(modelIdentifier, agentId) {
|
|
64604
|
-
const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
|
|
64605
|
-
await loadTools(resolvedModel);
|
|
64606
|
-
const loadedAfterPrimary = getToolNames().length;
|
|
64607
|
-
if (loadedAfterPrimary === 0 && !toolFilter.isActive()) {
|
|
64608
|
-
await loadTools();
|
|
64609
|
-
if (getToolNames().length === 0) {
|
|
64610
|
-
throw new Error(`Failed to load any Letta tools for model "${resolvedModel}".`);
|
|
64611
|
-
}
|
|
64612
|
-
}
|
|
64613
|
-
await ensureCorrectMemoryTool(agentId, resolvedModel);
|
|
64614
|
-
const { isGeminiModel: isGeminiModel3 } = await init_manager3().then(() => exports_manager2);
|
|
64615
|
-
const toolsetName = isOpenAIModel(resolvedModel) ? "codex" : isGeminiModel3(resolvedModel) ? "gemini" : "default";
|
|
64616
|
-
return toolsetName;
|
|
64617
|
-
}
|
|
64618
|
-
var CODEX_TOOLS, GEMINI_TOOLS;
|
|
64619
|
-
var init_toolset = __esm(async () => {
|
|
64620
|
-
init_model();
|
|
64621
|
-
init_filter();
|
|
64622
|
-
await __promiseAll([
|
|
64623
|
-
init_client2(),
|
|
64624
|
-
init_manager3()
|
|
64625
|
-
]);
|
|
64626
|
-
CODEX_TOOLS = OPENAI_PASCAL_TOOLS;
|
|
64627
|
-
GEMINI_TOOLS = GEMINI_PASCAL_TOOLS;
|
|
64628
|
-
});
|
|
64629
|
-
|
|
64630
64836
|
// src/agent/github-utils.ts
|
|
64631
64837
|
var exports_github_utils = {};
|
|
64632
64838
|
__export(exports_github_utils, {
|
|
@@ -64662,6 +64868,7 @@ function parseDirNames(entries) {
|
|
|
64662
64868
|
// src/agent/import.ts
|
|
64663
64869
|
var exports_import = {};
|
|
64664
64870
|
__export(exports_import, {
|
|
64871
|
+
importAgentFromRegistry: () => importAgentFromRegistry,
|
|
64665
64872
|
importAgentFromFile: () => importAgentFromFile,
|
|
64666
64873
|
extractSkillsFromAf: () => extractSkillsFromAf
|
|
64667
64874
|
});
|
|
@@ -64769,6 +64976,45 @@ async function downloadGitHubDirectory(entries, destDir, owner, repo, branch, ba
|
|
|
64769
64976
|
}
|
|
64770
64977
|
}
|
|
64771
64978
|
}
|
|
64979
|
+
function parseRegistryHandle(handle) {
|
|
64980
|
+
const normalized = handle.startsWith("@") ? handle.slice(1) : handle;
|
|
64981
|
+
const parts = normalized.split("/");
|
|
64982
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
64983
|
+
throw new Error(`Invalid import handle "${handle}". Use format: @author/agentname`);
|
|
64984
|
+
}
|
|
64985
|
+
return { author: parts[0], name: parts[1] };
|
|
64986
|
+
}
|
|
64987
|
+
async function importAgentFromRegistry(options) {
|
|
64988
|
+
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
64989
|
+
const { join: join20 } = await import("node:path");
|
|
64990
|
+
const { writeFile: writeFile5, unlink: unlink2 } = await import("node:fs/promises");
|
|
64991
|
+
const { author, name } = parseRegistryHandle(options.handle);
|
|
64992
|
+
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
|
|
64993
|
+
const response = await fetch(rawUrl);
|
|
64994
|
+
if (!response.ok) {
|
|
64995
|
+
if (response.status === 404) {
|
|
64996
|
+
throw new Error(`Agent @${author}/${name} not found in registry. Check that the agent exists at https://github.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/tree/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}`);
|
|
64997
|
+
}
|
|
64998
|
+
throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
|
|
64999
|
+
}
|
|
65000
|
+
const afContent = await response.text();
|
|
65001
|
+
const tempPath = join20(tmpdir2(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
65002
|
+
await writeFile5(tempPath, afContent, "utf-8");
|
|
65003
|
+
try {
|
|
65004
|
+
const result = await importAgentFromFile({
|
|
65005
|
+
filePath: tempPath,
|
|
65006
|
+
modelOverride: options.modelOverride,
|
|
65007
|
+
stripMessages: options.stripMessages ?? true,
|
|
65008
|
+
stripSkills: options.stripSkills ?? false
|
|
65009
|
+
});
|
|
65010
|
+
return result;
|
|
65011
|
+
} finally {
|
|
65012
|
+
try {
|
|
65013
|
+
await unlink2(tempPath);
|
|
65014
|
+
} catch {}
|
|
65015
|
+
}
|
|
65016
|
+
}
|
|
65017
|
+
var AGENT_REGISTRY_OWNER = "letta-ai", AGENT_REGISTRY_REPO = "agent-file", AGENT_REGISTRY_BRANCH = "main";
|
|
64772
65018
|
var init_import = __esm(async () => {
|
|
64773
65019
|
init_model();
|
|
64774
65020
|
await __promiseAll([
|
|
@@ -65220,6 +65466,7 @@ In headless mode, use:
|
|
|
65220
65466
|
process.exit(1);
|
|
65221
65467
|
}
|
|
65222
65468
|
}
|
|
65469
|
+
let isRegistryImport = false;
|
|
65223
65470
|
if (fromAfFile) {
|
|
65224
65471
|
if (specifiedAgentId) {
|
|
65225
65472
|
console.error("Error: --from-af cannot be used with --agent");
|
|
@@ -65233,6 +65480,15 @@ In headless mode, use:
|
|
|
65233
65480
|
console.error("Error: --from-af cannot be used with --new");
|
|
65234
65481
|
process.exit(1);
|
|
65235
65482
|
}
|
|
65483
|
+
if (fromAfFile.startsWith("@")) {
|
|
65484
|
+
isRegistryImport = true;
|
|
65485
|
+
const normalized = fromAfFile.slice(1);
|
|
65486
|
+
const parts = normalized.split("/");
|
|
65487
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
65488
|
+
console.error(`Error: Invalid registry handle "${fromAfFile}". Use format: @author/agentname`);
|
|
65489
|
+
process.exit(1);
|
|
65490
|
+
}
|
|
65491
|
+
}
|
|
65236
65492
|
}
|
|
65237
65493
|
if (initBlocksRaw && !forceNew) {
|
|
65238
65494
|
console.error("Error: --init-blocks can only be used together with --new to control initial memory blocks.");
|
|
@@ -65315,13 +65571,24 @@ In headless mode, use:
|
|
|
65315
65571
|
}
|
|
65316
65572
|
}
|
|
65317
65573
|
if (!agent && fromAfFile) {
|
|
65318
|
-
|
|
65319
|
-
|
|
65320
|
-
|
|
65321
|
-
|
|
65322
|
-
|
|
65323
|
-
|
|
65324
|
-
|
|
65574
|
+
let result;
|
|
65575
|
+
if (isRegistryImport) {
|
|
65576
|
+
const { importAgentFromRegistry: importAgentFromRegistry2 } = await init_import().then(() => exports_import);
|
|
65577
|
+
result = await importAgentFromRegistry2({
|
|
65578
|
+
handle: fromAfFile,
|
|
65579
|
+
modelOverride: model,
|
|
65580
|
+
stripMessages: true,
|
|
65581
|
+
stripSkills: false
|
|
65582
|
+
});
|
|
65583
|
+
} else {
|
|
65584
|
+
const { importAgentFromFile: importAgentFromFile2 } = await init_import().then(() => exports_import);
|
|
65585
|
+
result = await importAgentFromFile2({
|
|
65586
|
+
filePath: fromAfFile,
|
|
65587
|
+
modelOverride: model,
|
|
65588
|
+
stripMessages: true,
|
|
65589
|
+
stripSkills: false
|
|
65590
|
+
});
|
|
65591
|
+
}
|
|
65325
65592
|
agent = result.agent;
|
|
65326
65593
|
isNewlyCreatedAgent = true;
|
|
65327
65594
|
if (result.skills && result.skills.length > 0) {
|
|
@@ -65524,8 +65791,11 @@ In headless mode, use:
|
|
|
65524
65791
|
console.error(`Error: Invalid input format "${inputFormat}". Valid formats: stream-json`);
|
|
65525
65792
|
process.exit(1);
|
|
65526
65793
|
}
|
|
65794
|
+
const { getClientToolsFromRegistry: getClientToolsFromRegistry2 } = await init_manager3().then(() => exports_manager2);
|
|
65795
|
+
const loadedToolNames = getClientToolsFromRegistry2().map((t) => t.name);
|
|
65796
|
+
const availableTools = loadedToolNames.length > 0 ? loadedToolNames : agent.tools?.map((t) => t.name).filter((n) => !!n) || [];
|
|
65527
65797
|
if (isBidirectionalMode) {
|
|
65528
|
-
await runBidirectionalMode(agent, conversationId, client, outputFormat, includePartialMessages);
|
|
65798
|
+
await runBidirectionalMode(agent, conversationId, client, outputFormat, includePartialMessages, availableTools);
|
|
65529
65799
|
return;
|
|
65530
65800
|
}
|
|
65531
65801
|
const buffers = createBuffers(agent.id);
|
|
@@ -65539,7 +65809,7 @@ In headless mode, use:
|
|
|
65539
65809
|
agent_id: agent.id,
|
|
65540
65810
|
conversation_id: conversationId,
|
|
65541
65811
|
model: agent.llm_config?.model ?? "",
|
|
65542
|
-
tools:
|
|
65812
|
+
tools: availableTools,
|
|
65543
65813
|
cwd: process.cwd(),
|
|
65544
65814
|
mcp_servers: [],
|
|
65545
65815
|
permission_mode: "",
|
|
@@ -65565,6 +65835,7 @@ In headless mode, use:
|
|
|
65565
65835
|
if (pendingApprovals.length === 0)
|
|
65566
65836
|
break;
|
|
65567
65837
|
const { autoAllowed, autoDenied } = await classifyApprovals(pendingApprovals, {
|
|
65838
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
65568
65839
|
treatAskAsDeny: true,
|
|
65569
65840
|
denyReasonForAsk: "Tool requires approval (headless mode)",
|
|
65570
65841
|
requireArgsForAutoApprove: true,
|
|
@@ -65744,7 +66015,24 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
65744
66015
|
if (!errorDetail && preStreamError instanceof Error) {
|
|
65745
66016
|
errorDetail = preStreamError.message;
|
|
65746
66017
|
}
|
|
65747
|
-
|
|
66018
|
+
const preStreamAction = getPreStreamErrorAction(errorDetail, conversationBusyRetries, CONVERSATION_BUSY_MAX_RETRIES);
|
|
66019
|
+
if (preStreamAction === "resolve_approval_pending") {
|
|
66020
|
+
if (outputFormat === "stream-json") {
|
|
66021
|
+
const recoveryMsg = {
|
|
66022
|
+
type: "recovery",
|
|
66023
|
+
recovery_type: "approval_pending",
|
|
66024
|
+
message: "Detected pending approval conflict on send; resolving before retry",
|
|
66025
|
+
session_id: sessionId,
|
|
66026
|
+
uuid: `recovery-pre-stream-${crypto.randomUUID()}`
|
|
66027
|
+
};
|
|
66028
|
+
console.log(JSON.stringify(recoveryMsg));
|
|
66029
|
+
} else {
|
|
66030
|
+
console.error("Pending approval detected, resolving before retry...");
|
|
66031
|
+
}
|
|
66032
|
+
await resolveAllPendingApprovals();
|
|
66033
|
+
continue;
|
|
66034
|
+
}
|
|
66035
|
+
if (preStreamAction === "retry_conversation_busy") {
|
|
65748
66036
|
conversationBusyRetries += 1;
|
|
65749
66037
|
if (outputFormat === "stream-json") {
|
|
65750
66038
|
const retryMsg = {
|
|
@@ -65817,6 +66105,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
65817
66105
|
}
|
|
65818
66106
|
if (updatedApproval && !autoApprovalEmitted.has(updatedApproval.toolCallId)) {
|
|
65819
66107
|
const { autoAllowed } = await classifyApprovals([updatedApproval], {
|
|
66108
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
65820
66109
|
requireArgsForAutoApprove: true,
|
|
65821
66110
|
missingNameReason: "Tool call incomplete - missing name"
|
|
65822
66111
|
});
|
|
@@ -65895,9 +66184,8 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
65895
66184
|
console.error("Unexpected empty approvals array");
|
|
65896
66185
|
process.exit(1);
|
|
65897
66186
|
}
|
|
65898
|
-
const { autoAllowed, autoDenied } = await classifyApprovals(approvals, {
|
|
65899
|
-
|
|
65900
|
-
denyReasonForAsk: "Tool requires approval (headless mode)",
|
|
66187
|
+
const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovals(approvals, {
|
|
66188
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
65901
66189
|
requireArgsForAutoApprove: true,
|
|
65902
66190
|
missingNameReason: "Tool call incomplete - missing name"
|
|
65903
66191
|
});
|
|
@@ -65906,6 +66194,19 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
65906
66194
|
type: "approve",
|
|
65907
66195
|
approval: ac.approval
|
|
65908
66196
|
})),
|
|
66197
|
+
...needsUserInput.map((ac) => {
|
|
66198
|
+
if (isHeadlessAutoAllowTool(ac.approval.toolName)) {
|
|
66199
|
+
return {
|
|
66200
|
+
type: "approve",
|
|
66201
|
+
approval: ac.approval
|
|
66202
|
+
};
|
|
66203
|
+
}
|
|
66204
|
+
return {
|
|
66205
|
+
type: "deny",
|
|
66206
|
+
approval: ac.approval,
|
|
66207
|
+
reason: "Tool requires approval (headless mode)"
|
|
66208
|
+
};
|
|
66209
|
+
}),
|
|
65909
66210
|
...autoDenied.map((ac) => {
|
|
65910
66211
|
const fallback = "matchedRule" in ac.permission && ac.permission.matchedRule ? `Permission denied: ${ac.permission.matchedRule}` : ac.permission.reason ? `Permission denied: ${ac.permission.reason}` : "Permission denied: Unknown reason";
|
|
65911
66212
|
return {
|
|
@@ -66168,7 +66469,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|
|
66168
66469
|
markMilestone("HEADLESS_COMPLETE");
|
|
66169
66470
|
reportAllMilestones();
|
|
66170
66471
|
}
|
|
66171
|
-
async function runBidirectionalMode(agent, conversationId,
|
|
66472
|
+
async function runBidirectionalMode(agent, conversationId, client, _outputFormat, includePartialMessages, availableTools) {
|
|
66172
66473
|
const sessionId = agent.id;
|
|
66173
66474
|
const readline = await import("node:readline");
|
|
66174
66475
|
const initEvent = {
|
|
@@ -66178,12 +66479,74 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
|
|
|
66178
66479
|
agent_id: agent.id,
|
|
66179
66480
|
conversation_id: conversationId,
|
|
66180
66481
|
model: agent.llm_config?.model,
|
|
66181
|
-
tools:
|
|
66482
|
+
tools: availableTools,
|
|
66182
66483
|
cwd: process.cwd(),
|
|
66183
66484
|
uuid: `init-${agent.id}`
|
|
66184
66485
|
};
|
|
66185
66486
|
console.log(JSON.stringify(initEvent));
|
|
66186
66487
|
let currentAbortController = null;
|
|
66488
|
+
const resolveAllPendingApprovals = async () => {
|
|
66489
|
+
const { getResumeData: getResumeData3 } = await Promise.resolve().then(() => (init_check_approval(), exports_check_approval));
|
|
66490
|
+
while (true) {
|
|
66491
|
+
const freshAgent = await client.agents.retrieve(agent.id);
|
|
66492
|
+
let resume;
|
|
66493
|
+
try {
|
|
66494
|
+
resume = await getResumeData3(client, freshAgent, conversationId);
|
|
66495
|
+
} catch (error) {
|
|
66496
|
+
if (error instanceof APIError2 && (error.status === 404 || error.status === 422)) {
|
|
66497
|
+
break;
|
|
66498
|
+
}
|
|
66499
|
+
throw error;
|
|
66500
|
+
}
|
|
66501
|
+
const pendingApprovals = resume.pendingApprovals || [];
|
|
66502
|
+
if (pendingApprovals.length === 0)
|
|
66503
|
+
break;
|
|
66504
|
+
const { autoAllowed, autoDenied } = await classifyApprovals(pendingApprovals, {
|
|
66505
|
+
treatAskAsDeny: true,
|
|
66506
|
+
denyReasonForAsk: "Tool requires approval (headless mode)",
|
|
66507
|
+
requireArgsForAutoApprove: true,
|
|
66508
|
+
missingNameReason: "Tool call incomplete - missing name"
|
|
66509
|
+
});
|
|
66510
|
+
const decisions = [
|
|
66511
|
+
...autoAllowed.map((ac) => ({
|
|
66512
|
+
type: "approve",
|
|
66513
|
+
approval: ac.approval,
|
|
66514
|
+
reason: ac.permission.reason || "Allowed by permission rule",
|
|
66515
|
+
matchedRule: "matchedRule" in ac.permission && ac.permission.matchedRule ? ac.permission.matchedRule : "auto-approved"
|
|
66516
|
+
})),
|
|
66517
|
+
...autoDenied.map((ac) => {
|
|
66518
|
+
const fallback = "matchedRule" in ac.permission && ac.permission.matchedRule ? `Permission denied: ${ac.permission.matchedRule}` : ac.permission.reason ? `Permission denied: ${ac.permission.reason}` : "Permission denied: Unknown reason";
|
|
66519
|
+
return {
|
|
66520
|
+
type: "deny",
|
|
66521
|
+
approval: ac.approval,
|
|
66522
|
+
reason: ac.denyReason ?? fallback
|
|
66523
|
+
};
|
|
66524
|
+
})
|
|
66525
|
+
];
|
|
66526
|
+
const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
|
|
66527
|
+
const executedResults = await executeApprovalBatch2(decisions);
|
|
66528
|
+
const approvalInput = {
|
|
66529
|
+
type: "approval",
|
|
66530
|
+
approvals: executedResults
|
|
66531
|
+
};
|
|
66532
|
+
const approvalMessages = [approvalInput];
|
|
66533
|
+
{
|
|
66534
|
+
const { consumeQueuedSkillContent: consumeQueuedSkillContent2 } = await Promise.resolve().then(() => (init_skillContentRegistry(), exports_skillContentRegistry));
|
|
66535
|
+
const skillContents = consumeQueuedSkillContent2();
|
|
66536
|
+
if (skillContents.length > 0) {
|
|
66537
|
+
approvalMessages.push({
|
|
66538
|
+
role: "user",
|
|
66539
|
+
content: skillContents.map((sc) => ({
|
|
66540
|
+
type: "text",
|
|
66541
|
+
text: sc.content
|
|
66542
|
+
}))
|
|
66543
|
+
});
|
|
66544
|
+
}
|
|
66545
|
+
}
|
|
66546
|
+
const approvalStream = await sendMessageStream(conversationId, approvalMessages, { agentId: agent.id });
|
|
66547
|
+
await drainStreamWithResume(approvalStream, createBuffers(agent.id), () => {});
|
|
66548
|
+
}
|
|
66549
|
+
};
|
|
66187
66550
|
const rl = readline.createInterface({
|
|
66188
66551
|
input: process.stdin,
|
|
66189
66552
|
terminal: false
|
|
@@ -66303,7 +66666,7 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
|
|
|
66303
66666
|
response: {
|
|
66304
66667
|
agent_id: agent.id,
|
|
66305
66668
|
model: agent.llm_config?.model,
|
|
66306
|
-
tools:
|
|
66669
|
+
tools: availableTools
|
|
66307
66670
|
}
|
|
66308
66671
|
},
|
|
66309
66672
|
session_id: sessionId,
|
|
@@ -66325,6 +66688,54 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
|
|
|
66325
66688
|
uuid: crypto.randomUUID()
|
|
66326
66689
|
};
|
|
66327
66690
|
console.log(JSON.stringify(interruptResponse));
|
|
66691
|
+
} else if (subtype === "register_external_tools") {
|
|
66692
|
+
const toolsRequest = message.request;
|
|
66693
|
+
const tools = toolsRequest.tools ?? [];
|
|
66694
|
+
registerExternalTools(tools);
|
|
66695
|
+
setExternalToolExecutor(async (toolCallId, toolName, input) => {
|
|
66696
|
+
const execRequest = {
|
|
66697
|
+
type: "control_request",
|
|
66698
|
+
request_id: `ext-${toolCallId}`,
|
|
66699
|
+
request: {
|
|
66700
|
+
subtype: "execute_external_tool",
|
|
66701
|
+
tool_call_id: toolCallId,
|
|
66702
|
+
tool_name: toolName,
|
|
66703
|
+
input
|
|
66704
|
+
}
|
|
66705
|
+
};
|
|
66706
|
+
console.log(JSON.stringify(execRequest));
|
|
66707
|
+
while (true) {
|
|
66708
|
+
const line2 = await getNextLine();
|
|
66709
|
+
if (line2 === null) {
|
|
66710
|
+
return {
|
|
66711
|
+
content: [{ type: "text", text: "stdin closed" }],
|
|
66712
|
+
isError: true
|
|
66713
|
+
};
|
|
66714
|
+
}
|
|
66715
|
+
if (!line2.trim())
|
|
66716
|
+
continue;
|
|
66717
|
+
try {
|
|
66718
|
+
const msg = JSON.parse(line2);
|
|
66719
|
+
if (msg.type === "control_response" && msg.response?.subtype === "external_tool_result" && msg.response?.tool_call_id === toolCallId) {
|
|
66720
|
+
return {
|
|
66721
|
+
content: msg.response.content ?? [{ type: "text", text: "" }],
|
|
66722
|
+
isError: msg.response.is_error ?? false
|
|
66723
|
+
};
|
|
66724
|
+
}
|
|
66725
|
+
} catch {}
|
|
66726
|
+
}
|
|
66727
|
+
});
|
|
66728
|
+
const registerResponse = {
|
|
66729
|
+
type: "control_response",
|
|
66730
|
+
response: {
|
|
66731
|
+
subtype: "success",
|
|
66732
|
+
request_id: requestId ?? "",
|
|
66733
|
+
response: { registered: tools.length }
|
|
66734
|
+
},
|
|
66735
|
+
session_id: sessionId,
|
|
66736
|
+
uuid: crypto.randomUUID()
|
|
66737
|
+
};
|
|
66738
|
+
console.log(JSON.stringify(registerResponse));
|
|
66328
66739
|
} else {
|
|
66329
66740
|
const errorResponse = {
|
|
66330
66741
|
type: "control_response",
|
|
@@ -66393,9 +66804,40 @@ ${enrichedContent}`;
|
|
|
66393
66804
|
];
|
|
66394
66805
|
}
|
|
66395
66806
|
}
|
|
66396
|
-
|
|
66397
|
-
|
|
66398
|
-
|
|
66807
|
+
let stream2;
|
|
66808
|
+
try {
|
|
66809
|
+
stream2 = await sendMessageStream(conversationId, currentInput, {
|
|
66810
|
+
agentId: agent.id
|
|
66811
|
+
});
|
|
66812
|
+
} catch (preStreamError) {
|
|
66813
|
+
let errorDetail = "";
|
|
66814
|
+
if (preStreamError instanceof APIError2 && preStreamError.error && typeof preStreamError.error === "object") {
|
|
66815
|
+
const errObj = preStreamError.error;
|
|
66816
|
+
if (errObj.error && typeof errObj.error === "object" && "detail" in errObj.error) {
|
|
66817
|
+
const nested = errObj.error;
|
|
66818
|
+
errorDetail = typeof nested.detail === "string" ? nested.detail : "";
|
|
66819
|
+
}
|
|
66820
|
+
if (!errorDetail && typeof errObj.detail === "string") {
|
|
66821
|
+
errorDetail = errObj.detail;
|
|
66822
|
+
}
|
|
66823
|
+
}
|
|
66824
|
+
if (!errorDetail && preStreamError instanceof Error) {
|
|
66825
|
+
errorDetail = preStreamError.message;
|
|
66826
|
+
}
|
|
66827
|
+
if (isApprovalPendingError(errorDetail)) {
|
|
66828
|
+
const recoveryMsg = {
|
|
66829
|
+
type: "recovery",
|
|
66830
|
+
recovery_type: "approval_pending",
|
|
66831
|
+
message: "Detected pending approval conflict on send; resolving before retry",
|
|
66832
|
+
session_id: sessionId,
|
|
66833
|
+
uuid: `recovery-bidir-${crypto.randomUUID()}`
|
|
66834
|
+
};
|
|
66835
|
+
console.log(JSON.stringify(recoveryMsg));
|
|
66836
|
+
await resolveAllPendingApprovals();
|
|
66837
|
+
continue;
|
|
66838
|
+
}
|
|
66839
|
+
throw preStreamError;
|
|
66840
|
+
}
|
|
66399
66841
|
const streamJsonHook = ({
|
|
66400
66842
|
chunk,
|
|
66401
66843
|
shouldOutput,
|
|
@@ -66463,6 +66905,7 @@ ${enrichedContent}`;
|
|
|
66463
66905
|
break;
|
|
66464
66906
|
}
|
|
66465
66907
|
const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovals(approvals, {
|
|
66908
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
66466
66909
|
requireArgsForAutoApprove: true,
|
|
66467
66910
|
missingNameReason: "Tool call incomplete - missing name"
|
|
66468
66911
|
});
|
|
@@ -66620,6 +67063,7 @@ var init_headless = __esm(async () => {
|
|
|
66620
67063
|
init_model();
|
|
66621
67064
|
init_errorFormatter();
|
|
66622
67065
|
init_constants();
|
|
67066
|
+
init_interactivePolicy();
|
|
66623
67067
|
init_timing();
|
|
66624
67068
|
await __promiseAll([
|
|
66625
67069
|
init_approval_recovery(),
|
|
@@ -66630,7 +67074,8 @@ var init_headless = __esm(async () => {
|
|
|
66630
67074
|
init_accumulator(),
|
|
66631
67075
|
init_approvalClassification(),
|
|
66632
67076
|
init_stream(),
|
|
66633
|
-
init_settings_manager()
|
|
67077
|
+
init_settings_manager(),
|
|
67078
|
+
init_manager3()
|
|
66634
67079
|
]);
|
|
66635
67080
|
});
|
|
66636
67081
|
|
|
@@ -68532,7 +68977,9 @@ function formatArgsDisplay(argsJson, toolName) {
|
|
|
68532
68977
|
return { display, parsed };
|
|
68533
68978
|
}
|
|
68534
68979
|
var isRecord3 = (v) => typeof v === "object" && v !== null;
|
|
68535
|
-
var init_formatArgsDisplay = () => {
|
|
68980
|
+
var init_formatArgsDisplay = __esm(async () => {
|
|
68981
|
+
await init_toolNameMapping();
|
|
68982
|
+
});
|
|
68536
68983
|
|
|
68537
68984
|
// node_modules/diff/libesm/diff/base.js
|
|
68538
68985
|
class Diff {
|
|
@@ -70410,11 +70857,11 @@ function getFileEditHeader(toolName, toolArgs) {
|
|
|
70410
70857
|
}
|
|
70411
70858
|
var import_react33, jsx_dev_runtime14, SOLID_LINE5 = "─", DOTTED_LINE2 = "╌", ApprovalPreview;
|
|
70412
70859
|
var init_ApprovalPreview = __esm(async () => {
|
|
70413
|
-
init_formatArgsDisplay();
|
|
70414
70860
|
init_useTerminalWidth();
|
|
70415
70861
|
init_colors();
|
|
70416
70862
|
await __promiseAll([
|
|
70417
70863
|
init_build2(),
|
|
70864
|
+
init_formatArgsDisplay(),
|
|
70418
70865
|
init_AdvancedDiffRenderer(),
|
|
70419
70866
|
init_BashPreview(),
|
|
70420
70867
|
init_PlanPreview(),
|
|
@@ -71123,13 +71570,13 @@ function getDiffKind(toolName) {
|
|
|
71123
71570
|
var import_react38, jsx_dev_runtime17, SOLID_LINE8 = "─", DOTTED_LINE3 = "╌", InlineFileEditApproval;
|
|
71124
71571
|
var init_InlineFileEditApproval = __esm(async () => {
|
|
71125
71572
|
init_diff2();
|
|
71126
|
-
init_formatArgsDisplay();
|
|
71127
71573
|
init_useProgressIndicator();
|
|
71128
71574
|
init_useTerminalWidth();
|
|
71129
71575
|
init_useTextInputCursor();
|
|
71130
71576
|
init_colors();
|
|
71131
71577
|
await __promiseAll([
|
|
71132
71578
|
init_build2(),
|
|
71579
|
+
init_formatArgsDisplay(),
|
|
71133
71580
|
init_AdvancedDiffRenderer(),
|
|
71134
71581
|
init_Text2()
|
|
71135
71582
|
]);
|
|
@@ -72704,6 +73151,7 @@ function getQuestions(approval) {
|
|
|
72704
73151
|
var import_react43, jsx_dev_runtime22, ApprovalSwitch;
|
|
72705
73152
|
var init_ApprovalSwitch = __esm(async () => {
|
|
72706
73153
|
await __promiseAll([
|
|
73154
|
+
init_toolNameMapping(),
|
|
72707
73155
|
init_InlineBashApproval(),
|
|
72708
73156
|
init_InlineEnterPlanModeApproval(),
|
|
72709
73157
|
init_InlineFileEditApproval(),
|
|
@@ -80690,9 +81138,15 @@ function SlashCommandAutocomplete({
|
|
|
80690
81138
|
manageActiveState: false
|
|
80691
81139
|
});
|
|
80692
81140
|
import_react64.useLayoutEffect(() => {
|
|
80693
|
-
const
|
|
81141
|
+
const queryLength = queryInfo?.query.length ?? 0;
|
|
81142
|
+
const isActive = !hideAutocomplete && (matches.length > 0 || queryLength > 0);
|
|
80694
81143
|
onActiveChange?.(isActive);
|
|
80695
|
-
}, [
|
|
81144
|
+
}, [
|
|
81145
|
+
hideAutocomplete,
|
|
81146
|
+
matches.length,
|
|
81147
|
+
onActiveChange,
|
|
81148
|
+
queryInfo?.query.length
|
|
81149
|
+
]);
|
|
80696
81150
|
if (!currentInput.startsWith("/")) {
|
|
80697
81151
|
return null;
|
|
80698
81152
|
}
|
|
@@ -88777,13 +89231,14 @@ function isShellTool2(name) {
|
|
|
88777
89231
|
var import_react85, jsx_dev_runtime65, ToolCallMessage;
|
|
88778
89232
|
var init_ToolCallMessageRich = __esm(async () => {
|
|
88779
89233
|
init_constants();
|
|
88780
|
-
init_formatArgsDisplay();
|
|
88781
89234
|
init_subagentState();
|
|
88782
89235
|
init_useTerminalWidth();
|
|
88783
89236
|
init_colors();
|
|
88784
89237
|
await __promiseAll([
|
|
88785
89238
|
init_build2(),
|
|
88786
89239
|
init_manager3(),
|
|
89240
|
+
init_formatArgsDisplay(),
|
|
89241
|
+
init_toolNameMapping(),
|
|
88787
89242
|
init_Text2(),
|
|
88788
89243
|
init_AdvancedDiffRenderer(),
|
|
88789
89244
|
init_BlinkDot(),
|
|
@@ -90612,8 +91067,9 @@ function createSubagentGroupItem(taskToolCalls) {
|
|
|
90612
91067
|
agents
|
|
90613
91068
|
};
|
|
90614
91069
|
}
|
|
90615
|
-
var init_subagentAggregation = __esm(() => {
|
|
91070
|
+
var init_subagentAggregation = __esm(async () => {
|
|
90616
91071
|
init_subagentState();
|
|
91072
|
+
await init_toolNameMapping();
|
|
90617
91073
|
});
|
|
90618
91074
|
|
|
90619
91075
|
// src/cli/helpers/subagentTurnStart.ts
|
|
@@ -93322,7 +93778,7 @@ function App2({
|
|
|
93322
93778
|
continue;
|
|
93323
93779
|
if (!line.toolCallId || !line.name)
|
|
93324
93780
|
continue;
|
|
93325
|
-
if (line.name
|
|
93781
|
+
if (!isMemoryTool(line.name))
|
|
93326
93782
|
continue;
|
|
93327
93783
|
if (memorySyncProcessedToolCallsRef.current.has(line.toolCallId))
|
|
93328
93784
|
continue;
|
|
@@ -94393,7 +94849,9 @@ ${feedback}
|
|
|
94393
94849
|
};
|
|
94394
94850
|
const errorDetails = formatErrorDetails(errorObject, agentIdRef.current);
|
|
94395
94851
|
appendError(errorDetails, true);
|
|
94396
|
-
|
|
94852
|
+
if (!isEncryptedContentError(errorObject)) {
|
|
94853
|
+
appendError(getErrorHintForStopReason(stopReasonToHandle, currentModelId), true);
|
|
94854
|
+
}
|
|
94397
94855
|
} else {
|
|
94398
94856
|
appendError(`An error occurred during agent execution
|
|
94399
94857
|
(run_id: ${lastRunId}, stop_reason: ${stopReason})`, true);
|
|
@@ -98775,12 +99233,10 @@ var init_App2 = __esm(async () => {
|
|
|
98775
99233
|
init_diff2();
|
|
98776
99234
|
init_errorContext();
|
|
98777
99235
|
init_errorFormatter();
|
|
98778
|
-
init_formatArgsDisplay();
|
|
98779
99236
|
init_messageQueueBridge();
|
|
98780
99237
|
init_pasteRegistry();
|
|
98781
99238
|
init_planName();
|
|
98782
99239
|
init_queuedMessageParts();
|
|
98783
|
-
init_subagentAggregation();
|
|
98784
99240
|
init_subagentState();
|
|
98785
99241
|
init_thinkingMessages();
|
|
98786
99242
|
init_useSyncedState();
|
|
@@ -98838,9 +99294,13 @@ var init_App2 = __esm(async () => {
|
|
|
98838
99294
|
init_WelcomeScreen(),
|
|
98839
99295
|
init_accumulator(),
|
|
98840
99296
|
init_approvalClassification(),
|
|
99297
|
+
init_formatArgsDisplay(),
|
|
98841
99298
|
init_memoryReminder(),
|
|
98842
99299
|
init_sessionContext(),
|
|
98843
99300
|
init_stream(),
|
|
99301
|
+
init_subagentAggregation(),
|
|
99302
|
+
init_toolNameMapping(),
|
|
99303
|
+
init_toolNameMapping(),
|
|
98844
99304
|
init_useSuspend()
|
|
98845
99305
|
]);
|
|
98846
99306
|
import_react91 = __toESM(require_react(), 1);
|
|
@@ -99712,6 +100172,7 @@ var init_create3 = __esm(async () => {
|
|
|
99712
100172
|
// src/agent/import.ts
|
|
99713
100173
|
var exports_import2 = {};
|
|
99714
100174
|
__export(exports_import2, {
|
|
100175
|
+
importAgentFromRegistry: () => importAgentFromRegistry2,
|
|
99715
100176
|
importAgentFromFile: () => importAgentFromFile2,
|
|
99716
100177
|
extractSkillsFromAf: () => extractSkillsFromAf2
|
|
99717
100178
|
});
|
|
@@ -99819,6 +100280,45 @@ async function downloadGitHubDirectory2(entries, destDir, owner, repo, branch, b
|
|
|
99819
100280
|
}
|
|
99820
100281
|
}
|
|
99821
100282
|
}
|
|
100283
|
+
function parseRegistryHandle2(handle) {
|
|
100284
|
+
const normalized = handle.startsWith("@") ? handle.slice(1) : handle;
|
|
100285
|
+
const parts = normalized.split("/");
|
|
100286
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
100287
|
+
throw new Error(`Invalid import handle "${handle}". Use format: @author/agentname`);
|
|
100288
|
+
}
|
|
100289
|
+
return { author: parts[0], name: parts[1] };
|
|
100290
|
+
}
|
|
100291
|
+
async function importAgentFromRegistry2(options) {
|
|
100292
|
+
const { tmpdir: tmpdir4 } = await import("node:os");
|
|
100293
|
+
const { join: join31 } = await import("node:path");
|
|
100294
|
+
const { writeFile: writeFile6, unlink: unlink2 } = await import("node:fs/promises");
|
|
100295
|
+
const { author, name } = parseRegistryHandle2(options.handle);
|
|
100296
|
+
const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/refs/heads/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}/${name}.af`;
|
|
100297
|
+
const response = await fetch(rawUrl);
|
|
100298
|
+
if (!response.ok) {
|
|
100299
|
+
if (response.status === 404) {
|
|
100300
|
+
throw new Error(`Agent @${author}/${name} not found in registry. Check that the agent exists at https://github.com/${AGENT_REGISTRY_OWNER2}/${AGENT_REGISTRY_REPO2}/tree/${AGENT_REGISTRY_BRANCH2}/agents/@${author}/${name}`);
|
|
100301
|
+
}
|
|
100302
|
+
throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
|
|
100303
|
+
}
|
|
100304
|
+
const afContent = await response.text();
|
|
100305
|
+
const tempPath = join31(tmpdir4(), `letta-import-${author}-${name}-${Date.now()}.af`);
|
|
100306
|
+
await writeFile6(tempPath, afContent, "utf-8");
|
|
100307
|
+
try {
|
|
100308
|
+
const result = await importAgentFromFile2({
|
|
100309
|
+
filePath: tempPath,
|
|
100310
|
+
modelOverride: options.modelOverride,
|
|
100311
|
+
stripMessages: options.stripMessages ?? true,
|
|
100312
|
+
stripSkills: options.stripSkills ?? false
|
|
100313
|
+
});
|
|
100314
|
+
return result;
|
|
100315
|
+
} finally {
|
|
100316
|
+
try {
|
|
100317
|
+
await unlink2(tempPath);
|
|
100318
|
+
} catch {}
|
|
100319
|
+
}
|
|
100320
|
+
}
|
|
100321
|
+
var AGENT_REGISTRY_OWNER2 = "letta-ai", AGENT_REGISTRY_REPO2 = "agent-file", AGENT_REGISTRY_BRANCH2 = "main";
|
|
99822
100322
|
var init_import2 = __esm(async () => {
|
|
99823
100323
|
init_model();
|
|
99824
100324
|
await __promiseAll([
|
|
@@ -99919,7 +100419,7 @@ function buildModelSettings2(modelHandle, updateArgs) {
|
|
|
99919
100419
|
} else {
|
|
99920
100420
|
settings = {};
|
|
99921
100421
|
}
|
|
99922
|
-
if (typeof updateArgs?.max_output_tokens === "number") {
|
|
100422
|
+
if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
|
|
99923
100423
|
settings.max_output_tokens = updateArgs.max_output_tokens;
|
|
99924
100424
|
}
|
|
99925
100425
|
return settings;
|
|
@@ -99932,7 +100432,10 @@ async function updateAgentLLMConfig2(agentId, modelHandle, updateArgs) {
|
|
|
99932
100432
|
await client.agents.update(agentId, {
|
|
99933
100433
|
model: modelHandle,
|
|
99934
100434
|
...hasModelSettings && { model_settings: modelSettings },
|
|
99935
|
-
...contextWindow && { context_window_limit: contextWindow }
|
|
100435
|
+
...contextWindow && { context_window_limit: contextWindow },
|
|
100436
|
+
...typeof updateArgs?.max_output_tokens === "number" && {
|
|
100437
|
+
max_tokens: updateArgs.max_output_tokens
|
|
100438
|
+
}
|
|
99936
100439
|
});
|
|
99937
100440
|
const finalAgent = await client.agents.retrieve(agentId);
|
|
99938
100441
|
return finalAgent.llm_config;
|
|
@@ -103760,6 +104263,8 @@ function releaseSwitchLock2() {
|
|
|
103760
104263
|
lock.resolve = null;
|
|
103761
104264
|
}
|
|
103762
104265
|
}
|
|
104266
|
+
var EXTERNAL_TOOLS_KEY2 = Symbol.for("@letta/externalTools");
|
|
104267
|
+
var EXTERNAL_EXECUTOR_KEY2 = Symbol.for("@letta/externalToolExecutor");
|
|
103763
104268
|
function replaceRegistry2(newTools) {
|
|
103764
104269
|
toolRegistry2.clear();
|
|
103765
104270
|
for (const [key, value] of newTools) {
|
|
@@ -103958,6 +104463,7 @@ OPTIONS
|
|
|
103958
104463
|
--skills <path> Custom path to skills directory (default: .skills in current directory)
|
|
103959
104464
|
--sleeptime Enable sleeptime memory management (only for new agents)
|
|
103960
104465
|
--from-af <path> Create agent from an AgentFile (.af) template
|
|
104466
|
+
Use @author/name to import from the agent registry
|
|
103961
104467
|
--memfs Enable memory filesystem for this agent
|
|
103962
104468
|
--no-memfs Disable memory filesystem for this agent
|
|
103963
104469
|
|
|
@@ -104407,6 +104913,7 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
104407
104913
|
process.exit(1);
|
|
104408
104914
|
}
|
|
104409
104915
|
}
|
|
104916
|
+
let isRegistryImport = false;
|
|
104410
104917
|
if (fromAfFile) {
|
|
104411
104918
|
if (specifiedAgentId) {
|
|
104412
104919
|
console.error("Error: --from-af cannot be used with --agent");
|
|
@@ -104424,12 +104931,22 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
104424
104931
|
console.error("Error: --from-af cannot be used with --new");
|
|
104425
104932
|
process.exit(1);
|
|
104426
104933
|
}
|
|
104427
|
-
|
|
104428
|
-
|
|
104429
|
-
|
|
104430
|
-
|
|
104431
|
-
|
|
104432
|
-
|
|
104934
|
+
if (fromAfFile.startsWith("@")) {
|
|
104935
|
+
isRegistryImport = true;
|
|
104936
|
+
const normalized = fromAfFile.slice(1);
|
|
104937
|
+
const parts = normalized.split("/");
|
|
104938
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
104939
|
+
console.error(`Error: Invalid registry handle "${fromAfFile}". Use format: @author/agentname`);
|
|
104940
|
+
process.exit(1);
|
|
104941
|
+
}
|
|
104942
|
+
} else {
|
|
104943
|
+
const { resolve: resolve23 } = await import("path");
|
|
104944
|
+
const { existsSync: existsSync19 } = await import("fs");
|
|
104945
|
+
const resolvedPath = resolve23(fromAfFile);
|
|
104946
|
+
if (!existsSync19(resolvedPath)) {
|
|
104947
|
+
console.error(`Error: AgentFile not found: ${resolvedPath}`);
|
|
104948
|
+
process.exit(1);
|
|
104949
|
+
}
|
|
104433
104950
|
}
|
|
104434
104951
|
}
|
|
104435
104952
|
if (specifiedAgentName) {
|
|
@@ -104573,7 +105090,8 @@ Error: ${message}`);
|
|
|
104573
105090
|
systemPromptPreset: systemPromptPreset2,
|
|
104574
105091
|
toolset,
|
|
104575
105092
|
skillsDirectory: skillsDirectory2,
|
|
104576
|
-
fromAfFile: fromAfFile2
|
|
105093
|
+
fromAfFile: fromAfFile2,
|
|
105094
|
+
isRegistryImport: isRegistryImport2
|
|
104577
105095
|
}) {
|
|
104578
105096
|
const [showKeybindingSetup, setShowKeybindingSetup] = useState45(null);
|
|
104579
105097
|
const [loadingState, setLoadingState] = useState45("selecting");
|
|
@@ -104870,13 +105388,24 @@ Error: ${message}`);
|
|
|
104870
105388
|
let isNewlyCreatedAgent = false;
|
|
104871
105389
|
if (fromAfFile2) {
|
|
104872
105390
|
setLoadingState("importing");
|
|
104873
|
-
|
|
104874
|
-
|
|
104875
|
-
|
|
104876
|
-
|
|
104877
|
-
|
|
104878
|
-
|
|
104879
|
-
|
|
105391
|
+
let result;
|
|
105392
|
+
if (isRegistryImport2) {
|
|
105393
|
+
const { importAgentFromRegistry: importAgentFromRegistry3 } = await init_import2().then(() => exports_import2);
|
|
105394
|
+
result = await importAgentFromRegistry3({
|
|
105395
|
+
handle: fromAfFile2,
|
|
105396
|
+
modelOverride: model,
|
|
105397
|
+
stripMessages: true,
|
|
105398
|
+
stripSkills: false
|
|
105399
|
+
});
|
|
105400
|
+
} else {
|
|
105401
|
+
const { importAgentFromFile: importAgentFromFile3 } = await init_import2().then(() => exports_import2);
|
|
105402
|
+
result = await importAgentFromFile3({
|
|
105403
|
+
filePath: fromAfFile2,
|
|
105404
|
+
modelOverride: model,
|
|
105405
|
+
stripMessages: true,
|
|
105406
|
+
stripSkills: false
|
|
105407
|
+
});
|
|
105408
|
+
}
|
|
104880
105409
|
agent = result.agent;
|
|
104881
105410
|
isNewlyCreatedAgent = true;
|
|
104882
105411
|
setAgentProvenance({
|
|
@@ -105236,11 +105765,12 @@ Error during initialization: ${message}`);
|
|
|
105236
105765
|
systemPromptPreset,
|
|
105237
105766
|
toolset: specifiedToolset,
|
|
105238
105767
|
skillsDirectory,
|
|
105239
|
-
fromAfFile
|
|
105768
|
+
fromAfFile,
|
|
105769
|
+
isRegistryImport
|
|
105240
105770
|
}), {
|
|
105241
105771
|
exitOnCtrlC: false
|
|
105242
105772
|
});
|
|
105243
105773
|
}
|
|
105244
105774
|
main();
|
|
105245
105775
|
|
|
105246
|
-
//# debugId=
|
|
105776
|
+
//# debugId=333508E0ED33A45564756E2164756E21
|