Skip to content

refactor: remove the signature prefix marker to improve pass through#1593

Merged
looplj merged 1 commit into
unstablefrom
dev-tmp
May 7, 2026
Merged

refactor: remove the signature prefix marker to improve pass through#1593
looplj merged 1 commit into
unstablefrom
dev-tmp

Conversation

@looplj

@looplj looplj commented May 4, 2026

Copy link
Copy Markdown
Owner

No description provided.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request refactors signature handling by removing AccountIdentity and footprint-based prefixing across multiple transformers, replacing it with a heuristic-based provider detection in shared/signature.go. Feedback identifies a potential regression in ClaudeCodeTransformer where user ID injection is now disabled, a placeholder in a comment, a redundant check in the provider guessing logic, and a request for better documentation of protobuf wire type heuristics.

}

reqCopy = injectFakeUserIDStructured(ctx, reqCopy, t.accountIdentity)
reqCopy = injectFakeUserIDStructured(ctx, reqCopy, "")

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.

medium

The accountIdentity field was removed from the ClaudeCodeTransformer struct, and as a result, injectFakeUserIDStructured is now called with an empty string. This likely disables the user ID injection functionality that was previously tied to the channel's identity. If this was intentional as part of the refactor, consider removing the function call entirely to simplify the code. If the functionality is still required, the identity should be retained in the struct.

Comment thread llm/transformer/shared/signature.go Outdated

// GuessSignatureProvider guesses which AI provider a raw base64 blob belongs to.
//
// Heuristics (from xx.md):

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.

medium

The comment contains a placeholder reference xx.md. Please update it to point to the correct documentation or remove the reference if it's no longer needed.

Suggested change
// Heuristics (from xx.md):
// Heuristics:

Comment thread llm/transformer/shared/signature.go Outdated
}
}

if isBase64Url && !strings.ContainsAny(s, "+/") {

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.

medium

The check !strings.ContainsAny(s, "+/") is redundant because isBase64Url (which is set to the result of isBase64UrlString(s)) already ensures that the string only contains characters valid for base64url encoding, which excludes + and /.

Suggested change
if isBase64Url && !strings.ContainsAny(s, "+/") {
if isBase64Url {

Comment thread llm/transformer/shared/signature.go Outdated
Comment on lines +163 to +165
switch bytes[0] {
case 0x0a, 0x12, 0x1a:
return true

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.

medium

It would be helpful to add a comment explaining that these hex values (0x0a, 0x12, 0x1a) correspond to common protobuf field tags (field numbers 1, 2, and 3 with wire type 2). This provides context for why these specific bytes are used as a heuristic for identifying Gemini thought signatures.

@greptile-apps

greptile-apps Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the "signature prefix marker" mechanism, which previously embedded a per-channel footprint (derived from AccountIdentity = strconv.Itoa(c.ID)) into reasoning signatures via TransportScope. The new approach replaces footprint-based encoding/decoding with content-based provider detection (GuessSignatureProvider), where Anthropic signatures are identified by EqQ/Eqo/Eqr prefixes and Gemini signatures by protobuf structure. All transformers now emit Metadata: nil and AccountIdentity is removed from every config except ClaudeCode.

  • The integration test for "reasoning request" drops a lo.Filter that was previously stripping reasoning-type items from the expected payload before comparison — meaning reasoning items from prior turns now pass through in the outbound request, which is an important behavior change worth validating end-to-end.
  • DecodeAnthropicSignature now passes through any signature whose provider is Unknown (not just Anthropic), meaning a cross-provider signature that cannot be recognized will silently succeed rather than be dropped; conversely, DecodeGeminiThoughtSignature now only returns a signature identified as Gemini (dropping Unknown), which is the opposite policy.

Confidence Score: 4/5

Safe to merge with care — the behaviour changes around reasoning item pass-through and Unknown-signature handling are intentional but worth validating in a staging environment.

Only P2 findings in this review, but the PR carries significant behaviour changes (reasoning items now pass through into Responses API payloads, all provider-signature round-trips now rely on content-based heuristics rather than per-channel footprints) that warrant careful staging validation. Previous review threads flagged P1 concerns around looksLikeProto classification and ClaudeCode deterministic identity; the new looksLikeProto implementation is substantially more robust (full structural validation), but the overall risk profile of cross-provider signature routing keeps confidence at 4.

llm/transformer/shared/signature.go (GuessSignatureProvider heuristics — new trust anchor for all cross-provider routing), llm/transformer/openai/responses/integration_test.go (reasoning item pass-through behaviour change), llm/transformer/gemini/outbound_convert.go (Unknown-signature fallback to ContextEngineeringThoughtSignature)

Important Files Changed

Filename Overview
llm/transformer/shared/signature.go New file providing GuessSignatureProvider heuristics; Gemini detection relies on looksLikeProto which does full protobuf structural validation — replaces the old prefix-based approach.
llm/transformer/shared/anthropic.go Replaced footprint-prefix encode/decode with content-based provider detection; old DecodeAnthropicSignature(sig, footprint) removed, new version passes through if provider is Anthropic or Unknown.
llm/transformer/shared/gemini.go Simplified: EncodeGeminiThoughtSignature is now a passthrough; DecodeGeminiThoughtSignature only returns a value when GuessSignatureProvider identifies Gemini — Unknown signatures are now dropped.
internal/server/biz/channel_llm.go AccountIdentity removed from all outbound configs except ClaudeCode channels where it is correctly kept as strconv.Itoa(c.ID) for deterministic user_id generation.
llm/pipeline/non_streaming.go Removed TransportScope injection from pipeline context; metadata is no longer propagated to response transformers since Metadata is always nil now.
llm/transformer/anthropic/outbound_convert.go prepareAnthropicReasoning, convertMessages and related helpers all drop scope parameter; decoding now uses GuessSignatureProvider-based DecodeAnthropicSignature.
llm/transformer/gemini/outbound_convert.go Scope removed from all convert functions; old fallback path (pass through unknown signature when footprint=="") replaced by strict GuessSignatureProvider-based detection.
llm/transformer/openai/responses/outbound_convert.go convertAssistantMessage now uses DecodeOpenAIEncryptedContent without scope; passes through Unknown and OpenAI signatures as encrypted_content, drops Anthropic/Gemini.
llm/transformer/openai/responses/integration_test.go Removed filter that stripped reasoning items from the expected request fixture — reasoning items now pass through in outbound payload, a notable behaviour change.
llm/transformer/gemini/thinking_signature.go setOutboundToolCallThoughtSignature and getOutbountGeminiToolCallThoughtSignature simplified; scope.Footprint()=="" pass-through fallback removed, Unknown signatures are now dropped.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ReasoningSignature blob] --> B{GuessSignatureProvider}
    B -->|starts with gAAAA / gAAA| C[ProviderOpenAI]
    B -->|starts with EqQ / Eqo / Eqr| D[ProviderAnthropic]
    B -->|std base64 AND looksLikeProto| E[ProviderGemini]
    B -->|anything else| F[ProviderUnknown]

    C -->|DecodeAnthropicSignature| G[nil - rejected]
    D -->|DecodeAnthropicSignature| H[raw value - accepted]
    E -->|DecodeAnthropicSignature| G
    F -->|DecodeAnthropicSignature| H

    C -->|DecodeGeminiThoughtSignature| I[nil - rejected]
    D -->|DecodeGeminiThoughtSignature| I
    E -->|DecodeGeminiThoughtSignature| J[raw value - accepted]
    F -->|DecodeGeminiThoughtSignature| I

    C -->|DecodeOpenAIEncryptedContent| K[raw value - accepted]
    D -->|DecodeOpenAIEncryptedContent| L[nil - rejected]
    E -->|DecodeOpenAIEncryptedContent| L
    F -->|DecodeOpenAIEncryptedContent| K
Loading

Reviews (5): Last reviewed commit: "refactor: remove the signature prefix ma..." | Re-trigger Greptile

Comment thread llm/transformer/shared/signature.go Outdated
Comment thread llm/transformer/anthropic/claudecode/outbound.go Outdated
Comment thread llm/transformer/gemini/openai/outbound_test.go Outdated
@looplj looplj force-pushed the dev-tmp branch 3 times, most recently from 5130c80 to 8fc996f Compare May 4, 2026 08:01
@looplj looplj merged commit 4af1eb7 into unstable May 7, 2026
4 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