Repository navigation
fix(openai): project aggregated citations to top-level field instead of leaking transformer_metadata - #2572
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughThe aggregator now serializes deduplicated, sorted citations in the top-level ChangesCitation serialization
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to This change moves aggregated citations into the top-level response field and leaves citation-free output unchanged. Tests cover the new shape, so no merge-blocking risk is evident. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change aligns aggregated citations with the existing response format without changing their source or granting new permissions. Risk is limited, but downstream consumers of stored response bodies were not fully verified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…of leaking transformer_metadata When chat completion streams carry provider citations (Perplexity / OpenRouter style), AggregateStreamChunks collected them into llm.Response.TransformerMetadata and marshaled the unified response directly as the client body. The wire shape therefore contained the internal transformer_metadata envelope — a field documented as never serialized — and no top-level citations, while streaming chunks and the direct non-streaming path (ResponseFromLLM) both expose top-level citations. Non-streaming clients on stream-required channels and the persisted request-log bodies received the wrong shape. Marshal a thin client-facing wrapper that projects the collected, deduplicated citations back to the top-level citations field and never serializes the internal envelope. Streams without citations produce byte-identical output.
f0e28a8 to
4af1197
Compare
|
@coderabbitai review Please review current head The contributor's unique aggregator fix is preserved. Regression inputs now exercise unsorted, duplicated citations, and the citation-free test asserts the exact unchanged response body. No shared response metadata tags or persistence readers were changed. Validation:
Local build and lint commands were not run, per repository rules. |
|
…of leaking transformer_metadata (looplj#2572) When chat completion streams carry provider citations (Perplexity / OpenRouter style), AggregateStreamChunks collected them into llm.Response.TransformerMetadata and marshaled the unified response directly as the client body. The wire shape therefore contained the internal transformer_metadata envelope — a field documented as never serialized — and no top-level citations, while streaming chunks and the direct non-streaming path (ResponseFromLLM) both expose top-level citations. Non-streaming clients on stream-required channels and the persisted request-log bodies received the wrong shape. Marshal a thin client-facing wrapper that projects the collected, deduplicated citations back to the top-level citations field and never serializes the internal envelope. Streams without citations produce byte-identical output.
Problem
When chat completion streams carry provider citations (Perplexity /
OpenRouter style, top-level
citationson each chunk),AggregateStreamChunkscollects them intollm.Response.TransformerMetadata["citations"]and marshals the unifiedllm.Responsedirectly as the response body. The wire shape thereforecontains the internal envelope:
{"id":"chatcmpl-123",...,"transformer_metadata":{"citations":["https://..."]}}and no top-level
citations— while the streaming chunks themselves andthe direct non-streaming path (
ResponseFromLLM, which extracts citationsfrom
TransformerMetadatainto the top-level field) both exposetop-level
citations. TheTransformerMetadatafield is documented as"ignored when serializing to JSON and is only used internally by
transformers"; the aggregator is the one place that marshals the unified
response verbatim, so the internal envelope leaks to clients.
Two caller-visible consequences:
(
autoAggregateStream) receives citations in a shape no OpenAI clientreads — the citations are effectively lost.
records the internal envelope instead of the API shape; re-parsing it
through
ToLLMResponse(which reads top-levelcitations) loses them.Fix
Keep collecting and deduplicating citations as today, then marshal a thin
client-facing wrapper that projects them back to the top-level
citationsfield. The internal envelope is never serialized. Streamswithout citations produce byte-for-byte identical output.
Note on the existing test
TestAggregateStreamChunks_WithCitationspreviously asserted the leakedshape (citations under
transformer_metadataafter a JSON round-trip).It pinned the bug rather than a contract: the field's own documentation
says it is never serialized, and
ResponseFromLLMis the codebase'ssanctioned unified→wire projection, which places citations top-level. The
test now asserts the corrected shape; its content assertions are
unchanged.
Testing
aggregator_citations_test.go: citations spread across chunks arededuplicated, sorted, and emitted top-level; the body contains no
transformer_metadata; content/finish_reason/usage intact. A secondtest guards that citation-free streams keep byte-identical shape. The
main test fails on the base commit with the leaked envelope visible in
the output.
go test ./transformer/openai/...— pass.go test ./...(llm module) — pass except the pre-existingWindows-only
TestWebSocketStreamReturnsErrorWhenReusedConnectionClosesBeforeEventfailure in
openai/responses, which fails identically on the cleanbase and is unrelated to this change.
go vet ./...— clean.Summary by CodeRabbit
citationsfield when citations are present.citationsfield.