import { Router } from "express"; import type { AppServices } from "../serverContext"; import { ApiError, created, ok } from "../utils/http"; const PREFIX = "/api/accounting-agent/v1"; export function buildAccountingAgentRouter(services: AppServices): Router { const router = Router(); const runtime = services.runtimeAdapter; router.post(`${PREFIX}/runs/start`, (req, res, next) => { try { const body = (req.body ?? {}) as Record; const run = runtime.startRun({ sessionId: body.sessionId ? String(body.sessionId) : undefined, initiator: body.initiator ? String(body.initiator) : "operator", source: body.source ? String(body.source) : "gui", metadata: (body.metadata ?? {}) as Record, idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined }); created(res, { ok: true, sessionId: run.sessionId, runId: run.runId, status: run.status, run }); } catch (error) { next(error); } }); router.post(`${PREFIX}/runs/finish`, (req, res, next) => { try { const body = (req.body ?? {}) as Record; const status = String(body.status ?? "DONE") as "DONE" | "ERROR" | "CANCELLED"; if (!["DONE", "ERROR", "CANCELLED"].includes(status)) { throw new ApiError("INVALID_STATUS", `Invalid finish status: ${status}`, 400); } const run = runtime.finishRun({ runId: String(body.runId ?? ""), status, source: body.source ? String(body.source) : "gui", reason: body.reason ? String(body.reason) : undefined, metadata: (body.metadata ?? {}) as Record, idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined }); ok(res, { ok: true, run }); } catch (error) { next(error); } }); router.get(`${PREFIX}/runs`, (_req, res) => { ok(res, { ok: true, items: runtime.listRuns() }); }); router.get(`${PREFIX}/runs/:runId`, (req, res, next) => { try { const run = runtime.getRun(String(req.params.runId)); if (!run) { throw new ApiError("RUN_NOT_FOUND", `Run not found: ${req.params.runId}`, 404); } ok(res, { ok: true, run }); } catch (error) { next(error); } }); router.post(`${PREFIX}/tasks/enqueue`, (req, res, next) => { try { const body = (req.body ?? {}) as Record; const task = runtime.enqueueTask({ runId: String(body.runId ?? ""), payload: (body.payload ?? {}) as Record, source: body.source ? String(body.source) : "gui", idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined }); created(res, { ok: true, task }); } catch (error) { next(error); } }); router.post(`${PREFIX}/tasks/claim`, (_req, res) => { const task = runtime.claimTask(); ok(res, { ok: true, task }); }); router.post(`${PREFIX}/tasks/:taskId/complete`, (req, res, next) => { try { const body = (req.body ?? {}) as Record; const task = runtime.completeTask({ taskId: String(req.params.taskId), result: (body.result ?? {}) as Record, source: body.source ? String(body.source) : "worker", idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined }); ok(res, { ok: true, task }); } catch (error) { next(error); } }); router.post(`${PREFIX}/tasks/:taskId/error`, (req, res, next) => { try { const body = (req.body ?? {}) as Record; const task = runtime.failTask({ taskId: String(req.params.taskId), error: { code: String(body.code ?? "TASK_ERROR"), message: String(body.message ?? "Task failed"), details: body.details }, source: body.source ? String(body.source) : "worker", idempotencyKey: body.idempotencyKey ? String(body.idempotencyKey) : undefined }); ok(res, { ok: true, task }); } catch (error) { next(error); } }); router.get(`${PREFIX}/results`, (_req, res) => { ok(res, { ok: true, items: runtime.getResults() }); }); router.get(`${PREFIX}/trace/run/:runId`, (req, res) => { ok(res, { ok: true, items: runtime.getRunTrace(String(req.params.runId)) }); }); router.get(`${PREFIX}/health`, (_req, res) => { ok(res, runtime.health()); }); return router; }