Commit Graph
7 Commits
Author SHA1 Message Date
Lars Nolden 10314fb1cd Batch Analyse requests and survive opaque provider schema budgets
Analyse now classifies up to ten same-kind transactions per provider
request: the registry and history travel once per batch, so a
thousand-row backfill costs about a hundred paced requests instead of a
thousand. The answer schema appears once — an array item carrying an
enum-bound ref — because providers meter strict schemas by token cost:
duplicating registry enums per row, or bounding arrays with
minItems/maxItems that Gemini expands per element, rejects real
registries with a bare HTTP 400. Row count, duplicate refs, duplicate
tags and taxonomy bounds are all enforced server-side instead, and a
request still rejected outright halves until accepted, remembering the
working size for the run. Batch requests scale the HTTP budget by row
count, chunk failures cannot abort a run whose later rows succeeded,
and rows resolved against one snapshot share one minted merchant.

Measured on a real 165-row month over a zero-data-retention route:
165 analysed, 152 proposals, 0 errors, 17 requests, under 8 minutes.

Fresh installs default to google/gemini-3.8-flash, the model that
demonstrably honors strict structured outputs over a ZDR route. Preview
changes now carry counterparty, amount and currency, and the review
list shows the amount with a counterparty fallback for banks that leave
descriptions empty.
2026-09-13 13:37:06 +02:00
Lars Nolden ec99434002 Route requests only with parameters ZDR endpoints declare, and list them
The gpt-5.6 family's zero-data-retention endpoints declare
max_completion_tokens, so sending max_tokens under require_parameters
excluded every ZDR route and returned HTTP 404 for the whole family.
The cap is retired: the strict schema, the finish_reason check and the
64 KiB read cap already bound the response.

The model fields now offer the provider's public ZDR catalog filtered
by the exact conditions completions are routed under (live endpoint,
strict structured outputs), fetched server-side, cached for an hour,
and served at GET /api/models; the inputs stay free text so an unlisted
model remains usable when the catalog is unreachable.
2026-09-12 22:33:34 +02:00
Lars Nolden 266bfa6d6a leftovers 2026-09-11 23:36:52 +02:00
Lars Nolden 87f052a3ea Implement classification redesign 2026-09-11 22:46:17 +02:00
Lars Nolden dece0d5b79 Let imports opt out of AI classification
Classification preferences gains "Classify newly imported transactions with
AI", stored as classify_on_import in config.toml and on by default, so existing
configurations keep their behaviour. It covers CSV imports and bank
synchronization alike.

With it off, no import path contacts the provider: classification falls to the
new provider-free rules path, where an opted-in merchant rule still applies its
category and tags, an alias match still attaches its merchant, and everything
else arrives on the editable fallback without a provenance error that would
suggest the provider had failed. Analyse remains available on demand.
2026-09-11 18:10:05 +02:00
Lars Nolden 964b9dfc15 Add native NixOS deployment and UI-managed provider credentials 2026-09-10 14:25:37 +02:00
Lars Nolden 9843fe0c50 init 2026-09-10 12:30:42 +02:00