feat: implement client-side tools via client_tools spec (#456)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-01-02 23:35:40 -08:00
committed by GitHub
parent 5ad51d7095
commit 34367de5d7
14 changed files with 181 additions and 1157 deletions

View File

@@ -31,11 +31,7 @@ import { formatErrorDetails } from "./cli/helpers/errorFormatter";
import { safeJsonParseOr } from "./cli/helpers/safeJsonParse";
import { drainStreamWithResume } from "./cli/helpers/stream";
import { settingsManager } from "./settings-manager";
import {
checkToolPermission,
forceUpsertTools,
isToolsNotFoundError,
} from "./tools/manager";
import { checkToolPermission } from "./tools/manager";
import type {
AutoApprovalMessage,
CanUseToolControlRequest,
@@ -93,8 +89,6 @@ export async function handleHeadlessCommand(
"permission-mode": { type: "string" },
yolo: { type: "boolean" },
skills: { type: "string" },
link: { type: "boolean" },
unlink: { type: "boolean" },
sleeptime: { type: "boolean" },
"init-blocks": { type: "string" },
"base-tools": { type: "string" },
@@ -162,12 +156,6 @@ export async function handleHeadlessCommand(
const client = await getClient();
// Get base URL for tool upsert operations
const baseURL =
process.env.LETTA_BASE_URL ||
settings.env?.LETTA_BASE_URL ||
"https://api.letta.com";
// Resolve agent (same logic as interactive mode)
let agent: AgentState | null = null;
const specifiedAgentId = values.agent as string | undefined;
@@ -354,19 +342,8 @@ export async function handleHeadlessCommand(
memoryBlocks,
blockValues,
};
try {
const result = await createAgent(createOptions);
agent = result.agent;
} catch (err) {
if (isToolsNotFoundError(err)) {
console.warn("Tools missing on server, re-uploading and retrying...");
await forceUpsertTools(client, baseURL);
const result = await createAgent(createOptions);
agent = result.agent;
} else {
throw err;
}
}
const result = await createAgent(createOptions);
agent = result.agent;
}
// Priority 4: Try to resume from project settings (.letta/settings.local.json)
@@ -407,19 +384,8 @@ export async function handleHeadlessCommand(
systemPromptPreset,
// Note: systemCustom, systemAppend, and memoryBlocks only apply with --new flag
};
try {
const result = await createAgent(createOptions);
agent = result.agent;
} catch (err) {
if (isToolsNotFoundError(err)) {
console.warn("Tools missing on server, re-uploading and retrying...");
await forceUpsertTools(client, baseURL);
const result = await createAgent(createOptions);
agent = result.agent;
} else {
throw err;
}
}
const result = await createAgent(createOptions);
agent = result.agent;
}
// Check if we're resuming an existing agent (not creating a new one)