fabro/lib/crates
Scott Werner 45f564cbfe
refactor(llm): extract codec/openai_responses behind the Codec trait (#487)
## Summary

Next dialect extraction in the gateway refactor series (after #481 /
#485, sibling of the anthropic extraction): the OpenAI Responses API
wire translation moves out of `providers/openai.rs` into
`codec/openai_responses/`, behind the `Codec` / `StreamDecoder` traits.
The adapter becomes a thin transport shell (2,784 → 692 lines) owning
auth (bearer + org/project headers), base URL, the streaming byte loop,
and route config; all translation is in the codec.

Two commits, each independently green:
1. **Add the codec** (`wire`/`encode`/`decode`/`stream`/`mod`) —
compiling but unused behind a scoped `dead_code` allow.
2. **Rewire the adapter** to it and migrate the ~54 unit tests into the
codec submodules they now cover.

Key moves:
- **Codex mode splits along the codec seam**: encode-side param omission
(`temperature`/`top_p`/`max_output_tokens` omitted, `instructions`
always sent) rides on a new `CodecParams::openai_codex` flag; the
transport-side half (blocking requests served via streaming) is route
config on the adapter. No provider-name branching — codex is OpenAI's
only route split.
- **`translate_input` goes sync**: its only async-ness was file-path
image loading, now handled by the shared `attachments::resolve` (#485)
in the adapter before encode (images only; audio/documents render as
text placeholders in the codec without I/O).
- The invariant-dense pieces move wholesale, already pure: opaque
`openai_reasoning`/`openai_message` item round-trip, the `fc_…`/`call_…`
dual-id preservation via `provider_metadata`, custom-tool (apply_patch)
emission and raw-input accumulation, `store: false` + `include:
["reasoning.encrypted_content"]`.
- The SSE state machine becomes `SseAccumulator` behind `StreamDecoder`:
the transport owns byte reading + framing; the decoder is fed framed
`RawEvent`s, resolves the event type from the SSE `event:` line or the
JSON `type` field, and `finish()` synthesizes nothing
(`response.completed`/`incomplete` are the finishers — matching the old
EOF behavior exactly).

Coordination note: this PR makes the same unit→fielded `CodecParams`
change as the sibling anthropic extraction (each adds only its own
fields) — whichever lands second resolves a trivial field-union conflict
in `codec/mod.rs`.

## Behavior preservation

No behavior change. The 33 openai_responses wire snapshots from #471
(codex mode, dual-id round-trip, opaque items, attachment drop-on-error,
response_format, streaming happy path / tool deltas / reasoning deltas /
failure events) pass unmodified, and the full fabro-llm suite is back to
count (516: all 54 migrated tests plus one new test pinning the
count-tokens endpoint + filtered body on the codec).

## Testing

- `cargo nextest run -p fabro-llm` — 516 passed (126 wire snapshots
included)
- `cargo check --workspace`
- `cargo +nightly-2026-04-14 clippy -p fabro-llm --all-targets -- -D
warnings`
- `cargo +nightly-2026-04-14 fmt --check`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 17:11:18 -04:00
..
build-support fix(build): refresh embedded git sha on branch commits 2026-05-09 14:10:04 -04:00
fabro-acp fix(workflow): capture configured artifacts once (#337) 2026-05-21 10:52:22 -04:00
fabro-agent feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-api feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-auth Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-automation fix(automation): honor schedule trigger enabled state 2026-05-30 02:19:52 -04:00
fabro-checkpoint Interpolation foundation (InterpString v2) (#472) 2026-06-10 12:51:08 -04:00
fabro-cli feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-client Add fabro variable CLI namespace for server-managed variables (#434) 2026-05-27 13:57:25 -04:00
fabro-config feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-core Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-dev feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-dump Model run sandbox lifecycle explicitly (#431) 2026-05-27 12:48:56 -04:00
fabro-environment Interpolation foundation (InterpString v2) (#472) 2026-06-10 12:51:08 -04:00
fabro-github fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-graphviz Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-hooks Add event-sourced todo tools for OpenAI and Anthropic profiles (#353) 2026-05-22 13:44:42 -04:00
fabro-http refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-install feat(install): enable only allowed sandbox providers 2026-06-02 18:39:31 -04:00
fabro-interview Replace stdin JSONL control pipe with WebSocket worker control bus (#440) 2026-05-27 20:24:25 -04:00
fabro-llm refactor(llm): extract codec/openai_responses behind the Codec trait (#487) 2026-06-10 17:11:18 -04:00
fabro-macros refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-manifest Interpolation foundation (InterpString v2) (#472) 2026-06-10 12:51:08 -04:00
fabro-mcp Add legacy SSE MCP transport support (#386) 2026-05-24 15:29:01 -04:00
fabro-mcp-server feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-model feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00
fabro-oauth Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-options-metadata refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-proc refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-redact refactor(integrations): make chat integrations Slack-only 2026-05-09 11:43:16 -04:00
fabro-sandbox Model run sandbox lifecycle explicitly (#431) 2026-05-27 12:48:56 -04:00
fabro-server Interpolation foundation (InterpString v2) (#472) 2026-06-10 12:51:08 -04:00
fabro-slack Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-spa feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
fabro-static refactor: rationalize server secret scopes (vault-only for optional int… (#401) 2026-05-25 17:26:01 -04:00
fabro-store perf(server): cache bare GitHub clones for automation materialization 2026-05-29 08:29:58 -04:00
fabro-telemetry Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-template feat(template): resolve template error locations (#333) 2026-05-20 20:15:04 -04:00
fabro-test test(llm): pin provider wire behavior with per-dialect snapshot tests (#471) 2026-06-08 16:11:27 -04:00
fabro-tool feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-tracker fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-types Interpolation foundation (InterpString v2) (#472) 2026-06-10 12:51:08 -04:00
fabro-util Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-validate fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-variable feat(server): add variables API (#430) 2026-05-27 11:46:36 -04:00
fabro-vault feat(server): add variables API (#430) 2026-05-27 11:46:36 -04:00
fabro-workflow feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00