fix: align tool rename fallout

This commit is contained in:
Peter Steinberger
2026-01-09 05:54:34 +01:00
parent 333832c2e1
commit aa5e75e853
8 changed files with 42 additions and 34 deletions

View File

@@ -616,7 +616,6 @@ export function createSystemPromptOverride(
// OAuth token blocking of lowercase names. However, pi-coding-agent's SDK has
// hardcoded lowercase names in its built-in tool registry, so we must pass ALL
// tools as customTools to bypass the SDK's filtering.
// See: https://github.com/anthropics/claude-code/issues/XXX
type AnyAgentTool = AgentTool;

View File

@@ -313,12 +313,12 @@ describe("context-pruning", () => {
makeUser("u1"),
makeToolResult({
toolCallId: "t1",
toolName: "bash",
toolName: "Bash",
text: "x".repeat(20_000),
}),
makeToolResult({
toolCallId: "t2",
toolName: "browser",
toolName: "Browser",
text: "y".repeat(20_000),
}),
];

View File

@@ -2,7 +2,13 @@ import type { ContextPruningToolMatch } from "./settings.js";
function normalizePatterns(patterns?: string[]): string[] {
if (!Array.isArray(patterns)) return [];
return patterns.map((p) => String(p ?? "").trim()).filter(Boolean);
return patterns
.map((p) =>
String(p ?? "")
.trim()
.toLowerCase(),
)
.filter(Boolean);
}
type CompiledPattern =
@@ -39,8 +45,9 @@ export function makeToolPrunablePredicate(
const allow = compilePatterns(match.allow);
return (toolName: string) => {
if (matchesAny(toolName, deny)) return false;
const normalized = toolName.trim().toLowerCase();
if (matchesAny(normalized, deny)) return false;
if (allow.length === 0) return true;
return matchesAny(toolName, allow);
return matchesAny(normalized, allow);
};
}

View File

@@ -29,9 +29,9 @@ describe("Agent-specific tool filtering", () => {
});
const toolNames = tools.map((t) => t.name);
expect(toolNames).toContain("read");
expect(toolNames).toContain("write");
expect(toolNames).not.toContain("bash");
expect(toolNames).toContain("Read");
expect(toolNames).toContain("Write");
expect(toolNames).not.toContain("Bash");
});
it("should apply agent-specific tool policy", () => {
@@ -63,10 +63,10 @@ describe("Agent-specific tool filtering", () => {
});
const toolNames = tools.map((t) => t.name);
expect(toolNames).toContain("read");
expect(toolNames).not.toContain("bash");
expect(toolNames).not.toContain("write");
expect(toolNames).not.toContain("edit");
expect(toolNames).toContain("Read");
expect(toolNames).not.toContain("Bash");
expect(toolNames).not.toContain("Write");
expect(toolNames).not.toContain("Edit");
});
it("should allow different tool policies for different agents", () => {
@@ -96,9 +96,9 @@ describe("Agent-specific tool filtering", () => {
agentDir: "/tmp/agent-main",
});
const mainToolNames = mainTools.map((t) => t.name);
expect(mainToolNames).toContain("bash");
expect(mainToolNames).toContain("write");
expect(mainToolNames).toContain("edit");
expect(mainToolNames).toContain("Bash");
expect(mainToolNames).toContain("Write");
expect(mainToolNames).toContain("Edit");
// family agent: restricted
const familyTools = createClawdbotCodingTools({
@@ -108,10 +108,10 @@ describe("Agent-specific tool filtering", () => {
agentDir: "/tmp/agent-family",
});
const familyToolNames = familyTools.map((t) => t.name);
expect(familyToolNames).toContain("read");
expect(familyToolNames).not.toContain("bash");
expect(familyToolNames).not.toContain("write");
expect(familyToolNames).not.toContain("edit");
expect(familyToolNames).toContain("Read");
expect(familyToolNames).not.toContain("Bash");
expect(familyToolNames).not.toContain("Write");
expect(familyToolNames).not.toContain("Edit");
});
it("should prefer agent-specific tool policy over global", () => {
@@ -143,7 +143,7 @@ describe("Agent-specific tool filtering", () => {
const toolNames = tools.map((t) => t.name);
// Agent policy overrides global: browser is allowed again
expect(toolNames).toContain("browser");
expect(toolNames).not.toContain("bash");
expect(toolNames).not.toContain("Bash");
expect(toolNames).not.toContain("process");
});
@@ -209,9 +209,9 @@ describe("Agent-specific tool filtering", () => {
// Agent policy should be applied first, then sandbox
// Agent allows only "read", sandbox allows ["read", "write", "bash"]
// Result: only "read" (most restrictive wins)
expect(toolNames).toContain("read");
expect(toolNames).not.toContain("bash");
expect(toolNames).not.toContain("write");
expect(toolNames).toContain("Read");
expect(toolNames).not.toContain("Bash");
expect(toolNames).not.toContain("Write");
});
it("should run bash synchronously when process is denied", async () => {
@@ -229,7 +229,7 @@ describe("Agent-specific tool filtering", () => {
workspaceDir: "/tmp/test-main",
agentDir: "/tmp/agent-main",
});
const bash = tools.find((tool) => tool.name === "bash");
const bash = tools.find((tool) => tool.name === "Bash");
expect(bash).toBeDefined();
const result = await bash?.execute("call1", {

View File

@@ -403,7 +403,6 @@ function normalizeToolNames(list?: string[]) {
* Anthropic blocks specific lowercase tool names (bash, read, write, edit) with OAuth tokens.
* Renaming to capitalized versions bypasses the block while maintaining compatibility
* with regular API keys.
* @see https://github.com/anthropics/claude-code/issues/XXX
*/
const OAUTH_BLOCKED_TOOL_NAMES: Record<string, string> = {
bash: "Bash",