- Is this fulfillable? If the prompt references something that isn’t
provided — like “embed product screenshots” when you attached no images —
we reject with
400 preflight_failedbefore wasting credits. - What intents does the agent need to plan for? Tags like
visual_first,data_heavy,financial_modelare passed to the agent so it picks sensible defaults.
Why we do this
The tradeoff is deliberately in the client’s favor: a ~$0.0005 preflight call prevents a $0.10 agent run from producing mediocre output because a required asset was missing. It also gives the client a clear error message to fix, instead of a broken document with a placeholder[IMAGE MISSING].
What preflight sees
The validator only sees metadata — names, counts, tags, flags. It never sees the actual bytes of any asset. The prompt and a summary like this:Common rejection patterns
| Prompt fragment | Missing | Fix |
|---|---|---|
| ”with product screenshots” | images | Upload via POST /images, include the image_id in image_assets |
| ”using the attached CSV” | data_sources | Upload via POST /files, reference in data_sources |
| ”based on these contracts” | reference_files | Upload and reference in context_files |
| ”in our brand colors” | brand | Include brand: {primary_color, font, logo_url} in request |
Testing requests before submitting
If you want to check whether a request will pass without spending credits, hit the standalone preflight endpoint:When preflight fails open
If the preflight LLM is slow (>20s) or returns malformed output, we fail open — the request proceeds as ifvalid: true. We log the
event and alert internally; the agent will still attempt the work. This
prevents transient validator issues from blocking the API.
Tuning the rejection bar
If you’re hitting false positives (“my prompt wasn’t really asking for images but preflight rejected it”), a few options:- Rephrase the prompt — the validator is pattern-based, so softer phrasing helps (“include visuals where appropriate” won’t reject, “with product screenshots” will)
- Attach generic assets — for visual-first decks, uploading one placeholder image lets the validator pass; the agent may or may not use it
- File an issue — we tune the prompt continuously; false positives are a direct input into that tuning
Under the hood
Implementation lives inservices/api_documents/preflight.py in the
backend. Uses the same TrackingContext pattern as the main agents, so
preflight cost shows up in your Langfuse traces tagged
purpose=api_preflight. p50 latency is ~400ms; p95 ~800ms.