1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//! OpenRouter normalization Batch API and synchronous embedding client.
//!
//! `BatchTransport` owns normalization submission and polling.
//! `EmbeddingTransport` owns synchronous array embedding requests.
//!
//! API rules encoded here, verified against the live API on 2026-08-29
//! (`.agents/skills/openrouter-api/` and the batch quickstart):
//!
//! - One batch carries one `endpoint`, one batch-level `model`, and one
//! inline `requests` array. The body must serialize `endpoint` and `model`
//! before `requests`: the API stream-parses and answers 400 otherwise.
//! `SubmitBatch` fixes that order by field declaration; a test pins it.
//! - Success is any 2xx with a parseable batch body: submit answers
//! `202 Accepted` with `status: "validating"` — queued, not complete.
//! - Terminal statuses are `completed`, `failed`, `expired`, `cancelled`.
//! Results arrive inline in the poll response; there is no download
//! endpoint. A `completed` batch can still contain per-request failures:
//! exactly one of `response` or `error` is populated per result line.
//! - Result lines decode per line: a line that breaks the documented
//! envelope arrives as `BatchResultLine::Undecodable` with the raw JSON
//! preserved, so one bad line never fails a completed batch. The
//! result-side helpers are `BatchResultLine::chat_content` and
//! `embedding_vectors`.
//! - The batch-level `model` must be a `:batch` variant slug; a base slug is
//! rejected synchronously and fails the whole submission.
//! - Server-side retention is 30 days: callers persist every result into
//! Postgres at poll time.
//!
//! The API root is configuration, not a constant (context/05): the default
//! is the public endpoint; e2e points it at the local fake batch server.
pub use ;
pub use HttpTransport;
pub use ;