Skip to content

opt(llm): thinking signature encode with channel footprint, close #1035#1066

Merged
looplj merged 2 commits intorelease/v0.9.xfrom
dev-tmp-bak
Mar 19, 2026
Merged

opt(llm): thinking signature encode with channel footprint, close #1035#1066
looplj merged 2 commits intorelease/v0.9.xfrom
dev-tmp-bak

Conversation

@looplj
Copy link
Copy Markdown
Owner

@looplj looplj commented Mar 15, 2026

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness of LLM thinking signatures by embedding a channel-specific identifier, or 'footprint,' into them. This change ensures that reasoning content and encrypted data are correctly attributed and processed, preventing potential conflicts or misinterpretations when messages are transformed or passed between different LLM channels or providers. The footprint is propagated through the request context and integrated into the encoding and decoding logic of various transformer types.

Highlights

  • Channel Footprint Integration: Introduced a 'channel footprint' mechanism to LLM thinking signatures across Anthropic, Gemini, and OpenAI Responses transformers. This footprint, derived from the channel's base URL and ID, is embedded into reasoning signatures to prevent cross-channel signature conflicts and ensure correct attribution.
  • Context Propagation: The channel footprint is now propagated through the LLM processing pipeline via context.Context, ensuring that all relevant transformer operations have access to the channel's unique identifier.
  • Signature Encoding and Decoding Updates: Modified shared utility functions for Anthropic, Gemini, and OpenAI signatures to incorporate and validate the new channel footprint during encoding and decoding, enhancing the robustness of reasoning content handling.
  • New Footprint Utilities: Added new utility files (footprint.go and footprint_context.go) to manage the computation, validation, and context-based propagation of the channel footprint.
  • Comprehensive Test Coverage: Expanded test suites across various transformers and shared utilities to validate the correct generation, propagation, encoding, decoding, and cross-footprint rejection of the new channel-specific thinking signatures.
Changelog
  • internal/server/biz/channel_llm.go
    • Imported the strconv package.
    • Added accountIdentity variable by converting channel ID to string.
    • Propagated accountIdentity to various LLM transformer configurations (Anthropic, Codex, Gemini, OpenAI Responses).
  • internal/server/biz/channel_llm_codex_oauth_test.go
    • Imported strconv and shared packages.
    • Added assertions to verify the presence and correctness of the channel footprint in outbound requests' metadata.
  • llm/pipeline/non_streaming.go
    • Imported the shared package.
    • Added logic to extract the channel footprint from request metadata and propagate it into the context.
  • llm/pipeline/stream.go
    • Imported the shared package.
    • Added logic to extract the channel footprint from request metadata and propagate it into the context.
  • llm/transformer/anthropic/claudecode/outbound.go
    • Added AccountIdentity field to the Params struct.
    • Passed params.AccountIdentity to the Anthropic outbound transformer configuration.
  • llm/transformer/anthropic/outbound.go
    • Imported the shared package.
    • Added AccountIdentity field to the Config struct.
    • Modified TransformRequest to compute and attach a channel footprint to HTTP requests.
    • Updated TransformResponse to retrieve the channel footprint from the context.
    • Adjusted API key retrieval logic to always attempt to get the key, regardless of platform type.
  • llm/transformer/anthropic/outbound_convert.go
    • Modified several message conversion functions to accept and utilize the footprint parameter.
    • Updated calls to IsAnthropicSignatureWithFootprint and DecodeAnthropicSignature to use the footprint.
    • Removed the IsAnthropicRedactedContent check from relevant functions.
  • llm/transformer/anthropic/outbound_convert_test.go
    • Updated test calls to convertToLlmResponse and convertToAnthropicRequestWithConfig to include the footprint parameter.
    • Adjusted TestOutboundConvert_GeminiThoughtSignatureBecomesAnthropicRedactedThinking to correctly handle Gemini signatures as redacted thinking content.
  • llm/transformer/anthropic/outbound_stream.go
    • Imported the shared package.
    • Modified TransformStream to retrieve the footprint from context and pass it to the streaming state.
    • Added a footprint field to the streamState struct.
    • Updated transformStreamChunk to use the stream state's footprint for signature encoding.
  • llm/transformer/anthropic/outbound_stream_delta_test.go
    • Updated test setups to use NewOutboundTransformerWithConfig and include AccountIdentity.
    • Added shared.WithFootprint to test contexts for footprint propagation.
  • llm/transformer/anthropic/outbound_stream_test.go
    • Updated test setups to use NewOutboundTransformerWithConfig and include AccountIdentity.
    • Added shared.WithFootprint to test contexts for footprint propagation.
  • llm/transformer/anthropic/outbound_test.go
    • Imported the shared package.
    • Added TestOutboundTransformer_TransformRequest_AccountIdentityFootprint to verify footprint generation and attachment.
  • llm/transformer/anthropic/thinking_test.go
    • Updated test calls to convertToLlmResponse and convertToAnthropicRequestWithConfig to include the footprint parameter.
    • Modified TestOutboundConvert_GeminiThoughtSignatureBecomesAnthropicRedactedThinking to correctly assert Gemini thought signature conversion.
    • Updated EncodeAnthropicSignature calls to include the footprint parameter.
  • llm/transformer/gemini/image.go
    • Streamlined API key retrieval by removing a redundant nil check for APIKeyProvider.
  • llm/transformer/gemini/inbound_convert_test.go
    • Updated test calls to convertGeminiToLLMResponse to include the footprint parameter.
  • llm/transformer/gemini/openai/outbound.go
    • Added AccountIdentity field to Config and OutboundTransformer structs.
    • Modified TransformRequest to compute and attach a channel footprint to HTTP requests.
  • llm/transformer/gemini/openai/outbound_test.go
    • Added TestOutboundTransformer_TransformRequest_AccountIdentityFootprint to verify footprint generation and attachment.
    • Added TestOutboundTransformer_TransformRequest_OmitsFootprintWhenEmpty to verify footprint omission when empty.
  • llm/transformer/gemini/outbound.go
    • Imported the shared package.
    • Added AccountIdentity field to the Config struct.
    • Modified TransformRequest to retrieve API key, compute and attach a channel footprint to HTTP requests, and pass it to message conversion.
    • Updated TransformResponse to retrieve the footprint from context and pass it to convertGeminiToLLMResponse.
  • llm/transformer/gemini/outbound_convert.go
    • Modified several message conversion functions to accept and utilize the footprint parameter.
    • Updated calls to DecodeGeminiThoughtSignature and EncodeGeminiThoughtSignature to their footprint-aware counterparts.
  • llm/transformer/gemini/outbound_convert_test.go
    • Updated test calls to message conversion functions to include the footprint parameter.
  • llm/transformer/gemini/outbound_stream.go
    • Imported the shared package.
    • Modified TransformStream and TransformStreamChunk to retrieve the footprint from context and pass it to the streaming state.
    • Added a footprint field to the streamState struct.
    • Updated convertGeminiToLLMResponseWithState calls to use the stream state's footprint.
  • llm/transformer/gemini/outbound_stream_test.go
    • Updated test calls to convertGeminiToLLMResponse to include the footprint parameter.
  • llm/transformer/gemini/outbound_test.go
    • Imported the shared package.
    • Added TestOutboundTransformer_TransformRequest_AccountIdentityFootprint to verify footprint generation and attachment.
    • Added TestOutboundTransformer_TransformRequest_OmitsFootprintWhenEmpty to verify footprint omission when empty.
  • llm/transformer/openai/codex/outbound.go
    • Imported the auth package.
    • Added AccountIdentity field to the Params struct.
    • Modified NewOutboundTransformer to pass AccountIdentity to the underlying responses transformer configuration.
  • llm/transformer/openai/outbound.go
    • Imported the shared package.
    • Added AccountIdentity field to the Config struct.
    • Modified TransformRequest to compute and attach a channel footprint to HTTP requests.
  • llm/transformer/openai/responses/outbound.go
    • Added AccountIdentity field to the Config struct.
    • Modified TransformRequest to compute and attach a channel footprint to HTTP requests, and pass it to message input conversion.
    • Updated TransformResponse to retrieve the footprint from context and use it for encoding encrypted content.
  • llm/transformer/openai/responses/outbound_convert.go
    • Modified convertInputFromMessages and convertAssistantMessage to accept and utilize the footprint parameter.
    • Updated calls to DecodeOpenAIEncryptedContent to DecodeOpenAIEncryptedContentWithFootprint.
  • llm/transformer/openai/responses/outbound_convert_test.go
    • Updated test calls to convertInputFromMessages to include the footprint parameter.
  • llm/transformer/openai/responses/outbound_stream.go
    • Modified TransformStream to retrieve the footprint from context and pass it to the streaming state.
    • Added a footprint field to the outboundStreamState struct.
    • Updated transformStreamChunk to use the stream state's footprint for signature encoding.
  • llm/transformer/openai/responses/outbound_test.go
    • Added TestOutboundTransformer_TransformRequest_AccountIdentityFootprint to verify footprint generation and attachment.
    • Added TestOutboundTransformer_TransformRequest_OmitsFootprintWhenEmpty to verify footprint omission when empty.
  • llm/transformer/shared/README.md
    • Updated documentation to describe the new footprint-aware prefixes for Anthropic, Gemini, and OpenAI signatures.
  • llm/transformer/shared/anthropic.go
    • Introduced parseAnthropicSignaturePrefix to handle both standard and footprint-aware prefixes.
    • Modified IsAnthropicSignature, DecodeAnthropicSignature, EncodeAnthropicSignature to be footprint-aware.
    • Added IsAnthropicSignatureWithFootprint function.
    • Removed IsAnthropicRedactedContent function.
  • llm/transformer/shared/anthropic_test.go
    • Added testFootprint constant.
    • Expanded TestIsAnthropicSignature to include footprint-aware signatures.
    • Added TestIsAnthropicSignatureForFootprint for specific footprint matching tests.
    • Updated TestDecodeAnthropicSignature and TestEncodeAnthropicSignature to include footprint parameters.
    • Added TestAnthropicSignature_Base64Validity and TestAnthropicSignature_CrossFootprintRejection.
    • Removed TestIsAnthropicRedactedContent tests.
  • llm/transformer/shared/constants.go
    • Added AnthropicSignatureFootprintPrefix, GeminiThoughtSignatureFootprintPrefix, and OpenAIEncryptedContentFootprintPrefix constants.
  • llm/transformer/shared/footprint.go
    • Added new file to compute a 6-character hexadecimal footprint from a base URL and account identity.
    • Included isFootprintHex6 for footprint validation.
  • llm/transformer/shared/footprint_context.go
    • Added new file to provide context-based propagation for the channel footprint using WithFootprint and GetFootprint.
  • llm/transformer/shared/footprint_test.go
    • Added new file with tests for ComputeFootprint to verify determinism and format.
  • llm/transformer/shared/gemini.go
    • Introduced parseGeminiThoughtSignaturePrefix to handle both standard and footprint-aware prefixes.
    • Modified geminiThoughtSignaturePrefixLength, IsGeminiThoughtSignature, DecodeGeminiThoughtSignature to be footprint-aware.
    • Added IsGeminiThoughtSignatureWithFootprint, DecodeGeminiThoughtSignatureWithFootprint, EncodeGeminiThoughtSignatureWithFootprint, and NormalizeGeminiThoughtSignatureWithFootprint functions.
  • llm/transformer/shared/gemini_test.go
    • Added testGeminiFootprint constant.
    • Expanded TestIsGeminiThoughtSignature and TestDecodeGeminiThoughtSignature to include footprint-aware signatures.
    • Added TestEncodeDecodeGeminiThoughtSignatureWithFootprint for comprehensive testing.
    • Updated TestStripGeminiThoughtSignaturePrefix to handle new footprint prefixes.
    • Updated TestGeminiThoughtSignatureWholeValueCanDecodeAsBase64 to include footprint-aware signatures.
  • llm/transformer/shared/openai.go
    • Introduced parseOpenAIEncryptedContentPrefix to handle both standard and footprint-aware prefixes.
    • Modified IsOpenAIEncryptedContent, DecodeOpenAIEncryptedContent to be footprint-aware.
    • Added IsOpenAIEncryptedContentWithFootprint, DecodeOpenAIEncryptedContentWithFootprint, and EncodeOpenAIEncryptedContentWithFootprint functions.
  • llm/transformer/shared/openai_test.go
    • Added testOpenAIFootprint constant.
    • Expanded TestIsOpenAIEncryptedContent and TestDecodeOpenAIEncryptedContent to include footprint-aware content.
    • Added TestEncodeDecodeOpenAIEncryptedContentWithFootprint and TestOpenAIEncryptedContentWholeValueCanDecodeAsBase64.
Activity
  • No human activity has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a channel footprint mechanism to disambiguate thinking signatures from different channels, which is a great enhancement for multi-channel routing. The implementation is comprehensive, touching many transformers to propagate the channel identity and using it to create a unique footprint.

I've found a few issues in the shared signature handling logic that could lead to incorrect behavior when decoding signatures, particularly with how wildcard footprints are handled. Additionally, there's a potential for a nil pointer dereference in one of the Gemini transformers.

My review includes suggestions to fix these issues and improve the robustness of the new footprinting feature.

APIKey: apiKey,
HeaderKey: "x-goog-api-key",
}
apiKey := t.config.APIKeyProvider.Get(ctx)
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.

high

This direct call to t.config.APIKeyProvider.Get(ctx) could cause a panic if APIKeyProvider is nil. While the current usage in channel_llm.go ensures it's not nil, it's safer for the transformer to be self-contained and robust against being initialized with a nil provider. Please add a nil check for t.config.APIKeyProvider before calling Get.

Comment on lines +69 to +75
if embeddedFootprint == "" {
if footprint != "" {
return nil
}
} else if embeddedFootprint != footprint {
return nil
}
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.

high

The logic here for handling a wildcard footprint seems incorrect. If footprint is an empty string (wildcard), but the signature has an embeddedFootprint, this function will incorrectly return nil. This would prevent decoding of any footprinted signature when a specific footprint isn't required.

A better approach would be to only perform the footprint match when the provided footprint is not empty.

    if footprint != "" && embeddedFootprint != footprint {
        return nil
    }

Comment on lines +88 to +94
if embeddedFootprint == "" && footprint != "" {
return nil
}

if embeddedFootprint != "" && embeddedFootprint != footprint {
return nil
}
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.

high

Similar to my comment on anthropic.go, the logic for handling a wildcard footprint in DecodeGeminiThoughtSignatureWithFootprint is incorrect. It will fail to decode a signature that has a footprint when the caller doesn't specify one (i.e., provides an empty string as a wildcard).

To fix this and align with the wildcard behavior, I suggest simplifying the validation logic. The check should only fail if a specific footprint is provided and it doesn't match the embeddedFootprint.

Suggested change
if embeddedFootprint == "" && footprint != "" {
return nil
}
if embeddedFootprint != "" && embeddedFootprint != footprint {
return nil
}
if footprint != "" && embeddedFootprint != footprint {
return nil
}

Comment on lines +77 to +83
if embeddedFootprint == "" && footprint != "" {
return nil
}

decoded := (*content)[len(OpenAIEncryptedContentPrefix):]
if embeddedFootprint != "" && embeddedFootprint != footprint {
return nil
}
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.

high

This DecodeOpenAIEncryptedContentWithFootprint function has the same logical issue as the other decode functions in this PR regarding wildcard footprints. When footprint is an empty string, it should successfully decode a signature regardless of whether it has an embedded footprint. The current implementation will incorrectly fail in this scenario.

To ensure correct wildcard behavior, please simplify the validation to only enforce a match when a non-empty footprint is provided.

Suggested change
if embeddedFootprint == "" && footprint != "" {
return nil
}
decoded := (*content)[len(OpenAIEncryptedContentPrefix):]
if embeddedFootprint != "" && embeddedFootprint != footprint {
return nil
}
if footprint != "" && embeddedFootprint != footprint {
return nil
}

@looplj
Copy link
Copy Markdown
Owner Author

looplj commented Mar 15, 2026

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new AccountIdentity field to LLM transformer configurations across various platforms (Anthropic, Gemini, OpenAI Responses, and Codex). This identity, derived from the channel ID, is used to generate a unique 'footprint' for each request. This footprint is then propagated through the request context and included in HTTP request metadata, enabling more precise tracking and handling of provider-specific reasoning signatures and encrypted content during transformations, especially when switching between different LLM providers within the same session. The changes involve updating configuration structs, modifying request/response transformation logic to compute and utilize this footprint, and updating related test cases to reflect these new parameters and assertions.

@looplj
Copy link
Copy Markdown
Owner Author

looplj commented Mar 16, 2026

@gemini-code-assist review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a "channel footprint" to the LLM thinking signature encoding mechanism. This is a significant refactoring across many transformer files to make signature handling scope-aware, which should improve robustness when switching between different LLM providers. The changes are extensive and appear consistent with the new tests added. I've found one critical issue that could lead to a panic.

APIKey: apiKey,
HeaderKey: "x-goog-api-key",
}
apiKey := t.config.APIKeyProvider.Get(ctx)
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.

critical

The nil check for t.config.APIKeyProvider was removed before calling .Get(ctx). If APIKeyProvider is nil, this will cause a panic. It's safer to restore the nil check to prevent a potential nil pointer dereference.

For example:

if t.config.APIKeyProvider != nil {
    apiKey := t.config.APIKeyProvider.Get(ctx)
    if apiKey != "" {
        auth = &httpclient.AuthConfig{
            Type:      "api_key",
            APIKey:    apiKey,
            HeaderKey: "x-goog-api-key",
        }
    }
}

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

@looplj looplj merged commit c3a3aed into release/v0.9.x Mar 19, 2026
2 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.

1 participant