- 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>
66 lines
1.6 KiB
TypeScript
66 lines
1.6 KiB
TypeScript
import { queryOptions } from "@tanstack/react-query";
|
|
import { jsonQuery } from "../apiAdapter";
|
|
|
|
export interface AiUsage {
|
|
configured: boolean;
|
|
month_spend_usd: number;
|
|
budget_usd: number;
|
|
remaining_usd: number;
|
|
}
|
|
|
|
export interface ExtractedInvoice {
|
|
supplier_name: string;
|
|
invoice_number: string | null;
|
|
amount: number;
|
|
currency: string;
|
|
vat_rate: number;
|
|
issue_date: string | null;
|
|
due_date: string | null;
|
|
description: string | null;
|
|
}
|
|
|
|
export interface StoredChatMessage {
|
|
role: "user" | "assistant";
|
|
content: string;
|
|
created_at: string;
|
|
/** Parsed content_json — the assistant turn's tool trace, when present. */
|
|
meta?: {
|
|
tools?: { name: string; label: string; ok: boolean }[];
|
|
} | null;
|
|
}
|
|
|
|
export const aiUsageOptions = () =>
|
|
queryOptions({
|
|
queryKey: ["ai", "usage"],
|
|
queryFn: () => jsonQuery<AiUsage>("/api/admin/ai/usage"),
|
|
staleTime: 30_000,
|
|
});
|
|
|
|
export interface Conversation {
|
|
id: number;
|
|
title: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export const aiConversationsOptions = () =>
|
|
queryOptions({
|
|
queryKey: ["ai", "conversations"],
|
|
queryFn: () =>
|
|
jsonQuery<{ conversations: Conversation[] }>(
|
|
"/api/admin/ai/conversations",
|
|
),
|
|
staleTime: 30_000,
|
|
});
|
|
|
|
export const aiConversationMessagesOptions = (id: number) =>
|
|
queryOptions({
|
|
queryKey: ["ai", "conversation", id, "messages"],
|
|
queryFn: () =>
|
|
jsonQuery<{ messages: StoredChatMessage[] }>(
|
|
`/api/admin/ai/conversations/${id}/messages`,
|
|
),
|
|
// Re-read the DB on each mount/selection (no stale-cache resurrection).
|
|
staleTime: Infinity,
|
|
gcTime: 0,
|
|
});
|