Skip to content

AI

EstimateIQ uses AI for three jobs in the revision loop: parsing auditor notes, writing a next-best-action brief, and powering semantic search. Language-model calls run through an authenticated Cloudflare AI Gateway to Claude; if the gateway or a key is unavailable a deterministic fallback keeps every feature working with zero keys.

How inference is routed

Model calls go to the account’s authenticated AI Gateway (derekdavis) at its OpenAI-compatible /compat/chat/completions endpoint. The model is expressed as <provider>/<model> (default anthropic/claude-sonnet-4-6), the provider key authorizes the call, and CF_AIG_TOKEN authenticates the gateway — giving centralized logging, caching, and rate control over every request.

If no gateway (or provider key) is configured, EstimateIQ falls back — first to a direct Claude call, finally to a deterministic rule-based parser and templated brief. The output is structurally identical, so downstream code never branches on which path produced it. Each response reports its provider (gateway, claude, or deterministic).

Task 1 — Parse the auditor note

When a carrier returns an estimate with a desk-audit note (logged from the deal detail page or pushed via the XactAnalysis webhook), parseAuditorNote turns the free text into structured data:

{
"reasonCodes": ["DEPRECIATION", "PRICING"],
"disputedItems": [{ "code": "...", "desc": "...", "issue": "..." }],
"summary": "..."
}

Reason codes come from a fixed taxonomy: OP_DISPUTE, DEPRECIATION, CODE_VERIFICATION, PRICING, DOCUMENTATION, DUPLICATE_LINE, SCOPE, QUANTITY, MISSED_ITEM, DEDUCTIBLE.

The parsed result drives the rest of the revision handling:

  1. The revision leg stores the reason codes + disputed items on the swimlane.
  2. Disputed line items are flagged challenged by code.
  3. The per-carrier rules engine evaluates the reason codes, delta, round, loss type, and phase — firing priority overrides, SLA overrides, assignments, and follow-ups.
  4. The estimate’s nextAction and the auto-generated respond follow-up are set from the summary.

The deterministic fallback matches the note against a regex table for reason codes and extracts Xactimate-style code tokens for disputed items — so parsing always returns usable structure.

Task 2 — Next-best-action brief

Given an estimate’s state and history (carrier, status, ball, round, days held vs budget, last note, reason codes), EstimateIQ writes a 2–3 sentence recommendation of the single next move. The brief is persisted to R2 (ai/brief/:id.json) so it stays stable between views; Refresh from model on the detail page recomputes and re-saves it. Without a model, a deterministic brief is composed from the ball and aging (e.g. “Carrier has held round 3 for 8d, past the ~5d desk-audit window — call the desk adjuster.”).

Search is embedding-based. Workers AI (bge-base-en-v1.5) embeds the full content of every estimate — header, carrier, every revision/auditor note, line items, and follow-ups — into the Vectorize index; a query is embedded and matched against it, with results cached in KV. See Search for the operator view and Data loading for POST /api/admin/reindex.

Tuning AI in-app

GET /api/ai/config returns the current model + prompts, the built-in defaults, and any env overrides (AI_GATEWAY_MODEL, AI_GATEWAY_URL). Saving writes PUT /api/settings/aiConfig.

Endpoints

GET /api/ai/config # current model + prompts (+ defaults + env)
POST /api/ai/parse-revision # parse an auditor note → reason codes + disputed items
POST /api/ai/next-best-action/:id # compute a brief for a specific estimate
GET /api/ai-brief/:id # read the persisted brief (from R2)
POST /api/ai-brief/:id # recompute + persist the brief (from R2)
GET /api/search?q=... # semantic search (Workers AI + Vectorize, KV-cached)
POST /api/admin/reindex # re-embed every estimate into Vectorize (admin)

See the API reference for the full surface.