FN-5758: add cited-goal audit aggregation and runtime route
Add end-to-end goal-citation audit trail plumbing across core, engine, CLI, and dashboard. - extend goal citation extraction with aggregation logic and new core coverage - expose cited-goal runtime data through dashboard routes with dedicated API tests - wire goal-citation audit details into engine diagnostics and CLI extension audit expectations - document the new audit behavior and publish a patch changeset for @runfusion/fusion Files changed: .changeset/fn-5758-goal-citation-audit.md | 9 +++ docs/dashboard-guide.md | 2 + docs/diagnostics.md | 4 ++ .../__tests__/extension-goal-tools-audit.test.ts | 6 +- packages/cli/src/extension.ts | 3 + .../goal-citation-audit-aggregation.test.ts | 63 ++++++++++++++++++ packages/core/src/goal-citation-extractor.ts | 54 ++++++++++++++- packages/core/src/index.ts | 1 + .../src/__tests__/routes-run-cited-goals.test.ts | 77 ++++++++++++++++++++++ packages/dashboard/src/routes.ts | 11 ++++ .../src/routes/register-agent-runtime-routes.ts | 49 ++++++++++++++ .../src/__tests__/goal-anchoring-audit.test.ts | 40 +++++++---- packages/engine/src/goal-anchoring-audit.ts | 4 ++ packages/engine/src/goal-injection-diagnostics.ts | 1 + 14 files changed, 308 insertions(+), 16 deletions(-) Fusion-Task-Id: FN-5758 Fusion-Task-Lineage: b077c0b7-6ca4-489d-8c36-73d80a2afdb2
This commit is contained in:
@@ -4,6 +4,7 @@ import type { ApiRoutesContext } from "./types.js";
|
||||
type NormalizedAuditEvent = import("../routes.js").NormalizedRunAuditEvent;
|
||||
type TimelineEntry = import("../routes.js").TimelineEntry;
|
||||
type RunAuditResponse = import("../routes.js").RunAuditResponse;
|
||||
type RunCitedGoalsResponse = import("../routes.js").RunCitedGoalsResponse;
|
||||
type RunTimelineResponse = import("../routes.js").RunTimelineResponse;
|
||||
|
||||
interface AgentRuntimeRouteDeps {
|
||||
@@ -1519,6 +1520,54 @@ export function registerAgentRuntimeRoutes(ctx: ApiRoutesContext, deps: AgentRun
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/agents/:id/runs/:runId/cited-goals
|
||||
* Get cited goal IDs aggregated from goal-related run-audit events for a specific run.
|
||||
*/
|
||||
router.get("/agents/:id/runs/:runId/cited-goals", async (req, res) => {
|
||||
try {
|
||||
const { store: scopedStore } = await getProjectContext(req);
|
||||
const { AgentStore, collectCitedGoalIdsFromAudit } = await import("@fusion/core");
|
||||
const agentStore = new AgentStore({ rootDir: scopedStore.getFusionDir() });
|
||||
await agentStore.init();
|
||||
|
||||
const runId = req.params.runId;
|
||||
if (!runId || runId.trim().length === 0) {
|
||||
throw badRequest("runId is required");
|
||||
}
|
||||
|
||||
const run = await agentStore.getRunDetail(req.params.id, req.params.runId);
|
||||
if (!run) {
|
||||
throw notFound("Run not found");
|
||||
}
|
||||
|
||||
const goalEvents = scopedStore.getRunAuditEvents({
|
||||
runId: req.params.runId,
|
||||
domain: "database",
|
||||
});
|
||||
|
||||
const { injectedGoalIds, retrievedGoalIds, citedGoalIds } = collectCitedGoalIdsFromAudit(goalEvents);
|
||||
const taskId = run.contextSnapshot?.taskId as string | undefined;
|
||||
const response: RunCitedGoalsResponse = {
|
||||
runId: req.params.runId,
|
||||
taskId,
|
||||
injectedGoalIds,
|
||||
retrievedGoalIds,
|
||||
citedGoalIds,
|
||||
};
|
||||
res.json(response);
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof ApiError) {
|
||||
throw err;
|
||||
}
|
||||
if ((err instanceof Error ? err.message : String(err)).includes("not found")) {
|
||||
throw notFound(err instanceof Error ? err.message : String(err));
|
||||
} else {
|
||||
rethrowAsApiError(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/agents/:id/runs/:runId/timeline
|
||||
* Get a correlated timeline combining run-audit events and agent logs for a specific run.
|
||||
|
||||
Reference in New Issue
Block a user