Open Net Worth
Open Net Worth is an open-source personal AI wealth assistant you run yourself: one ledger for your whole financial life, worked by an AI agent you control.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Conversational agent with real tool use over receipt data — the LLM picks the right SQL tool (list, aggregate, or detail) and answers in natural language.
翻訳待ち
Loading the full README.
Read the full README ↗Conversational agent that answers in natural language about Peruvian receipts and invoices. Showcases real tool use: the LLM decides which SQL tool to call (list_receipts, query_aggregates, get_receipt_detail), executes it against Neon Postgres, and responds with verifiable data. Reuses the same database as Invoice Extractor — extract first, then analyze.
Author: sebpost2
Live demo · No sign-up · 27 demo receipts preloaded
list_receipts({orderBy: "total_desc"}) → grabs the first id → get_receipt_detail({id}) → writes the answer.z.enum, z.string), the AI SDK validates inputs before execution, and TypeScript infers the types on the server.streamText + useChat).<details> component showing the exact input and output JSON. Visitors see what the model queried, not just what it said.get_receipt_detail, the receipt id is shown. If it comes from a list/aggregate, the scope is shown ("Based on N receipts"). No fabricated references.react-markdown + GFM.npm run seed (Tottus, Pardos, Sodimac, Inkafarma, etc.) plus the 3 real ones from the extractor — 27 receipts total for substantial questions.evals/ lock down the agent's behavior — single-step routing (ES + EN), multi-step list → detail chains, and no-tool refusal for greetings/off-topic. Run with npm run eval. A pre-eval guard verifies the duplicated prompt copy hasn't drifted from src/lib/chat-prompts.ts.| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 (dark-first) |
| LLM SDK | Vercel AI SDK v6 (ai, @ai-sdk/groq, @ai-sdk/react) |
| Model | OpenAI gpt-oss-120b via Groq |
| Database | PostgreSQL (Neon, serverless) — shared with the extractor |
| ORM | Prisma 7 with @prisma/adapter-pg |
| Validation | Zod 4 |
| Markdown | react-markdown + remark-gfm |
| Rate limit | In-memory token bucket |
| LLM evals | Promptfoo (OSS) — 22 tool-selection cases under evals/ |
| Deploy | Vercel |
┌──────────┐ sendMessage ┌────────────────┐ streamText ┌──────┐
│ Client │ ─────────────> │ /api/chat │ ───────────────> │ Groq │
│ useChat │ │ (route handler)│ + tools (Zod) │ LLM │
└────┬─────┘ └────────┬───────┘ └───┬──┘
│ │ │
│ UIMessageStream │ │
│ <─────────────────────────────┤ ┌────────┐ tool call │
│ • text-delta │ │ Neon │ <────────────────┤
│ • tool-input-streaming │ │ DB │ │
│ • tool-output-available │ └────────┘ tool result ────┤
│ • text-end │ │
│ │ ... until stepCountIs(5) │
useChat({ transport: DefaultChatTransport }).streamText with the 3 tools and the Groq model.execute (Prisma query) and feeds the result back to the model.stopWhen: stepCountIs(5)) or write the final answer.| Tool | Input | Output | When the model picks it |
|---|---|---|---|
list_receipts | orderBy: "date_desc" | "date_asc" | "total_desc" | "total_asc" | Array of receipts with summary fields | "Show me my receipts", "which was the most expensive?" |
query_aggregates | metric: "total_spent" | "total_igv" | "total_subtotal" | "count" | "all" | Per-currency aggregates | "How much did I spend?", "How many receipts?", "How much VAT?" |
get_receipt_detail | id: string | Full receipt with items | "Give me the details of [id]", final step after identifying a receipt via a list |
This is the beginning of the README. Read the rest at the original. Read the full README ↗