Skip to content

feat(google): instrument generate_content_stream for streaming spans - #760

Open
Aftabbs wants to merge 1 commit into
JudgmentLabs:mainfrom
Aftabbs:feat/google-stream-instrumentation
Open

feat(google): instrument generate_content_stream for streaming spans#760
Aftabbs wants to merge 1 commit into
JudgmentLabs:mainfrom
Aftabbs:feat/google-stream-instrumentation

Conversation

@Aftabbs

@Aftabbs Aftabbs commented Jul 21, 2026

Copy link
Copy Markdown

Summary

wrap_google_client only patched client.models.generate_content (non-streaming). Any call to client.models.generate_content_stream(...) produced no OTel span, no token tracking, and no content capture.

  • Add wrap_generate_content_stream_sync in generate_content.py using immutable_wrap_sync_iterator
  • Update wrap_google_client in wrapper.py to apply both wrappers
  • Add 8 tests in test_generate_content_stream.py

Behaviour

Hook What it does
pre_hook Starts GOOGLE_API_CALL span, logs prompt and model name
yield_hook Accumulates text across chunks; captures usage_metadata from any chunk that provides it (typically the final one)
finally_hook Writes gen_ai.completion, token counts, and resolved model name to span; closes span
error_hook Sets ERROR status on span if iteration raises

Tests (8)

  1. test_creates_span — streaming call creates a GOOGLE_API_CALL span
  2. test_span_has_llm_kind — span carries JUDGMENT_SPAN_KIND = "llm"
  3. test_accumulates_text_across_chunks — text from multiple chunks is joined
  4. test_records_token_usage_from_final_chunk — prompt/completion counts from usage_metadata
  5. test_chunks_without_text_do_not_add_to_completionchunk.text = None is skipped
  6. test_error_sets_error_status — mid-stream exception sets ERROR on span
  7. test_wrap_replaces_methodgenerate_content_stream is replaced after wrapping
  8. test_yields_all_chunks_unchanged — caller receives all original chunks

Closes #759

Checklist

  • Tests added
  • Follows existing immutable_wrap_sync_iterator pattern (see llm_together/chat_completions.py)
  • No new external dependencies

Open in Devin Review

wrap_google_client only patched client.models.generate_content (non-streaming).
Streaming calls via generate_content_stream produced no spans, no token
tracking, and no content capture.

Add wrap_generate_content_stream_sync using immutable_wrap_sync_iterator:
- pre_hook: starts GOOGLE_API_CALL span, logs prompt and model name
- yield_hook: accumulates text and captures usage_metadata per chunk
- finally_hook: writes gen_ai.completion, token counts, and model name,
  then closes span; error_hook sets ERROR status before finally runs

Update wrap_google_client to apply both wrappers on Client init.

Add 8 tests in test_generate_content_stream.py covering span creation,
text accumulation, token recording from final chunk, None-text chunks,
error propagation, method replacement, and passthrough of all chunks.

Closes JudgmentLabs#759

Author: Aftabbs <aftabbs.wwe@gmail.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

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.

Bug: generate_content_stream produces no instrumentation spans

1 participant