Skip to content

Commit 1bc8318

Browse files
authored
docs: focus codecs on provider normalization (#706)
#### Overview Refocuses the Codecs concept on provider request and response normalization. - [x] I confirm this contribution is my own work, or I have the right to submit it under this project's license. - [x] I searched existing issues and open pull requests, and this does not duplicate existing work. #### Details - Makes provider codecs the primary concept and keeps typed-value codecs as a linked secondary path. - Adds separate request and response flow diagrams. - Explains the lossless patch contract and the difference between preserving unknown fields and understanding their semantics. - Moves implementation links to their first relevant mention. #### Where should the reviewer start? Review `Provider Request and Response Codecs` and `Preservation Is Not Semantic Support` in `docs/about-nemo-relay/concepts/codecs.mdx`. #### Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to) - Closes [RELAY-613](https://linear.app/nvidia/issue/RELAY-613/focus-the-codecs-concept-on-provider-payload-normalization) ## Summary by CodeRabbit - **Documentation** - Updated codec documentation to clarify provider codecs, typed value codecs, and their responsibilities. - Documented request and response normalization, lossless patching, unknown-field preservation, and payload fidelity. - Added request/response flow diagrams and clarified gateway, agent, and provider-specific extraction behavior. - Refined terminology for route selection, correlation, semantic support, and scope ownership. - Removed outdated “Read Next” links. Authors: - Alex Fournier (https://github.com/afourniernv) Approvers: - https://github.com/lvojtku URL: #706
1 parent d27a20e commit 1bc8318

1 file changed

Lines changed: 105 additions & 80 deletions

File tree

docs/about-nemo-relay/concepts/codecs.mdx

Lines changed: 105 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,87 @@
11
---
2-
title: "Codecs"
3-
description: ""
2+
title: "Provider Codecs"
3+
description: "Understand how provider codecs normalize requests and responses, preserve unknown fields, and expose supported fields."
44
position: 7
55
---
6+
import { MermaidStyles } from "@/components/MermaidStyles";
7+
68
{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
79
SPDX-License-Identifier: Apache-2.0 */}
810

911
This page explains how codecs fit into the shared NeMo Relay runtime contract.
1012

1113
## Overview
1214

13-
A codec is a boundary translator. It converts one runtime-facing data shape into
14-
another without changing who owns execution.
15+
A provider codec translates provider-native LLM request and response payloads
16+
into annotated Relay data. Middleware and observability can then work with
17+
consistent fields without taking control of provider execution. Refer to
18+
[Provider Payload Normalization](/integrate-into-frameworks/provider-codecs) for
19+
implementation guidance.
1520

16-
NeMo Relay uses codecs when runtime behavior needs stable, JSON-compatible, or
17-
annotated data but the application or provider surface starts from a different
18-
shape.
21+
NeMo Relay also supports
22+
[typed value codecs](/integrate-into-frameworks/using-codecs), which translate
23+
application objects at a public wrapper API.
1924

2025
## Key Features
2126

22-
Codecs let NeMo Relay preserve one execution model across different boundaries:
23-
24-
- Application-owned typed values
25-
- Framework-owned callback payloads
26-
- Provider-native LLM request and response shapes
27-
- Exporter or subscriber consumers that need normalized data
28-
29-
Without codecs, request-side middleware and observability would need to reason
30-
about every framework or provider shape directly.
31-
32-
## Two Main Codec Roles
33-
34-
NeMo Relay documentation uses the word `codec` in two ways: typed value codecs
35-
and provider codecs. They are related, but they differ in the ways described
36-
below.
37-
38-
### Typed Value Codecs
27+
Provider codecs handle:
3928

40-
Typed value codecs translate application-facing values to and from JSON-friendly
41-
shapes at the public wrapper boundary.
29+
- Provider-native LLM request and response payloads
30+
- Request middleware that needs normalized instructions, messages, tools, or
31+
generation controls
32+
- Events, subscribers, and exporters that need normalized response facts
4233

43-
Typed value codecs are suitable for:
34+
Without provider codecs, request middleware and observability would need to
35+
parse every provider payload directly.
4436

45-
- Application code wants native objects
46-
- Framework callbacks expect typed values
47-
- Runtime events and JSON-based middleware still need stable serialized payloads
48-
49-
### Provider Codecs
37+
## Provider Request and Response Codecs
5038

5139
Provider codecs translate provider-native LLM payloads in the request and
5240
response halves of a provider call. First, request codecs decode provider
5341
requests into annotated request data for request intercepts and request-side
54-
middleware, then encode edits back into the provider shape when execution
55-
continues. Later, after the provider returns, response codecs decode provider
42+
middleware, then encode edits back into the provider payload when execution
43+
continues. Later, after the provider returns,
44+
[response codecs](/integrate-into-frameworks/provider-response-codecs) decode provider
5645
responses into annotated response data for LLM end events, subscribers,
5746
exporters, and diagnostics.
5847

59-
Provider codecs are suitable for:
48+
Use provider codecs when:
6049

61-
- Provider payloads differ structurally
62-
- Request intercepts need normalized request meaning
50+
- Provider payloads differ structurally.
51+
- Request intercepts need consistent request fields.
6352
- Response annotations such as usage, model names, or tool calls should be
64-
exposed in one stable shape for downstream consumers
53+
exposed through consistent fields for downstream consumers.
54+
55+
<MermaidStyles />
56+
57+
### Request Path
58+
59+
The following diagram shows the request path.
60+
61+
```mermaid
62+
flowchart LR
63+
native["Provider-native request"] --> decode["Request codec decodes"]
64+
decode --> annotated["Annotated request"]
65+
annotated --> middleware["Request middleware reads or edits"]
66+
middleware --> encode["Request codec patches original"]
67+
encode --> provider["Provider call"]
68+
```
69+
70+
### Response Path
71+
72+
The following diagram shows the response path.
73+
74+
```mermaid
75+
flowchart LR
76+
provider["Provider response"] --> decode["Response codec decodes"]
77+
decode --> annotated["Annotated response"]
78+
annotated --> event["LLM end event"]
79+
event --> consumers["Subscribers and exporters"]
80+
```
6581

6682
Response decoding improves observability and downstream consistency. It does not
6783
automatically change the value returned to the application unless a separate
68-
typed value boundary also does so.
84+
typed value codec also does so.
6985

7086
The built-in request codecs are lossless patch codecs. For an unchanged
7187
annotation, the following identity holds at the JSON-value level:
@@ -86,50 +102,71 @@ changing a key overlays it.
86102
- `instructions` represents Anthropic `system` and OpenAI Responses
87103
`instructions`.
88104
- `messages`, content parts, function calls and results, tools, and tool choice
89-
expose portable components when the shapes have shared semantics.
90-
- `api_specific` is a tagged, mutable surface for modeled Anthropic Messages,
105+
expose portable components when the provider formats have equivalent meaning.
106+
- `api_specific` is a tagged, mutable field for modeled Anthropic Messages,
91107
OpenAI Chat Completions, or OpenAI Responses controls.
92108
- Provider-only messages, content blocks, input items, tools, and tool choices
93109
use `{ provider, kind, value }`, where `value` is the exact native JSON.
94-
- Top-level `extra` is reserved for unknown future fields.
110+
- Top-level `extra` preserves unknown or unmodeled fields.
95111

96-
A provider-native component can only be encoded by the provider surface named
112+
A provider-native component can only be encoded by the provider API named
97113
in its `provider` field. Provider mismatches and portable edits that the target
98114
API cannot represent fail before the provider callback.
99115

100-
## Normalized Data Consumption
116+
### Preservation Is Not Semantic Support
117+
118+
Provider APIs can add fields or change semantics before Relay's built-in codecs
119+
are updated. The lossless patch contract preserves unknown fields and
120+
provider-native components when they are unchanged, which keeps newer payloads
121+
from being discarded. That pass-through behavior does not mean Relay
122+
understands, validates, or can portably edit those fields.
101123

102-
Normalized codec output is applicable to several runtime layers:
124+
Semantic support is limited to the provider fields modeled by the current codec
125+
implementation. New provider behavior requires a codec and test update before
126+
middleware or exporters should rely on its normalized meaning.
103127

104-
- Request intercepts or request-side middleware that need stable request meaning
128+
## Typed Value Codecs
129+
130+
Typed value codecs serve a different purpose. They translate
131+
application-facing objects to and from JSON-compatible values when application
132+
code or framework callbacks need native types but Relay events and middleware
133+
need a stable serialized payload. Refer to
134+
[Using Codecs](/integrate-into-frameworks/using-codecs) for implementation
135+
guidance.
136+
137+
## Where Normalized Data Is Used
138+
139+
Several parts of Relay use normalized codec output:
140+
141+
- Request intercepts or request-side middleware that need consistent request fields
105142
- Lifecycle events that should expose consistent semantic payloads
106143
- Subscribers that inspect runtime activity in process
107144
- Exporters that write raw ATOF events or project them into ATIF or typed
108145
OpenTelemetry output
109146

110147
Codecs do not replace scopes, middleware, subscribers, or plugins. They make
111-
those layers easier to apply consistently across heterogeneous inputs.
148+
those layers easier to apply consistently across provider-specific inputs.
112149

113-
## Extraction Strategy Boundaries
150+
## Extraction Responsibilities
114151

115-
NeMo Relay keeps extraction responsibilities separated so refactors can reuse
116-
normalization logic without changing runtime ownership or public binding APIs.
152+
NeMo Relay separates extraction responsibilities so normalization logic can be
153+
reused without changing public binding APIs.
117154

118155
### Provider Schema Extraction
119156

120-
Provider schema extraction is codec-owned. Built-in provider surfaces, such as
121-
OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages, each own the
122-
logic that recognizes their request and response shapes and maps them into
123-
`AnnotatedLlmRequest` or `AnnotatedLlmResponse`.
157+
Provider codecs extract provider schema fields. The built-in codecs for OpenAI
158+
Chat Completions, OpenAI Responses, and Anthropic Messages recognize their
159+
request and response payloads and map them into `AnnotatedLlmRequest` or
160+
`AnnotatedLlmResponse`.
124161

125162
When a managed LLM event already has an annotation, subscribers and exporters
126163
consume that annotation. When an event has only raw provider JSON, best-effort
127-
normalization may detect a built-in provider surface and decode it. This
164+
normalization can detect a built-in provider codec and decode it. This
128165
fallback is fail-open: unrecognized, ambiguous, missing, sparse, or invalid
129166
payloads remain observable as raw lifecycle data. A recognized provider hint can
130-
disambiguate an otherwise identical request shape, such as an Anthropic Messages
167+
disambiguate an otherwise identical request payload, such as an Anthropic Messages
131168
request without a top-level `system` field, but no provider annotation is
132-
invented without either a matching provider surface or a recognized hint.
169+
invented without either a matching provider codec or a recognized hint.
133170

134171
Provider extraction covers model names, instructions, messages, generation
135172
parameters, tool definitions, tool calls, finish reasons, usage, cost,
@@ -145,24 +182,24 @@ usage, cost, provider-specific, and preserved `extra` fields. Cost parsing and
145182
estimation helpers are codec implementation details behind that interface, not a
146183
separate provider-response API.
147184

148-
### Provider Request Extraction
185+
### Gateway Request Extraction
149186

150-
Provider request extraction is gateway-owned. It uses the selected gateway route,
187+
The gateway extracts route-specific request facts. It uses the selected route,
151188
such as OpenAI Responses, OpenAI Chat Completions, OpenAI Models, Anthropic
152189
Messages, or Anthropic Count Tokens, to extract request facts that are not codec
153190
schema annotations.
154191

155192
Route-specific request extractors resolve gateway session IDs, request-affinity
156193
keys, and fallback turn input for provider calls that arrive before the matching
157-
agent prompt hook. This keeps correlation and ownership hints near gateway
158-
alignment, while provider codecs stay focused on decoding request and response
194+
agent prompt hook. This keeps correlation and routing hints in the gateway
195+
routing logic, while provider codecs stay focused on request and response
159196
schemas.
160197

161198
Provider request extraction can also pass a narrow provider hint into codec
162199
normalization. For example, the recognized `anthropic` and `anthropic.messages`
163200
hints let Anthropic Messages requests without a top-level `system` field decode
164-
through the Anthropic provider surface instead of being treated as shape-only
165-
OpenAI Chat payloads.
201+
through the Anthropic codec instead of being inferred as OpenAI Chat payloads
202+
from their fields alone.
166203

167204
The `nemo-relay` gateway always enables matching request codecs for
168205
`/v1/messages`, `/v1/chat/completions`, and `/v1/responses`, for both buffered
@@ -176,16 +213,16 @@ remains writable on routes without a request codec.
176213
Agent payload extraction is separate from provider codecs. Coding agents,
177214
harnesses, and framework hooks can expose session IDs, event names, subagent
178215
relationships, tool IDs, tool names, tool arguments, tool results, LLM hints,
179-
and status fields through host-specific payload shapes. These facts help NeMo
216+
and status fields through host-specific payload formats. These facts help NeMo
180217
Relay attach lifecycle events to the right scope, but they do not decode
181218
provider schemas or build request-affinity keys from provider requests.
182219

183220
Agent extraction may be partial. Missing identifiers use compatibility
184-
fallbacks at the adapter boundary, such as synthetic session IDs, synthetic tool
221+
fallbacks in the adapter, such as synthetic session IDs, synthetic tool
185222
call IDs, an explicit `unknown_tool` name, or a generic subagent ID. Lossy,
186223
summary-only, or truncated payloads should keep their original payload and
187-
metadata available for debugging instead of pretending to be reconstruction
188-
grade provider data.
224+
metadata available for debugging instead of presenting them as complete provider
225+
data.
189226

190227
### Exporter Projection
191228

@@ -199,22 +236,10 @@ semantic attributes remain exporter-local.
199236

200237
Codecs do not decide:
201238

202-
- Ownership boundaries
239+
- Which scope owns the call
203240
- Middleware ordering
204241
- Whether execution is allowed to continue
205242
- Which exporter is active
206243

207244
Those responsibilities belong to scopes, middleware, plugins, and exporter or
208245
subscriber registration.
209-
210-
## Read Next
211-
212-
- Use [Using Codecs](/integrate-into-frameworks/using-codecs) for typed value
213-
codecs at framework-facing boundaries.
214-
- Use [Provider Codecs](/integrate-into-frameworks/provider-codecs) for
215-
provider-native request and response normalization.
216-
- Use [Provider Response
217-
Codecs](/integrate-into-frameworks/provider-response-codecs) when the main
218-
need is response-side annotations for subscribers or exporters.
219-
- Refer to the [Glossary](/resources/glossary) for the stable terminology used
220-
across codecs, providers, and observability surfaces.

0 commit comments

Comments
 (0)