@@ -10,14 +10,21 @@ Include `ai/openai/codex/typed/Client.h` and use the facades returned by an
1010existing ` AppServerClient ` :
1111
1212``` cpp
13- client.threads().start({.cwd = "/tmp/project"}, handler);
14- client.threads().resume(threadId, {}, handler);
15- client.threads().list({}, handler);
16- client.threads().read(threadId, handler);
17- client.turns().start(threadId, {typed::TextInput{"Hello"}}, {}, handler);
18- client.turns().interrupt(threadId, turnId, handler);
13+ client.typed(). threads().start({.cwd = "/tmp/project"}, handler);
14+ client.typed(). threads().resume(threadId, {}, handler);
15+ client.typed(). threads().list({}, handler);
16+ client.typed(). threads().read(threadId, handler);
17+ client.typed(). turns().start(threadId, {typed::TextInput{"Hello"}}, {}, handler);
18+ client.typed(). turns().interrupt(threadId, turnId, handler);
1919```
2020
21+ `typed::Client` is the installed, PIMPL-backed grouped facade. Its current
22+ accessors return the one existing `Threads`, `Turns`, `Events`, and `Requests`
23+ object owned by the `AppServerClient`; they do not allocate a second protocol
24+ engine. The old direct accessors remain source-compatible deprecated
25+ forwarders, for example `client.threads()` forwards to
26+ `client.typed().threads()`. New code should use the grouped form.
27+
2128Unsupported or newly introduced operations remain available through
2229`client.raw()`.
2330
@@ -37,13 +44,16 @@ including stability membership, lives in
3744[ coverage report] ( app-server-api-coverage.md ) records inventory and
3845implementation coverage as separate metrics. A private production
3946` ProtocolSurfaceRegistry ` is both the local disposition inventory checked by
40- the coverage guard and the source used by runtime method and discriminator
41- dispatch. Registration in that registry does not claim a typed implementation.
47+ the coverage guard and the source used by runtime method, top-level message,
48+ and implemented nested-union dispatch. A1.0 extends those same rows with
49+ offline authoritative request/result contracts, fixed domain slices, and
50+ mechanically derived completeness evidence. Registration alone still does not
51+ claim a typed implementation or schema completeness.
4252
43- This A0 census does not expand the typed API described below. Unimplemented
44- entries remain raw- or opaque-preserved according to their runtime disposition.
45- Adding the owner-frozen stable typed request, notification, server-request,
46- item, and delta surface is A1 work .
53+ The grouped API described below remains the pre-A1 request surface plus the
54+ A1.0 cross-cutting error model. Other stable operations remain raw- or
55+ opaque-preserved according to their registry disposition until their fixed
56+ A1.1–A1.4 domain slice .
4757
4858The typed operation set is ` thread/start ` , ` thread/resume ` , ` thread/list ` ,
4959` thread/read ` , ` turn/start ` , and ` turn/interrupt ` .
@@ -76,6 +86,16 @@ It also retains the client request ID and the original raw result JSON. A typed
7686decode failure affects only that operation; it is not promoted to a transport
7787or connection failure.
7888
89+ For a remote JSON-RPC error, ` remoteError ` remains the authoritative raw
90+ ` ProtocolError ` , including its code, message, and optional data. When that
91+ data has the pinned ` TurnError ` shape, the adapter additionally exposes
92+ ` codexErrorInfo ` and ` codexErrorDiagnostic ` . Failure to decode this structured
93+ supplement never changes the remote-error classification or the connection.
94+ The placement is proven by pinned production source: the
95+ ` ActiveTurnNotSteerable ` handler serializes a ` TurnError ` and assigns it to the
96+ JSON-RPC error's ` data ` ; the otherwise unconstrained data field is not decoded
97+ by name similarity.
98+
7999Submission failures are returned synchronously through the unchanged
80100` RawProtocol::Submission ` and do not invoke the completion. Accepted
81101completions remain asynchronous. Typed adapters add neither a pending registry
@@ -87,8 +107,8 @@ handlers remain installed across an explicit stop/start.
87107
88108## Events and items
89109
90- ` client.events().setOnEvent() ` receives an ` Event ` variant. The typed methods
91- currently include:
110+ ` client.typed(). events().setOnEvent() ` receives an ` Event ` variant. The typed
111+ methods currently include:
92112
93113- thread started and thread status changed;
94114- turn started, completed, and failed completion classification;
@@ -118,6 +138,11 @@ complete `UserMessageItem::content` value held by the typed layer.
118138completeness marker and any future string; an omitted marker has the
119139schema-defined ` full ` default.
120140
141+ The current public item union is named ` ThreadItem ` , with ` Item ` retained as a
142+ source-compatible alias. ` ResponseItem ` is deliberately a distinct public type
143+ direction; A1.0 does not combine its pinned alternatives with ` ThreadItem ` or
144+ invent the A1.1 alternatives.
145+
121146Unknown notification methods become ` UnknownEvent ` . Unknown item
122147discriminators become ` UnknownItem ` . Unknown items retain any valid common item
123148ID plus the thread and turn IDs supplied by their notification or parent turn.
@@ -126,9 +151,43 @@ A malformed item-local field also degrades to `UnknownItem` with a
126151envelope becomes ` UnknownEvent ` . These values retain their original raw JSON
127152and do not fail the connection.
128153
154+ ## Structured decode diagnostics and Codex errors
155+
156+ Typed forward-compatibility handling has a structured diagnostic in addition
157+ to the temporarily retained optional string error:
158+
159+ ``` cpp
160+ struct DecodeDiagnostic {
161+ DecodeIssueKind kind;
162+ DecodeIssueSeverity severity;
163+ std::string surface;
164+ std::string fieldPath;
165+ std::string message;
166+ };
167+ ```
168+
169+ `UnknownMethod`, `UnknownDiscriminator`, and `UnknownEnumValue` use
170+ `ForwardCompatibility`. A known method or discriminator with an invalid
171+ payload uses `MalformedKnownPayload` and `ProtocolWarning`. Diagnostic text
172+ contains protocol identities and paths, not payload values; the complete raw
173+ JSON is retained separately. Neither class alone fails the connection.
174+
175+ `CodexErrorInfo` has one public alternative for each of the 16 pinned known
176+ discriminators and an explicit `UnknownCodexErrorInfo` alternative. The four
177+ HTTP alternatives distinguish an omitted status from explicit `null` and a
178+ numeric value. `activeTurnNotSteerable.turnKind` is an open string-backed enum
179+ with helpers for `review` and `compact`; a future value remains typed and
180+ receives an `UnknownEnumValue` diagnostic. Every alternative retains its
181+ complete raw JSON.
182+
183+ The `error` notification preserves its legacy raw `TurnError` JSON and adds a
184+ structured `TurnError` view. That view distinguishes omitted, null, and value
185+ semantics for `additionalDetails` and `codexErrorInfo`. Malformed known error
186+ payloads degrade to the raw-preserving compatibility path.
187+
129188## Server requests
130189
131- ` client.requests().setOnRequest() ` currently classifies:
190+ `client.typed(). requests().setOnRequest()` currently classifies:
132191
133192- `item/commandExecution/requestApproval`;
134193- `item/fileChange/requestApproval`;
@@ -184,23 +243,25 @@ through the event loop.
184243
185244## ABI and forward compatibility
186245
187- Task 3 adds public methods to ` AppServerClient ` , private implementation state,
188- and new exported typed C++ classes. The ` AppServerClient ` object still
189- contains only its existing ` Impl ` pointer, so its object layout is unchanged.
190- ` Protocol::ServerRequest ` gains a ` ServerRequestToken ` field for occurrence
191- ownership, which is a public raw-protocol type layout change. The library's
192- normal C++ ABI/versioning policy applies to that change and to the new exported
193- symbols and types.
246+ A1 is one deliberate in-progress C++ rebuild boundary. A1.0 adds
247+ ` AppServerClient::typed() ` , the one-pointer-PIMPL ` typed::Client ` , structured
248+ diagnostics, and public error variants. ` AppServerClient ` itself still contains
249+ only its existing ` Impl ` pointer; all grouped facades use the same raw engine.
250+ Public ` std::variant ` and aggregate layouts changed where the typed model
251+ required it, and this documentation does not claim binary compatibility for
252+ already-built consumers.
253+
254+ SOVERSION remains unchanged in A1.0. The single A1 SOVERSION action is deferred
255+ to A1 closure in A1.4.
194256
195257Typed public headers are installed. Decoder headers under ` detail/ ` remain
196258private. Raw JSON on results, threads, turns, items, events, and server requests
197259is the forward-compatibility escape hatch, and ` client.raw() ` remains
198260available for protocol additions not yet represented by the typed layer.
199261
200- Adding ` UserMessageItem ` extends the public ` Item ` variant, and adding partial
201- common metadata enlarges the public ` UnknownItem ` structure. Existing variant
202- indices are retained and the new ` UnknownItem ` member is appended, preserving
203- ordinary field access and existing three-field aggregate initializers at source
204- level. The layouts are not binary-compatible, however, and exhaustive item
205- visitors must handle the new alternative; already-built C++ consumers must be
206- rebuilt.
262+ The legacy direct facade accessors remain available at source level with
263+ deprecation diagnostics. ` Item ` remains an alias of ` ThreadItem ` . Existing
264+ optional string decode errors remain while structured classification becomes
265+ authoritative. Raw JSON on results, threads, turns, items, events, server
266+ requests, and Codex error alternatives remains the escape hatch for protocol
267+ growth.
0 commit comments