Skip to content

feat(protocol): document the chat-completions SSE response - #61

Merged
its-janghoon merged 2 commits into
developfrom
feature/chunk-schema-and-sse-docs
Sep 23, 2026
Merged

its-janghoon merged 2 commits into
developfrom
feature/chunk-schema-and-sse-docs

Conversation

@its-janghoon

Copy link
Copy Markdown
Contributor

feat(protocol): document the chat-completions SSE response

The route answers with application/json or with text/event-stream depending on
stream, and HttpApi can only declare one success schema. So the generated spec described
only the JSON, and a client built from it looks for choices[].message.content on a
streaming response and finds nothing on every frame - because a chunk carries
choices[].delta instead. That is the same gap /event has, and the same fix site.

Adds ChatCompletionChunk, which is genuinely a different shape rather than a reuse: the
object discriminator is chat.completion.chunk, and each choice carries a partial delta
instead of a complete message. Every delta field is optional because OpenAI's stream uses
the shape sparsely - the first frame typically carries only role, middle frames only
content, a tool call arrives spread across frames, and the terminator carries an empty
delta with finish_reason set. A schema that required content would reject the terminator.

Declared for documentation and codegen only. The handler stays handleRaw and writes its own
SSE frames, because choosing between JSON and a stream per request is exactly what HttpApi
cannot express.

Both content types are declared on the one 200 rather than the SSE replacing the JSON, so
the spec says what actually happens instead of lying in the other direction.

Registered through HttpApi.AdditionalSchemas. A $ref to a schema no endpoint references
dangles otherwise, and a dangling ref generates a client with a missing type rather than
failing loudly - which is why one of the three new tests asserts the ref resolves to a
registered component rather than only that the ref is present.

Coverage 211/0/0, route and wire tests 28/28, openapi tests 21/21, protocol and redrob
typecheck clean.

The generated artifacts are NOT regenerated here. bun script/generate.ts also rewrites
packages/sdk/openapi.json, which is stale on clean develop by 991 lines including routes
that are not mine, so committing it would sweep another session's unregenerated surface
into this change. It needs its own regeneration commit, which is being raised separately.

The route answers with `application/json` or with `text/event-stream` depending on
`stream`, and HttpApi can only declare one success schema. So the generated spec described
only the JSON, and a client built from it looks for choices[].message.content on a
streaming response and finds nothing on every frame - because a chunk carries
choices[].delta instead. That is the same gap /event has, and the same fix site.

Adds ChatCompletionChunk, which is genuinely a different shape rather than a reuse: the
object discriminator is chat.completion.chunk, and each choice carries a partial delta
instead of a complete message. Every delta field is optional because OpenAI's stream uses
the shape sparsely - the first frame typically carries only role, middle frames only
content, a tool call arrives spread across frames, and the terminator carries an empty
delta with finish_reason set. A schema that required content would reject the terminator.

Declared for documentation and codegen only. The handler stays handleRaw and writes its own
SSE frames, because choosing between JSON and a stream per request is exactly what HttpApi
cannot express.

Both content types are declared on the one 200 rather than the SSE replacing the JSON, so
the spec says what actually happens instead of lying in the other direction.

Registered through HttpApi.AdditionalSchemas. A $ref to a schema no endpoint references
dangles otherwise, and a dangling ref generates a client with a missing type rather than
failing loudly - which is why one of the three new tests asserts the ref resolves to a
registered component rather than only that the ref is present.

Coverage 211/0/0, route and wire tests 28/28, openapi tests 21/21, protocol and redrob
typecheck clean.

The generated artifacts are NOT regenerated here. `bun script/generate.ts` also rewrites
packages/sdk/openapi.json, which is stale on clean develop by 991 lines including routes
that are not mine, so committing it would sweep another session's unregenerated surface
into this change. It needs its own regeneration commit, which is being raised separately.
No source change. `bun script/generate.ts` output only.

Two things land together, and the split matters for review:

The chat-completions SSE documentation from the previous commit - the 200 now declares both
application/json and text/event-stream, and ChatCompletionChunk appears as a component.

Pre-existing drift that was already in the repo before this branch. packages/sdk/openapi.json
was stale on clean develop by roughly 900 lines, including routes that are not mine
(/api/variant/paraphrase among them). Those were regenerated here because there is no way to
regenerate only part of the file, and leaving them would mean the committed spec still does
not describe the served API. This is why it is a separate commit: the source change is
reviewable on its own, and this one is verifiable by re-running the generator.

There is no CI check for this drift, which is why it accumulated. The client generator IS
checked (packages/client check:generated fails on any diff) and passes; the SDK spec is not.
Worth adding a check, but that is a change to CI rather than to artifacts and does not belong
here.

Also deliberately NOT committed: the ~54 files `generate.ts` reformats as a side effect,
mostly markdown table alignment and line wrapping in untouched sources. Those are the
generator running a formatter over the repo, not generated output, and sweeping them in would
bury the three files that actually matter.
@its-janghoon
its-janghoon merged commit ec8ae0a into develop Sep 23, 2026
15 checks passed
@its-janghoon
its-janghoon deleted the feature/chunk-schema-and-sse-docs branch September 23, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant