docs(llm): document ProviderShared helpers and framing seam
Update the adapter authoring guide to reflect the dedupe pass: - Generalize the `parse` bullet from `ProviderShared.sse` to `ProviderShared.framed` and call out the two framing dialects in use today (SSE for OpenAI/Anthropic/Gemini/compat, AWS event stream for Bedrock). - Spell out that `framed`'s `framing` parameter is the seam for new wire formats; the rest of the pipeline is shared. - New 'Shared adapter helpers' subsection enumerating the `ProviderShared` exports a new adapter author should reach for before hand-rolling: `framed`, `sse`, `sseFraming`, `joinText`, `parseToolInput`, `parseJson`, `chunkError`. - Closing nudge: lift 3-5 line repeats into ProviderShared rather than copy them between adapters. Doc-only — no code or test changes.
This commit is contained in:
+21
-2
@@ -45,9 +45,28 @@ Adapters should stay boring and typed:
|
||||
- target patches mutate that draft before validation.
|
||||
- `validate` validates the final provider target with Schema.
|
||||
- `toHttp` creates the `HttpClientRequest`.
|
||||
- `parse` decodes provider chunks into `LLMEvent`s. The shared `ProviderShared.sse` helper handles SSE framing, chunk decoding, and stateful chunk-to-event raising; adapters supply `decodeChunk` and a `process` callback that produces events.
|
||||
- `parse` decodes provider chunks into `LLMEvent`s. The shared `ProviderShared.framed` helper handles transport-error mapping, chunk decoding, and stateful chunk-to-event raising; adapters supply a `framing` step (bytes → frames), a `decodeChunk`, and a `process` callback that produces events.
|
||||
|
||||
The transport is HTTP + SSE today; the `LLMEvent` stream contract is intentionally transport-agnostic. When a provider ships a non-HTTP transport (OpenAI's WebSocket-based Codex backend, hypothetical bidirectional streaming APIs), it should land as a sibling adapter with a `toWs` (or analogous) producer + a `parse` that reads frames from that transport — not by leaking transport details into core types.
|
||||
The transport is HTTP today, with two framing dialects:
|
||||
|
||||
- **SSE** for OpenAI Chat / OpenAI Responses / Anthropic Messages / Gemini / OpenAI-compatible Chat. Use `ProviderShared.sse(...)` — a thin wrapper around `framed` with `sseFraming` (decode bytes → `Sse.decode` → drop `[DONE]` and Retry control events).
|
||||
- **AWS event stream** for Bedrock Converse. Bedrock supplies its own `eventStreamFraming` step that runs `@smithy/eventstream-codec` against a cursor-based byte buffer.
|
||||
|
||||
When a provider ships a non-HTTP transport (OpenAI's WebSocket-based Codex backend, hypothetical bidirectional streaming APIs), it should land as a sibling adapter with a `toWs` (or analogous) producer + a `parse` that reads frames from that transport — not by leaking transport details into core types. The `framed` helper's `framing` parameter is the seam for new wire formats; the rest of the stream pipeline (terminal-error normalization, `mapAccumEffect` state, `onHalt` fallback) is already shared.
|
||||
|
||||
### Shared adapter helpers
|
||||
|
||||
`ProviderShared` exports a small toolkit so adapters can stay focused on provider-native shapes:
|
||||
|
||||
- `framed({ adapter, response, readError, framing, decodeChunk, initial, process, onHalt? })` — the canonical streaming pipeline. Reach for it before hand-rolling a `Stream` chain.
|
||||
- `sse({ ... })` — convenience wrapper for SSE adapters. Identical shape to `framed` minus the `framing` field.
|
||||
- `sseFraming` — the SSE-specific framing step, exposed in case an adapter wants to wrap or compose it.
|
||||
- `joinText(parts)` — joins an array of `TextPart` (or anything with a `.text`) with newlines. Use this anywhere an adapter flattens text content into a single string for a provider field.
|
||||
- `parseToolInput(adapter, name, raw)` — Schema-decodes a tool-call argument string with the canonical "Invalid JSON input for `<adapter>` tool call `<name>`" error message. Treats empty input as `{}`. Use this in `finishToolCall` / `finalizeToolCalls`; do not roll a fresh `parseJson` callsite.
|
||||
- `parseJson(adapter, raw, message)` — generic JSON-via-Schema decode for non-tool payloads.
|
||||
- `chunkError(adapter, message, ...)` — typed `ProviderChunkError` constructor for stream-time failures.
|
||||
|
||||
If you find yourself copying a 3-to-5-line snippet between two adapters, lift it into `ProviderShared` next to these helpers rather than duplicating.
|
||||
|
||||
### Patches
|
||||
|
||||
|
||||
Reference in New Issue
Block a user