Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions src/agents/tools/qveris-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,25 +382,29 @@ describe("createQverisTools", () => {
expect(parsed.execution_id).toBe("exec-123");
});

it("qveris_call returns a structured error when tool was not discovered", async () => {
const fetchMock = vi.fn();
it("qveris_call proceeds with null search_id when tool was not discovered", async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
status: 200,
json: () =>
Promise.resolve({ execution_id: "exec-1", success: true, result: { data: "ok" } }),
text: () => Promise.resolve(""),
headers: new Headers(),
});
globalThis.fetch = fetchMock as typeof globalThis.fetch;
const tools = createQverisTools({ config: makeConfig() });
const invoke = tools.find((t) => t.name === "qveris_call")!;

const result = await invoke.execute("call-1", {
await invoke.execute("call-1", {
tool_id: "unknown-tool-xyz",
params_to_tool: '{"city": "London"}',
});

const parsed = parseToolResult(result);
expect(parsed.success).toBe(false);
expect(parsed.error_type).toBe("tool_not_discovered");
expect(String(parsed.detail)).toContain("not been discovered");
expect(String(parsed.detail)).toContain("/search or /tools/execute");
expect(String(parsed.note)).toContain("Stay inside the QVeris tool workflow");
expect(String(parsed.note)).toContain("Never call /search");
expect(fetchMock).not.toHaveBeenCalled();
expect(fetchMock).toHaveBeenCalledTimes(1);
const [url, init] = fetchMock.mock.calls[0];
expect(url).toContain("/tools/execute");
const body = JSON.parse(init.body);
expect(body.search_id).toBeNull();
});

it("qveris_call returns recovery_step on body-level failure", async () => {
Expand Down
18 changes: 2 additions & 16 deletions src/agents/tools/qveris-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ async function qverisDiscover(params: {

async function qverisCall(params: {
toolId: string;
searchId: string;
searchId?: string;
sessionId: string;
parameters: Record<string, unknown>;
maxResponseSize: number;
Expand All @@ -453,7 +453,7 @@ async function qverisCall(params: {
body: JSON.stringify({
parameters: params.parameters,
max_response_size: params.maxResponseSize,
search_id: params.searchId,
search_id: params.searchId ?? null,
session_id: params.sessionId,
}),
signal: controller.signal,
Expand Down Expand Up @@ -1228,20 +1228,6 @@ export function createQverisTools(options?: {
readNumberParam(params, "max_response_size", { integer: true }) ?? maxResponseSize;
const timeoutOverride = readNumberParam(params, "timeout_seconds");

if (!searchId) {
return jsonResult({
success: false,
error_type: "tool_not_discovered",
detail:
"This tool_id has not been discovered in the current session. " +
"Run qveris_discover first to search for the tool, then retry qveris_call with the same tool_id. " +
"Do NOT bypass this workflow by calling QVeris /search or /tools/execute directly.",
retry_hint:
"Use qveris_discover to find the tool, then call it with the tool_id from the results.",
note: QVERIS_WORKFLOW_NOTE,
} satisfies QverisErrorResult);
}

let toolParams: Record<string, unknown>;
try {
toolParams = JSON.parse(paramsToToolRaw) as Record<string, unknown>;
Expand Down
Loading