fabro/lib
Scott Werner 548c1574d2
Some checks failed
Rust / Format (push) Has been cancelled
Rust / Clippy (push) Has been cancelled
Rust / Generated Docs (push) Has been cancelled
Rust / Test (Linux) (push) Has been cancelled
Rust / Test (macOS) (push) Has been cancelled
TypeScript / Typecheck (push) Has been cancelled
TypeScript / Test (push) Has been cancelled
TypeScript / Build (push) Has been cancelled
refactor(llm): extract codec/gemini_generate behind the Codec trait (#489)
## Summary

Final dialect extraction in the gateway refactor series (after #481 /
#485, sibling of #487 and #488): the Gemini `generateContent` wire
translation moves out of `providers/gemini.rs` into
`codec/gemini_generate/`, behind the `Codec` / `StreamDecoder` traits.
The adapter becomes a thin transport shell (1,607 → ~400 lines) owning
auth (`x-goog-api-key`), base URL, and the streaming byte loop; 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, migrate the ~22 unit tests, and add the
previously missing stream-decoder tests.

Gemini is the simplest route story in the series — no provider-name
branching, no mode flags, count-tokens always available, no forced
streaming — so there is no route config and **no `CodecParams` changes**
(this PR is conflict-free with #487/#488 apart from one `mod` line; if
it lands after them, the unit-struct `CodecParams` literals become
`::default()` on rebase, mechanical).

It does exercise two trait seams the other codecs don't:
- **Fully-formed endpoints from the codec**: model-in-path
`:generateContent` / `:streamGenerateContent?alt=sse` / `:countTokens`
ride on `EncodedRequest.endpoint` (the count body wraps the request in
`generateContentRequest`).
- **The first `decode_error` override**: Gemini's gRPC-status mapping
(`error_from_grpc_status` with HTTP-status fallback) moves behind the
codec; the adapter feeds it status + body + retry-after. The send-side
timeout mapping stays transport-side.

Other moves, wholesale and already pure: synthetic-UUID
tool-call/response ids, the id→name recovery map for `functionResponse`,
usage arithmetic (cache subtraction + tool-use addition +
thoughts→reasoning), default `safety_settings` injection (flagged
profile-ish in a comment, unchanged), `thoughtSignature` round-trip, and
the `provider_options.gemini` merge. `translate_messages` goes sync:
file-backed Image/Audio/Document attachments resolve via the shared
`attachments::resolve` (#485) before encode.

The streaming decoder preserves Gemini's distinct stream-end contract
exactly: data-only SSE (no event types, no `[DONE]`), and `finish()`
synthesizes the `Finish` from accumulated state unconditionally at
byte-stream end — there is no terminal wire event.

## Behavior preservation

No behavior change. The 32 gemini wire snapshots from #471 (encode
round-trips, attachments, response_format, provider_options merges,
streaming happy path / tool deltas / reasoning deltas / the
unconditional-Finish stream-end pin) pass unmodified, and the full
fabro-llm suite is green at 525: all 22 migrated tests plus 10 new ones
— 9 stream-decoder unit tests (gemini previously had **zero**:
text/thought deltas, reasoning→text transition, single-chunk function
calls, finish-reason handling, Finish synthesis with and without a wire
finish reason, ToolCalls inference, malformed-chunk errors) and 1
pinning the three model-in-path endpoints.

## Testing

- `cargo nextest run -p fabro-llm` — 525 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:38:52 -04:00
..
crates refactor(llm): extract codec/gemini_generate behind the Codec trait (#489) 2026-06-10 17:38:52 -04:00
packages/fabro-api-client feat(llm): add Claude Fable 5 support (#482) 2026-06-10 14:01:56 -04:00