feat(odin): Phase 2a read-only agentic assistant + tool-trace UI

- agentic chat loop (max 6 round-trips, budget re-checked between iterations)
  over 10 read-only, permission-delegated tools in src/services/ai-tools.ts
- persist assistant tool trace in ai_chat_messages.content_json (+ migration)
- consulted-tools chips in OdinThread; header now shows month spend only
  (budget cap hidden from the UI, server-side 402 guard unchanged)
- seed: ai.use permission; Settings exposes the ai permission module
- docs: REVIEW consolidation; deployment-guide.md superseded by docs/release.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-10 23:31:50 +02:00
parent 2dbacc3bec
commit 674b44d047
26 changed files with 13728 additions and 2935 deletions

View File

@@ -291,15 +291,28 @@ CSP blocks it and it would leak the secret).
## AI Assistant — "Odin"
Admin-only (`ai.use` permission) Claude assistant at `/odin`. **Phase-1 scope
is invoice import ONLY** — general chat is guarded off in `OdinChat.submit`
(text-only messages get a canned reply, no API call). Backend
`src/services/ai.service.ts` + `src/routes/admin/ai.ts`; per-call cost ledger
in `ai_usage` with a monthly budget cap (402 when exceeded). Invoice flow:
PDF → `extract-invoices` (structured output) → review cards → existing
`POST /received-invoices`. **`received_invoices.amount` is GROSS
(VAT-inclusive)** — VAT is back-calculated (`vatFromGross`). Phase-2 design
notes live in `docs/superpowers/specs/`.
`ai.use`-gated Claude assistant at `/odin` (granted to admin). **Phase 2a:
read-only agentic assistant** — chat turns run an agentic loop
(`agenticChat` in `src/services/ai.service.ts`, max 6 round-trips, budget
re-checked between iterations) over the read-only tools in
`src/services/ai-tools.ts` (invoices, offers, orders, projects, customers,
warehouse, attendance).
**Security model (do not weaken):** Odin is the **user's delegate** — the
tool list is pre-filtered by the caller's permissions AND every handler
re-checks them (`ctxCan`); there are **NO write tools** (writes come in
Phase 2b as propose→confirm action cards, never autonomous). Tool handlers
call the same service functions the routes use. Assistant turns persist
their tool trace in `ai_chat_messages.content_json` (plain `content` stays
the display text); the UI shows consulted-tool chips. The system prompt
enforces plain-text replies (the chat renders pre-wrap text, no Markdown).
Per-call cost ledger in `ai_usage` with a monthly budget cap (402 when
exceeded). Invoice flow unchanged: PDF → `extract-invoices` (structured
output) → review cards → existing `POST /received-invoices`.
**`received_invoices.amount` is GROSS (VAT-inclusive)** — VAT is
back-calculated (`vatFromGross`). Phase-2 design notes live in
`docs/superpowers/specs/`.
---