fix(api): use a neutral catalog pointer in the call_api protocol refusal

A non-empty description does not always say who can use the endpoint
(the WebSocket entries only say they are not callable through call_api),
so point to the description for details instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 5.5 committed 2026-11-09 00:11:44 -06:00
1 parent 843e16db8b
commit e7ff8ba610
2 files changed
+9 -2

No files matched your search

@@ -21,7 +21,7 @@ it("tells agents searching for assistant disconnection that only the person can
it("says the call_api protocol rejection is final instead of inviting another search", () => {
expect(() => validateRunnerApiCall({ operationId: "GET /api/mcp/connections" }, context))
.toThrow(/no other API route substitutes for it\. Its catalog description says who can use it\./);
.toThrow(/no other API route substitutes for it\. Read its catalog description for details\./);
});
it("points at the catalog description only when the protocol endpoint has one", () => {
@@ -32,3 +32,10 @@ it("points at the catalog description only when the protocol endpoint has one",
expect(message).toContain("no other API route substitutes for it.");
expect(message).not.toContain("catalog description");
});
it("does not claim a non-guidance protocol description says who can use the endpoint", () => {
let message = "";
try { validateRunnerApiCall({ operationId: "GET /api/companies/{companyId}/events/ws" }, context); } catch (error) { message = (error as Error).message; }
expect(message).toContain("Read its catalog description for details.");
expect(message).not.toContain("who can use it");
});
@@ -54,7 +54,7 @@ export function validateRunnerApiCall(value: unknown, context: RunnerApiContext)
if (!parsed.success) throw badRequest("Invalid call_api arguments", { issues: parsed.error.issues });
const input = parsed.data;
const operation = runnerApiOperation(input.operationId);
if (operation.transport !== "rest") throw unprocessable(`This endpoint requires its existing protocol client; call_api supports REST only and no other API route substitutes for it.${operation.description.trim() ? " Its catalog description says who can use it." : ""}`);
if (operation.transport !== "rest") throw unprocessable(`This endpoint requires its existing protocol client; call_api supports REST only and no other API route substitutes for it.${operation.description.trim() ? " Read its catalog description for details." : ""}`);
if (input.responseText && operation.method !== "GET") throw badRequest("responseText requires a GET operation; read the saved artifact instead of repeating a mutation");
if (!operation.allowedModes.includes(context.workMode)) throw forbidden("call_api permits only reads in Ask and Plan modes; use the permitted dedicated tools");
if (input.pathParams?.companyId && input.pathParams.companyId !== context.companyId) throw forbidden("API call belongs to another company");