fix(coding-agent/mcp): include customWireName in applied-tool signature
A tool's wire-visible name (`customWireName`) is rendered into the system prompt body via `toolPromptNames`, but the applied-tool signature only hashed name+label+description. A future tool whose wire name varied without touching the other fields would silently produce a stale system prompt that advertises the wrong callable name to the model — desyncing prompt guidance from actual tool routing. Today the only mutation path (edit-mode toggle) is also covered by a description change and an explicit `refreshBaseSystemPrompt` from `#syncEditToolModeAfterModelChange`, so this is a defensive fix rather than a live bug. Including `customWireName` makes the signature a self-consistent model of the prompt inputs. - Extended `describeTool` in `#computeAppliedToolSignature` to include `tool.customWireName ?? ""`. Applies to both the active-tool segment and the (mcpDiscoveryEnabled) registry segment via the shared helper. - Updated the docstring to call out wire-name coverage. - Added a regression test that mutates `customWireName` between identical-metadata refreshes and asserts the rebuild fires. Per Codex review on #890.
This commit is contained in:
@@ -300,4 +300,38 @@ describe("AgentSession refreshMCPTools rebuild skipping", () => {
|
||||
await session.refreshMCPTools([active, discoverableV2]);
|
||||
expect(rebuildCount).toBe(baseline + 1);
|
||||
});
|
||||
it("rebuilds when an MCP tool's customWireName changes", async () => {
|
||||
// `customWireName` overrides the model-facing tool name (e.g. `edit` exposes
|
||||
// itself as `apply_patch` to GPT-5). The wire name is rendered into the prompt
|
||||
// body via `toolPromptNames`, so a wire-name flip with the rest of the metadata
|
||||
// constant would otherwise leave a stale system prompt that advertises the wrong
|
||||
// callable name to the model. The signature must catch this.
|
||||
let rebuildCount = 0;
|
||||
const { session } = newSession(async toolNames => {
|
||||
rebuildCount++;
|
||||
return `tools:${toolNames.join(",")}`;
|
||||
});
|
||||
|
||||
// Attach a custom wire name to the MCP tool. `applyToolProxy` forwards arbitrary
|
||||
// properties from the underlying CustomTool to the wrapper, so the AgentTool the
|
||||
// signature inspects exposes `customWireName` as if it were declared on the type.
|
||||
const v1 = createMcpCustomTool("mcp__nucleus_search", "nucleus", "search", "Search");
|
||||
const v1WithWire = { ...v1, customWireName: "wire_v1" } as typeof v1 & { customWireName: string };
|
||||
await session.refreshMCPTools([v1WithWire]);
|
||||
expect(rebuildCount).toBe(1);
|
||||
|
||||
// Same wire name: skip.
|
||||
await session.refreshMCPTools([v1WithWire]);
|
||||
expect(rebuildCount).toBe(1);
|
||||
|
||||
// Wire name changes while name/label/description stay constant: must rebuild.
|
||||
const v2WithWire = { ...v1, customWireName: "wire_v2" } as typeof v1 & { customWireName: string };
|
||||
await session.refreshMCPTools([v2WithWire]);
|
||||
expect(rebuildCount).toBe(2);
|
||||
|
||||
// Drop wire name entirely: must rebuild (signature must differ from `wire_v2`).
|
||||
await session.refreshMCPTools([v1]);
|
||||
expect(rebuildCount).toBe(3);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user