feat(FN-3330): add wait_for_completion polling for research runs in extensi
Adds `wait_for_completion` polling support for research runs in the CLI extension, along with tests covering the research status schema and wait behavior, and ships a patch changeset for `@runfusion/fusion`. Fusion-Task-Id: FN-3330
This commit is contained in:
@@ -27,7 +27,7 @@ vi.mock("../commands/task.js", () => ({
|
||||
}));
|
||||
|
||||
import kbExtension from "../extension.js";
|
||||
import { TaskStore, AgentStore } from "@fusion/core";
|
||||
import { TaskStore, AgentStore, RESEARCH_RUN_STATUSES } from "@fusion/core";
|
||||
import { isGhAvailable, isGhAuthenticated, runGhJsonAsync } from "@fusion/core/gh-cli";
|
||||
import { runTaskPlan } from "../commands/task.js";
|
||||
|
||||
@@ -116,6 +116,23 @@ async function removeDirWithRetries(path: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function enableResearch(cwd: string): Promise<TaskStore> {
|
||||
const store = new TaskStore(cwd);
|
||||
await store.init();
|
||||
await store.updateGlobalSettings({
|
||||
researchGlobalEnabled: true,
|
||||
researchGlobalDefaults: { searchProvider: "searxng" },
|
||||
researchSearxngUrl: "http://localhost:8888",
|
||||
});
|
||||
await store.updateSettings({
|
||||
researchEnabled: true,
|
||||
researchSettings: { enabled: true, searchProvider: "searxng" },
|
||||
researchWebSearchProvider: "searxng",
|
||||
researchSearxngUrl: "http://localhost:8888",
|
||||
});
|
||||
return store;
|
||||
}
|
||||
|
||||
// ── Tests ──────────────────────────────────────────────────────────
|
||||
|
||||
// Audited in FN-3189: this suite is expensive (~62s) and currently stale
|
||||
@@ -1327,6 +1344,61 @@ describe("fn pi extension (runnable structured-output regression slice)", () =>
|
||||
});
|
||||
});
|
||||
|
||||
describe("research tools", () => {
|
||||
it("fn_research_list status parameter matches RESEARCH_RUN_STATUSES", () => {
|
||||
const tool = api.tools.get("fn_research_list") as any;
|
||||
const statusSchema = tool.parameters.properties.status;
|
||||
const enumValues = statusSchema.enum ?? statusSchema.anyOf?.[0]?.enum;
|
||||
expect(enumValues).toEqual([...RESEARCH_RUN_STATUSES]);
|
||||
});
|
||||
|
||||
it("fn_research_run preserves fire-and-forget behavior when wait_for_completion is false", async () => {
|
||||
await enableResearch(tmpDir);
|
||||
const tool = api.tools.get("fn_research_run")!;
|
||||
|
||||
const result = await tool.execute(
|
||||
"research-run-ff",
|
||||
{ query: "test query", wait_for_completion: false },
|
||||
undefined,
|
||||
undefined,
|
||||
makeCtx(tmpDir),
|
||||
);
|
||||
|
||||
expect(result.content[0].text).toContain("Start the project engine to process pending runs");
|
||||
expect(result.details.status).toBe("queued");
|
||||
});
|
||||
|
||||
it("fn_research_run waits and returns terminal run details when wait_for_completion is true", async () => {
|
||||
const store = await enableResearch(tmpDir);
|
||||
const tool = api.tools.get("fn_research_run")!;
|
||||
const researchStore = store.getResearchStore();
|
||||
|
||||
setTimeout(() => {
|
||||
const queuedRun = researchStore.listRuns({ limit: 1 })[0];
|
||||
if (!queuedRun) {
|
||||
return;
|
||||
}
|
||||
researchStore.updateRun(queuedRun.id, { status: "running" });
|
||||
researchStore.updateRun(queuedRun.id, {
|
||||
status: "completed",
|
||||
results: { summary: "done", findings: [{ heading: "h1", content: "f1", sources: [] }], citations: [] },
|
||||
});
|
||||
}, 25);
|
||||
|
||||
const result = await tool.execute(
|
||||
"research-run-wait",
|
||||
{ query: "terminal query", wait_for_completion: true, max_wait_ms: 4000 },
|
||||
undefined,
|
||||
undefined,
|
||||
makeCtx(tmpDir),
|
||||
);
|
||||
|
||||
expect(result.details.status).toBe("completed");
|
||||
expect(result.details.summary).toBe("done");
|
||||
expect(result.content[0].text).toContain("is completed");
|
||||
});
|
||||
});
|
||||
|
||||
describe("fn_delegate_task", () => {
|
||||
it("delegates task to agent", async () => {
|
||||
const agentId = await seedAgent(tmpDir, { name: "delegate-target" });
|
||||
|
||||
Reference in New Issue
Block a user