You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add the retrieval-provider 0079 OpenAI-compatible embeddings wire
mapping (section 8.3) over the existing OpenAIEmbeddingProvider.
input_type flows into EmbeddingEvent.request_params but is a wire no-op
on OpenAI's symmetric /v1/embeddings; for an asymmetric model behind a
compatible endpoint, a bound client-side query_prefix / document_prefix
prepends to the input per input_type. dimensions maps to the wire
dimensions field, and base_url now defaults to https://api.openai.com
per the spec (it was previously required).
Single-source the client-side prefix rule and its application in
retrieval/_events.py (client_side_prefix + apply_client_side_prefix),
adopted by both OpenAI and TEI. Un-defer conformance fixtures 023-027,
read an openai_embedding_provider block in the harness, and assert the
request origin against the bound base_url so the override fixture
verifies routing. Env-gated live tests cover embed, dimensions, and
Matryoshka truncation.
Copy file name to clipboardExpand all lines: conformance.toml
+5-3Lines changed: 5 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -786,10 +786,12 @@ since = "0.16.0"
786
786
note = "Retrieval-provider Jina hosted wire mapping (§8 / §8.2) -- a §8 mapping in the family established by 0077. Two bundled providers ship, distinct instances (one model each) sharing the hosted endpoint: base_url defaults to https://api.jina.ai (origin only; the provider appends /v1/embeddings / /v1/rerank), and the required api_key is sent as Authorization: Bearer <key> (§8.2 *Construction*). JinaEmbeddingProvider posts POST {base_url}/v1/embeddings with {model, input, task?, dimensions?, truncate: false} -- input_type is realized as Jina's native `task` per the closed set (query -> retrieval.query, document -> retrieval.passage); absent input_type omits `task` (the symmetric default), and an unrecognized input_type is a pre-send provider_invalid_request (§7, no request issued). dimensions -> Jina's dimensions (Matryoshka) when set; truncate: false is sent explicitly (fail-loud). It parses the object envelope {model, usage: {total_tokens}, data: [{index, embedding}]}, orders the vectors by data[i].index into input order, and maps usage.total_tokens -> EmbeddingUsage.input_tokens (Jina reports usage, unlike TEI's null -- a record when the body surfaces it, never fabricated). JinaRerankProvider posts POST {base_url}/v1/rerank with {model, query, documents, top_n?, return_documents, truncation: false} -- documents maps directly onto the string array (no per-document wrapping), top_n <- top_k (omitted when None), and return_documents is sent EXPLICITLY (Jina's wire default is true but OA's is False, §2, so the mapping sends the resolved OA value). truncation: false is sent explicitly (fail-loud). It parses {model, usage: {total_tokens}, results: [{index, relevance_score, document?}]} (Cohere-shaped relevance_score), reads the document echo only when present (never auto-filled), sorts by relevance_score descending, enforces the §6 invariants (valid index, no duplicate, len(results) <= top_k), and maps usage.total_tokens -> RerankUsage.input_tokens with search_units null (Jina meters by tokens). raw is the verbatim response dict on both surfaces. Errors map per §8.2: 401/403 -> provider_authentication, 429 -> provider_rate_limit (NOT provider_unavailable), 404 -> provider_invalid_model, 422 (over-length / malformed) -> provider_invalid_request, else -> provider_unavailable. Jina enforces no per-call embed cap (server-side batching), so there is no client-side chunk-and-stitch. Both providers dispatch the typed EmbeddingEvent / RerankEvent (graph-engine §6) per call, mutually exclusive with the failure variant; input_type flows into EmbeddingEvent.request_params with absence-is-meaningful semantics, and RerankEvent.output_results is populated unconditionally on success (proposal 0089). genai_system = 'jina'. Conformance fixtures 018-022 pass, driven through the general wire-capture harness (0077) extended with an expected_wire_headers subset assertion locking the Authorization: Bearer <api_key> header on the outbound request."
# embeddings wire mapping (§8.3), in the §8 mapping family established by
790
+
#0077.
791
791
[proposals."0079"]
792
-
status = "not-yet"
792
+
status = "implemented"
793
+
since = "0.16.0"
794
+
note = "Retrieval-provider OpenAI-compatible embeddings wire mapping (§8 / §8.3) -- a §8 mapping in the family established by 0077, formalized over the OpenAIEmbeddingProvider that shipped with the embedding capability (0059). base_url defaults to https://api.openai.com (origin only; the provider appends /v1/embeddings) and is overridable for any OpenAI-compatible backend (vLLM / LocalAI / TEI's OpenAI surface) -- gen_ai.system 'openai' names the WIRE SURFACE, not the backing deployment (fixture 025); the api_key is sent as Authorization: Bearer <key> (§8.3 *Construction*). OpenAIEmbeddingProvider posts POST {base_url}/v1/embeddings with {model, input, dimensions?} -- input is always the array form (§3), and dimensions -> the wire dimensions field (Matryoshka) when set. input_type is a NO-OP on the base wire: the OpenAI /v1/embeddings wire has no query/document field, so an absent input_type is the correct symmetric default and the mapping does not error on a supplied one -- the wire body is byte-identical to the no-input_type request, input sent verbatim (fixture 026). input_type STILL flows into EmbeddingEvent.request_params with absence-is-meaningful semantics (empty when absent), decoupled from the wire body so it never leaks onto the wire. For an asymmetric model behind a compatible endpoint the construction MAY bind the §8.1 client-side query_prefix / document_prefix -- input_type then selects which prefix to prepend to each input client-side, the only way to express the query/document distinction on a wire with no input_type field (fixture 027); the un-prefixed caller intent is what reaches the event. encoding_format ('base64') rides the extras-pass-through bag (the mapping does not send it by default; OpenAI's wire default is 'float'). It parses the object envelope {object, data: [{object, index, embedding}], model, usage: {prompt_tokens, total_tokens}}, orders the vectors by data[i].index into input order, and maps usage.prompt_tokens -> EmbeddingUsage.input_tokens (total_tokens == prompt_tokens; embedding has no output tokens); response_id is null (OpenAI embeddings carry no id). Errors map per §8.3: 401/403 -> provider_authentication, 429 -> provider_rate_limit, 404 -> provider_invalid_model, 400/422 (malformed / oversized) -> provider_invalid_request, else (5xx) -> provider_unavailable. The client-side embed chunk-and-stitch over OpenAI's 2048-input cap (0092) stays out of scope here. genai_system = 'openai'. Conformance fixtures 023-027 pass, driven through the general wire-capture harness (0077) with the expected_wire_headers Authorization: Bearer assertion (0078). The §8.1 client-side prefix lookup is now a shared retrieval helper (client_side_prefix), adopted by both TEI (0077) and OpenAI."
0 commit comments