fix(startup): clear Letta Code tool rules on boot (#1405)

Co-authored-by: Jin Peng <jinjpeng@gmail.com>
Co-authored-by: Letta Code <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-03-16 12:53:17 -07:00
committed by GitHub
parent 380c7e1369
commit 6c7a2efdbb
5 changed files with 188 additions and 2 deletions

View File

@@ -1,3 +1,4 @@
import type { AgentState } from "@letta-ai/letta-client/resources/agents/agents";
import { getClient } from "../agent/client";
import { resolveModel } from "../agent/model";
import { toolFilter } from "./filter";
@@ -219,6 +220,53 @@ export async function reattachMemoryTool(
}
}
type PersistedToolRule = NonNullable<AgentState["tool_rules"]>[number];
interface AgentWithToolsAndRules {
tags?: string[] | null;
tool_rules?: PersistedToolRule[];
}
export function shouldClearPersistedToolRules(
agent: AgentWithToolsAndRules,
): boolean {
return (
agent.tags?.includes("origin:letta-code") === true &&
(agent.tool_rules?.length ?? 0) > 0
);
}
export async function clearPersistedClientToolRules(
agentId: string,
): Promise<{ removedToolNames: string[] } | null> {
const client = await getClient();
try {
const agentWithTools = (await client.agents.retrieve(agentId, {
include: ["agent.tools"],
})) as AgentWithToolsAndRules;
if (!shouldClearPersistedToolRules(agentWithTools)) {
return null;
}
const existingRules = agentWithTools.tool_rules || [];
await client.agents.update(agentId, {
tool_rules: [],
});
return {
removedToolNames: existingRules
.map((rule) => rule.tool_name)
.filter((name): name is string => typeof name === "string"),
};
} catch (err) {
console.warn(
`Warning: Failed to clear persisted client tool rules: ${err instanceof Error ? err.message : String(err)}`,
);
return null;
}
}
/**
* Force switch to a specific toolset regardless of model.
*