# AI assistant and tools

TanStack AI streams a private conversation through one authorized tool catalog.

<Diagram
  name="approvals"
  alt="The assistant and MCP share a catalog; an exact write waits for user approval before the transaction commits its change, audit and replay result."
/>

## Enable and configure [#enable-and-configure]

Set `AI_PROVIDER` and its matching secret, then enable `ai.assistant`. Both gates are required. `AI_MODEL` can override the provider default. Secrets remain server-side. The existing MCP server works without a configured AI provider.

The default request limits are five model/tool steps, 2,048 output tokens per model call, a 60-second abort deadline and ten requests per minute per User. Input and history are separately bounded. These per-request limits do not replace provider account spending controls.

## One catalog [#one-catalog]

`catalog.schema.ts` defines Zod tool contracts; `catalog.ts` binds authorized implementations. The assistant and MCP adapt those same operations. Each call checks current Organization membership. The assistant uses the Session's Active Organization and rejects a change during a turn.

The catalog has 23 tools. Read operations include `todo_list`, `todo_detail`, `files_list`, `whoami`, `search`, `fetch`, `document_read` and `organization_info`, plus AutoFolio's garage tools: `garage_cars`, `costs_summary`, `costs_compare`, `vehicle_tco`, `net_worth`, `upcoming`, `sale_estimate` (the deal result at the estimated value, an estimate) and `expense_draft` (a draft the User saves in Add expense; it writes nothing). Garage results carry every amount formatted for the account and the app screen with the details; the mobile assistant links each answer to that screen. Approved writes are `todo_create`, `todo_complete`, `import_start`, `create_todo_draft`, `draft_task_plan` and `propose_review`; `ask_for_input` pauses for a User choice.

`files_list` exposes confirmed file IDs and conversion status. `document_read` returns two chunks by default, at most four of 8 KiB each, and `nextCursor` for another page. Search ranks converted text alongside Todos and filenames. Original file bytes never enter tool results. An `awaitingBrowser` result means the User must finish preparation in Files. Reading Document Text sends the selected chunks to the configured model provider and stores the results in the Thread. Treat source text as untrusted data and disclose partial reads. See [documents](/docs/features/documents).

Every write needs approval bound to its User, Organization, tool name and parsed arguments. Assistant approvals also bind the Thread and call ID. The execution transaction checks current membership and expiry, applies the change, records its audit and stores the result. A replay returns that result rather than repeating the mutation.

## Copilot cards [#copilot-cards]

With `ai.genui` on, the mobile assistant draws each garage tool result as a fixed card instead of quoting it ([ADR-0018](/docs/adr/0018-copilot-generative-ui), Plan B of the AI features spec §3; OpenUI was evaluated and set aside). The result schemas live in `@autofolio/api/assistant/contract`; `threadView` parses each one against its schema and drops anything else.

- **Copilot-Costs** (`costs_summary`): the period's total, its change against the span before, the months as bars and the three biggest categories; "See costs" opens Finances. Chips suggest the next question.
- **Copilot-Compare** (`costs_compare`, `sale_estimate`): cost per km or mile and per month per car; the sale at the estimated value with its source, the loan and the deal result (estimate); Prepare sale opens M-Vender.
- **Copilot-Draft** (`expense_draft`): the draft's amount, volume, date, reading and vendor, the economy of the tank it closes; Review and save opens Add expense prefilled, Discard hides it. Nothing is saved before the User saves (RN10).
- TCO, net worth, what is due and the car list have their own cards. Every card names its source and opens its screen.

The app sends `cards: true`, so the server (with the flag on) asks the model for a sentence or two rather than every number. The dev links `autofolio://dev/Copilot-Costs`, `Copilot-Compare` and `Copilot-Draft` ask the board's question in a new conversation; they need a provider, `ai.assistant`, and spend a question of the quota.

## Streaming and persistence [#streaming-and-persistence]

TanStack AI owns the native Promise/SSE lifecycle. The HTTP boundary owns input limits, auth, cancellation, the Thread lease and its bounded pool. Persistence snapshots at most once per second and saves the finished transcript. Stop, timeout or disconnect aborts the turn; reopening recovers the last saved state and pending interrupts.

There is no disconnected background run or resumable transport. Text after the last snapshot can be lost. Deleting a Thread deletes its messages and linked approvals but does not undo completed domain changes.

## Extend [#extend]

Add a catalog contract and authorized operation once, then adapt through the existing assistant/MCP consumers. Preserve exact-argument approval and replay protection. Tests use the deterministic adapter only in an `ai-test` build plus `AI_TEST_PROVIDER=true`; never publish that build. Read [ADR-0007](/docs/adr/0007-ai-assistant-and-tool-catalog) before changing transport, approvals or persistence.

## Key files [#key-files]

- [`packages/api/src/features/agent-tools/agent-tools.catalog.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/agent-tools/agent-tools.catalog.ts)
- [`packages/api/src/features/agent-tools/agent-tools.contract.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/agent-tools/agent-tools.contract.ts)
- [`packages/api/src/features/assistant/assistant.http.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/assistant/assistant.http.ts)
- [`packages/api/src/features/agent-tools/agent-tools.approvals.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/agent-tools/agent-tools.approvals.ts)
- [`packages/api/src/features/assistant/assistant.threads.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/assistant/assistant.threads.ts)
- [`scripts/test-local-ai.mjs`](https://github.com/CarlosZiegler/autofolio/blob/main/scripts/test-local-ai.mjs)

