Files
legal-ai/web-ui/src/lib/api/paperclip-agents.ts
Chaim 6f713042b5 feat(settings): add Agents tab — read-only Paperclip agent config view
Task #29: surfaces all 14 agents (7 roles × 2 companies) in /settings as
master+mirror pairs with drift detection. Replaces ad-hoc psql + script
inspection with a single dashboard.

Backend: GET /api/admin/paperclip-agents — fetches via Paperclip API
(not direct DB), groups by name, computes drift across model/effort/
timeoutSec/maxTurnsPerRun/skills/runtime_config.heartbeat/budget/status.

Frontend: new AgentsTab card-per-pair with side-by-side compare,
drift highlighting, expandable details (skills list + instructions path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 17:23:48 +00:00

72 lines
1.8 KiB
TypeScript

/**
* Paperclip agents — read-only admin view (Task #29).
*
* Backend: `GET /api/admin/paperclip-agents` returns master+mirror pairs
* (CMP / CMPA) for all 7 agent roles, with drift detection between the pair.
*/
import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "./client";
export type PaperclipAgent = {
id: string;
company_id: string;
company_name: string;
name: string;
role: string | null;
status: string | null;
pause_reason: string | null;
adapter_type: string | null;
model: string | null;
effort: string | null;
timeoutSec: number | null;
maxTurnsPerRun: number | null;
desiredSkills: string[];
instructionsBundleMode: string | null;
instructionsRootPath: string | null;
instructionsEntryFile: string | null;
instructionsFilePath: string | null;
graceSec: number | null;
cooldownSec: number | null;
wakeOnDemand: boolean | null;
maxConcurrentRuns: number | null;
intervalSec: number | null;
enabled: boolean | null;
budget_monthly_cents: number | null;
spent_monthly_cents: number | null;
last_heartbeat_at: string | null;
updated_at: string | null;
};
export type DriftEntry = {
field: string;
master: unknown;
mirror: unknown;
};
export type AgentPair = {
name: string;
role: string | null;
master: PaperclipAgent | null;
mirror: PaperclipAgent | null;
drift: DriftEntry[];
};
export type PaperclipAgentsResponse = {
pairs: AgentPair[];
companies: Array<{
id: string;
label: string;
slot: "master" | "mirror";
}>;
};
export function usePaperclipAgents() {
return useQuery({
queryKey: ["settings", "paperclip-agents"] as const,
queryFn: ({ signal }) =>
apiRequest<PaperclipAgentsResponse>("/api/admin/paperclip-agents", { signal }),
staleTime: 30_000,
});
}