Skip to content

fix(server-utils): Restore request config attributes on google-genai chat spans - #23316

Merged
isaacs merged 6 commits into
getsentry:developfrom
zkasuran:fix/google-genai-chat-config-attrs
Aug 28, 2026
Merged

fix(server-utils): Restore request config attributes on google-genai chat spans#23316
isaacs merged 6 commits into
getsentry:developfrom
zkasuran:fix/google-genai-chat-config-attrs

Conversation

@zkasuran

@zkasuran zkasuran commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

chats.create() takes a config (temperature, topP, topK, maxOutputTokens, frequencyPenalty, presencePenalty, tools, systemInstruction) that @google/genai reuses for every chat.sendMessage() and chat.sendMessageStream() call on that chat. #19990 removed the chats.create() span, which was the only span reporting those values, and nothing took over. Chat spans have carried model and token counts but no request config since then.

Both google-genai instrumentation paths are fixed:

  • instrumentGoogleGenAIClient, the client proxy, used by @sentry/cloudflare and @sentry/vercel-edge and available for manual wrapping.
  • googleGenAIIntegration, the diagnostics-channel integration, which is the default for Node, Bun, Deno, Astro, AWS Lambda and Google Cloud Functions.

Only the first path was in the original report, but both build their attributes from the per-message arguments alone, so both lost the same data.

Decisions

The config is read from the chat instance, not captured at create time. @google/genai stores config as a plain property on the Chat object, and both paths already hold that object: the proxy passes it as the instrumented method's context, and the channel path receives it as data.self. extractModel() already recovers the model the same way. Carrying the chats.create() arguments forward instead would have meant threading state through createDeepProxy, which fixes only the proxy path and moves that function away from its openai and anthropic-ai counterparts that #19990 deliberately converged. The cost is a dependency on an internal field name, which this file already accepts for model / modelVersion.

A per-message config replaces the chat config, it does not merge into it. The SDK resolves the request as params.config ?? chat.config, so a message that carries its own config sends only that config. The span mirrors that. Merging key by key would report a create-time maxOutputTokens alongside a per-message temperature and describe a request that was never sent.

The chat history stays off the message spans. The SDK does send it, folded into contents, and the instance carries the whole transcript, but repeating every past turn on every message span duplicates what earlier spans already reported and grows without bound. gen_ai.request.messages keeps just the message being sent.

Non-chat calls are unaffected. models.generateContent and models.embedContent have no chat instance, so they resolve their config from their own arguments exactly as before.

Fixes #20086

AI assistance (Claude, Anthropic) was used in developing this change. The design, review and verification were done by the author.

@zkasuran
zkasuran requested a review from a team as a code owner August 12, 2026 06:50
@zkasuran
zkasuran requested review from logaretm and stephanie-anderson and removed request for a team August 12, 2026 06:50

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f1c434. Configure here.

Comment thread packages/server-utils/src/ai/google-genai/index.ts
@nicohrubec
nicohrubec requested review from nicohrubec and removed request for stephanie-anderson August 12, 2026 08:06
zkasuran and others added 2 commits August 13, 2026 08:29
…ssage spans

Removing the chats.create() span dropped the config it captured (temperature,
top_p, top_k, max_tokens, frequency_penalty, presence_penalty, available_tools
and system_instructions). That config is set once on the chat instance and reused
for every chat.sendMessage() and chat.sendMessageStream() call, so those spans
lost it and the trace no longer showed the chat configuration.

Capture the params at chats.create() time and weld model plus config onto each
message span. The create-time config is the default and a per-message config
overrides it key by key. The create history is left off the message spans.

Fixes getsentry#20086

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on chat spans

@google/genai resolves each request's config as `params.config ?? chat.config`, so a
per-message config given to chat.sendMessage() or chat.sendMessageStream() replaces the
create-time config wholesale rather than merging with it. The previous shallow merge welded
create-time fields such as systemInstruction, tools and sampling settings onto message spans
that did not actually send them, over-reporting what the request carried.

Fall back to the create-time config only when the message carries no config of its own. Lock
the corrected attributes in the per-message config test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zkasuran
zkasuran force-pushed the fix/google-genai-chat-config-attrs branch from 35019b0 to ab1b14d Compare August 13, 2026 03:00
@github-actions

Copy link
Copy Markdown
Contributor

👋 @logaretm, @nicohrubec — Please review this PR when you get a chance!

3 similar comments
@github-actions

Copy link
Copy Markdown
Contributor

👋 @logaretm, @nicohrubec — Please review this PR when you get a chance!

@github-actions

Copy link
Copy Markdown
Contributor

👋 @logaretm, @nicohrubec — Please review this PR when you get a chance!

@github-actions

Copy link
Copy Markdown
Contributor

👋 @logaretm, @nicohrubec — Please review this PR when you get a chance!

Two conflicts, both in the google-genai instrumentation that develop moved under us.

packages/server-utils/src/ai/google-genai/index.ts: develop added low-cardinality
span names when span streaming is on (getsentry#23573) and dropped the captureException
calls from the instrumentation (getsentry#23024), touching the same lines where this branch
threads the chat create-time params through. Kept both: the merged apply() computes
attributeParams via mergeChatCreateParams, feeds those to extractRequestAttributes
plus addPrivateRequestAttributes, then derives model with develop's || 'unknown' and
its spanName sentinel logic.

packages/server-utils/test/ai/lib/tracing/google-genai.test.ts: add/add, develop
landed a span-names suite at the same path this branch used for the config suite.
Took develop's file whole and re-added the config suite beside it, hoisting the
shared setupClient to module scope and switching the config assertions from
spanToJSON to spanToStaticSpanJSON, since spanToJSON now returns the streamed shape
(attributes, no data).

Also updated the Cloudflare integration test. Its chat span assertion matches
attributes exhaustively with toEqual, while that scenario passes a config to
chats.create, so propagating it adds temperature, top_p and max_tokens to the chat
span. Verified the assertion fails without those three keys and passes with them.
The node suites assert per key, so they were unaffected.

Verified: @sentry/server-utils 432 tests passing (44 files), node google-genai and
google-genai-v2 integration 24 passing, cloudflare google-genai integration 1
passing, oxfmt --check, oxlint --type-aware, oxlint src --type-aware --type-check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zkasuran
zkasuran requested a review from a team as a code owner August 28, 2026 15:44
@zkasuran
zkasuran requested review from andreiborza and isaacs and removed request for a team August 28, 2026 15:44
@isaacs

isaacs commented Aug 28, 2026

Copy link
Copy Markdown
Member

Sorry for the delay, @zkasuran! Taking a look at this now.

@isaacs isaacs changed the title fix(server-utils): Propagate chats.create() config to google-genai message spans fix(server-utils): Restore request config attributes on google-genai chat spans Aug 28, 2026
@isaacs
isaacs enabled auto-merge (squash) August 28, 2026 20:00
@isaacs

isaacs commented Aug 28, 2026

Copy link
Copy Markdown
Member

Thanks for sending this fix!

There were a few issues, but fairly easy to address in the fixup. Will squash and land as soon as CI approves.

Basically, the fix here was missing the default instrumentation path for some platforms. As a consequence, a Cloudflare Worker gets the restored attributes and a Node app on the default integration would not. Fixed in the fixup commit that I pushed to your branch.

I also updated the PR description to match.

@isaacs
isaacs merged commit fade8e2 into getsentry:develop Aug 28, 2026
361 of 363 checks passed
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.

Propagate chat config attributes to chat.sendMessage()/chat.sendMessageStream() spans for Google GenAI

2 participants