Skip to content

fix(examples): robust streaming example + streaming integration tests#6

Merged
shanev merged 1 commit into
mainfrom
fix/streaming-example-robustness
Jul 2, 2026
Merged

fix(examples): robust streaming example + streaming integration tests#6
shanev merged 1 commit into
mainfrom
fix/streaming-example-robustness

Conversation

@shanev

@shanev shanev commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

The streaming example (examples/streaming) could panic (index out of range [0] with length 0) when a stream produced no output — reproduced intermittently on a fresh go run (cold gRPC connection returning a transient empty/error response). That's the headline example crashing at launch.

Two robustness bugs:

  • The Iterator loop checked !ok before the error, so a real gRPC status was silently swallowed instead of surfaced.
  • acc.Response().GetOutputs()[0] had no length guard.

Changes

  • examples/streaming/main.go — drain via stream.Recv() (io.EOF ends the loop; any other error is fatal and surfaced), and guard the final output access → fails with a clear message instead of a panic. Verified 8/8 clean fresh runs.
  • README.md — same guard on the streaming snippet (+ fixed indentation).
  • integration/ — new reproducible integration tests (build tag integration, skipped without XAI_API_KEY): repeated fresh-client streaming and the exact example pattern, asserting every run yields non-empty content. Gives the headline feature real coverage.

make ci green (build, test, vet, govulncheck 0, buf lint).

🤖 Generated with Claude Code

…on tests

The streaming example could panic (`index out of range [0]`) when the stream
produced no output — e.g. a transient empty/error response on a cold gRPC
connection. Two robustness bugs:
- the Iterator loop checked `!ok` before the error, silently swallowing a real
  gRPC status instead of surfacing it;
- `acc.Response().GetOutputs()[0]` had no length guard.

Rewrite the example to drain via `stream.Recv()` (io.EOF to end, any other error
is fatal and surfaced) and guard the final output access, so it fails with a
clear message rather than a panic. Apply the same guard to the README snippet.

Add reproducible integration tests under `integration/` (build tag `integration`,
skipped without XAI_API_KEY): repeated fresh-client streaming and the exact
example pattern, asserting every run yields non-empty content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shanev shanev merged commit 1a5c82d into main Jul 2, 2026
1 check passed
@shanev shanev deleted the fix/streaming-example-robustness branch July 2, 2026 19:02
shanev added a commit that referenced this pull request Jul 2, 2026
Follow-up to #6 (which was merged without a codex pass). Codex found the fix
was not faithfully proven or documented:

- integration/streaming_acceptance_test.go: the test used the swallow-prone
  Iterator loop (!ok checked before the error) — the very bug it guards
  against — and did not mirror the shipped example (which uses stream.Recv).
  Rewrite it to drain via Recv exactly like the example, surface non-EOF errors,
  and bound each run with a 60s timeout so a stuck stream fails instead of hangs.
- README.md: match the example's zero-output handling (log.Fatal, diagnosable)
  instead of silently doing nothing; use errors.Is(err, io.EOF); correct the
  "iterator helper" description to stream.Recv.
- docs/tutorials/streaming.md: the Iterator section still showed the unsafe
  pattern (error swallowed via !ok, unguarded GetOutputs()[0]). Fix the ordering
  (surface real errors before breaking on !ok) and guard the final access.

make ci green; the acceptance test passes 20/20 fresh streams against the API.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shanev added a commit that referenced this pull request Jul 2, 2026
* fix: address pre-release codex review of v0.1.3

A pre-tag codex review found release blockers and leftover instances of the
streaming bugs #6/#7 fixed elsewhere:

- Version was still 0.1.1 in two places (client.go, transport's default
  User-Agent) and would have shipped in a v0.1.3 tag. Move it to a single
  internal/version package referenced by both so they cannot drift; bump to
  0.1.3.
- integration/stream_test.go and examples/tool_call still swallowed non-EOF
  iterator errors (!ok checked before err); tool_call also had an unguarded
  GetOutputs()[0] panic. Fix ordering and guard, matching examples/streaming.
- docs/tutorials/streaming.md silently ignored a zero-output stream while the
  README and example fail explicitly; make it consistent.
- README ForEachChunk snippet reused an already-drained stream; show creating
  a fresh stream and use errors.Is for EOF.
- examples/streaming: prompt now asks for an eight-line poem so the demo
  visibly streams token-by-token instead of finishing in a blink.

make ci green; full integration suite passes live (20-run acceptance + TTFT
test); example verified streaming with the new prompt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: sweep remaining unsafe snippet patterns flagged by codex

Second codex pass on the v0.1.3 release found the same classes of issue in
more release-facing snippets. Sweep all of them:

- Guard every GetOutputs()[0] in README + docs (unary, deferred, accumulator
  finals in responses.md and tool-doc-search.md).
- Stop swallowing errors in snippets: CreateStream / Create / Retrieve /
  Delete / StartDeferred / Documents.Search / ToolResponseMessage now check
  errors instead of `, _ :=`.
- Tool Call Events snippet: check CreateStream error and non-EOF Recv errors
  (was looping over nil chunks on a mid-stream error).
- ForEachChunk snippets (README + tutorial) create a fresh stream (a stream
  can only be consumed once) and tolerate io.EOF via errors.Is.
- README callback snippet no longer references an undefined `req`.

Repo-wide sweep confirms no remaining `, _ := client.` or unguarded
GetOutputs()[0] in README, docs/, or examples/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs+example: final codex sweep; stream reasoning deltas in the demo

Third codex pass findings, all addressed:
- performance.md, README tool/search snippets, tool-doc-search.md: stop
  swallowing errors from NewClient / FunctionTool / WebSource / Parameters /
  registry.Handle.
- quickstarts.md: guard embeddings/images result indexing.
- Make snippets compile as complete blocks: use or explicitly discard
  declared values (stored, full, msg).

examples/streaming: TTFT investigation showed grok-4.3 streams typed
reasoning deltas ~0.6s after the request, ~3-7s before the first answer
token. Print the reasoning trace dimmed, then the answer — output starts
immediately, and it demonstrates the typed-chunk advantage (reasoning vs
content are separate fields, no parsing). Replace the duplicate final-answer
print with an accumulator stats line (tokens + model).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: handle RequireStoredRequests error; complete replay-harness snippets

Round-4 codex findings: RequireStoredRequests is fallible (error was dropped),
and both replay snippets left client/err dangling. Check the errors and close
the client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* examples: shorten the done line so it doesn't wrap in a standard terminal

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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