signature

package
v7.2.88 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Claude thinking signature validation.

Spec reference: SIGNATURE-CHANNEL-SPEC.md

Encoding detection (Spec section 3)

Claude signatures use base64 encoding in one or two layers. The raw string's first character determines the encoding depth. This is mathematically equivalent to the spec's "decode first, check byte" approach:

  • E prefix: single-layer, payload[0] == 0x12, first 6 bits = 000100, base64 index 4 = E.
  • R prefix: double-layer, inner[0] == E (0x45), first 6 bits = 010001, base64 index 17 = R.

Valid signatures can be normalized to R-form (double-layer base64) before sending to the Antigravity backend.

Protobuf structure (Spec sections 4.1 and 4.2) in strict mode only

After base64 decoding to raw bytes, the first byte must be 0x12:

Top-level protobuf
|- Field 2 (bytes): container                    -> extractClaudeBytesField(payload, 2)
|  |- Field 1 (bytes): channel block             -> extractClaudeBytesField(container, 1)
|  |  |- Field 1 (varint): channel_id [required] -> routing_class (11 | 12)
|  |  |- Field 2 (varint): infra [optional]      -> infrastructure_class (aws=1 | google=2)
|  |  |- Field 3 (varint): version=2             -> skipped
|  |  |- Field 5 (bytes): ECDSA sig              -> skipped, per Spec section 11
|  |  |- Field 6 (bytes): model_text [optional]  -> schema_features
|  |  `- Field 7 (varint): unknown [optional]    -> schema_features
|  |- Field 2 (bytes): nonce 12B                 -> skipped
|  |- Field 3 (bytes): session 12B               -> skipped
|  |- Field 4 (bytes): SHA-384 48B               -> skipped
|  `- Field 5 (bytes): metadata                  -> skipped, per Spec section 11
`- Field 3 (varint): =1                          -> skipped

Output dimensions (Spec section 8)

routing_class:        routing_class_11 | routing_class_12 | unknown
infrastructure_class: infra_default (absent) | infra_aws (1) | infra_google (2) | infra_unknown
schema_features:      compact_schema (len 70-72, no f6/f7) | extended_model_tagged_schema (f6 exists) | unknown
legacy_route_hint:    only for ch=11, legacy_default_group | legacy_aws_group | legacy_vertex_direct/proxy

Compatibility

Verified against all confirmed spec samples (Anthropic Max 20x, Azure, Vertex, Bedrock) and legacy ch=11 signatures. Both single-layer (E) and double-layer (R) encodings are supported. Historical cache-mode modelGroup# prefixes are stripped.

CAIS envelope (newest Claude Code models)

Newer Claude Code models wrap the channel block in a CAIS envelope whose decoded payload starts with 0x08 (top-level field 1 varint) instead of 0x12, so the base64 string starts with 'C' instead of 'E'/'R'. The envelope version varint in top-level field 1 is the ONLY structural difference from the layout above; everything below it is unchanged.

The channel block itself belongs to a newer schema generation that is shared by both envelopes: channel_id 16, no infra field 2, plus a block kind (field 8) and a context id (field 11). Observed traffic confirms this schema appears under the classic 0x12 envelope too (opus-4-6/4-7/4-8, sonnet-5) and under the CAIS envelope (opus-5, fable-5), so envelope form and channel schema generation vary independently and must not be inferred from each other:

Top-level protobuf
|- Field 1 (varint): envelope version [required marker, observed as 2]
|- Field 2 (bytes): container [required]
|  `- Field 1 (bytes): channel block [required]
|     |- Field 1  (varint): channel_id [required, observed as 16]
|     |- Field 3  (varint): version [optional, observed as 2]
|     |- Field 5  (bytes):  ECDSA signature [required, observed as 64B]
|     |- Field 6  (bytes):  model_text [required, "claude-" prefixed]
|     |- Field 7  (varint): unknown [optional, observed as 1]
|     |- Field 8  (bytes):  block kind [optional, observed as "thinking"]
|     `- Field 11 (bytes):  context id [optional, canonical UUID]
`- Field 3 (varint): trailer [optional, observed as 1]

CAIS validation is structural rather than an exact replay of the observed bytes. The payload is an opaque upstream-issued blob and rejecting it drops the whole thinking block, so only the fields that actually identify the format are required: the 0x08 marker, the nested container/channel block, the signature bytes, and the "claude-" model text. Observed-but-incidental values such as channel_id 16 or the "thinking" block kind are recorded for debugging and checked only for wire type, so an upstream field bump cannot silently erase conversation history.

Which provider emits which envelope

Three providers serve Claude models, and the envelope depends on the model generation rather than on the provider:

  • Claude Code OAuth subscription (Claude Code Max): opus-4-5, sonnet-4-6 and every later model up to opus-5 and fable-5. Emits the CAIS envelope for the newest models (opus-5, fable-5) and the single-layer E envelope for the opus-4-6/4-7/4-8 and sonnet-5 generation — but both carry the same channel_id 16 channel schema, so only the envelope differs.
  • Claude Messages API: the full Claude model range, same envelopes as the Claude Code OAuth subscription.
  • Antigravity: only opus-4-6-think and sonnet-4-6, and always the double-layer R form on Google infrastructure (infra_google). Antigravity never issues a CAIS envelope or a single-layer E signature, and its replay path requires R form, so CompatibleAntigravityClaudeThinkingSignature rejects CAIS signatures.

A single conversation therefore mixes envelopes whenever a user switches model generations or providers, and every form must stay replayable toward the provider that issued it.

Gemini thought signature validation notes.

The Antigravity Gemini request translator can preserve provider-compatible Gemini thought signatures and uses the skip sentinel only for synthetic or incompatible model parts.

Gemini 3 and later models can return thoughtSignature on model content parts. Function-call parts are the strict case: when a model functionCall is replayed with a following functionResponse, Gemini validates that the original functionCall part still carries its provider-issued thoughtSignature. Text or other non-functionCall parts may also carry a signature; those should be preserved when replaying native Gemini history, but they are not the primary validation gate.

Synthetic history and migration from other model families are different. If a functionCall part was not produced by Gemini API, there is no real signature to preserve. Gemini documents two bypass sentinels for that case:

  • "skip_thought_signature_validator"
  • "context_engineering_is_the_way_to_go"

This repo emits "skip_thought_signature_validator" only when the first functionCall in a synthetic model turn lacks a compatible provider signature. Later parallel calls and ordinary text/thought parts preserve their native unsigned shape.

This validator is intentionally more conservative than a decrypting verifier. Claude has a known E/R base64 envelope and a protobuf tree in this package. Gemini thought signatures are opaque provider state here, so local validation checks only the transport-level protobuf envelope and leaves the wrapped provider payload uninterpreted.

Validation tiers:

  • Sentinel tier: accept the documented bypass sentinels only on the first model functionCall when it is synthetic, migrated, or otherwise not traceable to a prior Gemini model response in the same conversation.
  • Opaque-shape tier: for real Gemini signatures, require a non-empty string, bounded length, successful standard base64 decoding, and a known protobuf envelope when the caller needs provider compatibility. The only known envelope is the Gemini 3.x field-2 -> field-1 payload, whose body holds either versioned opaque state or a provider UUID. Gemini 2.5 emitted a repeated field-1 form; those models are out of scope and their signatures are no longer a known envelope. Bare base64 UUID payloads are classified separately and should be replaced with the bypass sentinel rather than replayed.
  • Replay tier: real validation means preserving the exact model part that came from Gemini, including its thoughtSignature, id/name/function args, part index, and ordering relative to sibling parallel function calls.
  • Tool pairing tier: functionResponse parts must match the preceding functionCall id/name and must not be interleaved between parallel calls. The valid shape is all model functionCalls first, then their responses.
  • Compatibility tier: GPT-compatible Gemini traffic stores the same state under tool_calls[].extra_content.google.thought_signature. If that path is translated back to native Gemini, the value must stay attached to the same assistant tool call.

Important non-goals:

  • Do not treat a Gemini thoughtSignature as a Claude signature. Similar base64 prefixes are not provenance.
  • Do not attach a signature to user functionResponse/tool-result parts.
  • Do not log complete signatures during validation failures; log only field paths, lengths, and redacted prefixes.
  • Do not preserve client-provided signatures across model/provider/session boundaries unless the request pipeline can prove they came from the same Gemini conversation state.

Index

Constants

View Source
const (
	MaxGeminiThoughtSignatureLen = 32 * 1024 * 1024

	GeminiSkipThoughtSignatureValidator = "skip_thought_signature_validator"
	GeminiContextEngineeringBypass      = "context_engineering_is_the_way_to_go"
)
View Source
const (
	// MaxGrokEncryptedContentLen is a transport safety cap for opaque replay blobs.
	MaxGrokEncryptedContentLen = 8 * 1024 * 1024
	// MinGrokEncryptedContentDecodedLen is a deliberately loose floor. The
	// shortest observed native payload is exactly 50 bytes (grok-composer-2.5-fast),
	// and those samples share no structure, so 50 is a sampling artifact rather
	// than a protocol minimum. Sitting on the observed floor would silently reject
	// a future shorter payload and surface as lost reasoning context, so keep
	// headroom here and let the entropy check do the real filtering.
	MinGrokEncryptedContentDecodedLen = 32
	// MinGrokEncryptedContentEntropyRatio rejects obvious non-ciphertext payloads.
	// Native samples are >= 0.892 against the sample-size entropy ceiling.
	MinGrokEncryptedContentEntropyRatio = 0.85
)
View Source
const MaxClaudeThinkingSignatureLen = 32 * 1024 * 1024
View Source
const MaxGPTReasoningSignatureLen = 32 * 1024 * 1024

Variables

This section is empty.

Functions

func CompatibleAntigravityClaudeThinkingSignature

func CompatibleAntigravityClaudeThinkingSignature(rawSignature string) (string, bool)

CompatibleAntigravityClaudeThinkingSignature returns the double-layer R-form required by Antigravity Claude replay. It only accepts signatures that are strictly identifiable as Claude, so Gemini E-prefixed envelopes cannot slip through the looser Antigravity bypass normalization path.

func CompatibleSignatureForProvider

func CompatibleSignatureForProvider(targetProvider SignatureProvider, rawSignature string) (string, bool)

CompatibleSignatureForProvider returns a replayable provider-native signature for targetProvider. It strips this repo's provider prefix and normalizes Claude signatures to the format expected by the target when possible.

func CompatibleSignatureForProviderBlock

func CompatibleSignatureForProviderBlock(targetProvider SignatureProvider, rawSignature string, blockKind SignatureBlockKind) (string, bool)

CompatibleSignatureForProviderBlock returns a replayable provider-native signature for targetProvider when the source block kind is known.

func GeminiReplaySignatureOrBypass

func GeminiReplaySignatureOrBypass(rawSignature string, blockKind SignatureBlockKind) string

GeminiReplaySignatureOrBypass returns a Gemini-replayable thoughtSignature. Compatible Gemini signatures are normalized and preserved. Missing, unknown, or cross-provider signatures are replaced with Gemini's bypass sentinel.

func HasClaudeThinkingSignaturePrefix

func HasClaudeThinkingSignaturePrefix(rawSignature string) bool

HasClaudeThinkingSignaturePrefix reports whether rawSignature has the Claude E/R signature prefix after stripping an optional cache prefix.

func HasDecodableClaudeThinkingSignature

func HasDecodableClaudeThinkingSignature(rawSignature string) bool

HasDecodableClaudeThinkingSignature reports whether rawSignature has the Claude E/R shape and its expected base64 layer(s) can be decoded.

func IsGeminiThoughtSignatureBypass

func IsGeminiThoughtSignatureBypass(rawSignature string) bool

IsGeminiThoughtSignatureBypass reports whether rawSignature is one of Gemini's documented bypass sentinels for synthetic or migrated function-call history.

func IsSignatureCompatibleWithProvider

func IsSignatureCompatibleWithProvider(targetProvider SignatureProvider, rawSignature string) bool

func IsValidClaudeCAISSignature added in v7.2.88

func IsValidClaudeCAISSignature(rawSignature string) bool

IsValidClaudeCAISSignature returns whether rawSignature is a valid Claude CAIS thinking signature.

func IsValidClaudeThinkingSignature

func IsValidClaudeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) bool

IsValidClaudeThinkingSignature returns whether rawSignature is a valid Claude thinking signature under the requested validation options.

func IsValidGPTReasoningSignature

func IsValidGPTReasoningSignature(rawSignature string) bool

func IsValidGeminiThoughtSignature

func IsValidGeminiThoughtSignature(rawSignature string, opts ...GeminiThoughtSignatureValidationOptions) bool

IsValidGeminiThoughtSignature returns whether rawSignature has a valid local Gemini thought-signature shape under opts.

func IsValidGrokEncryptedContent added in v7.2.49

func IsValidGrokEncryptedContent(raw string) bool

func NormalizeClaudeProviderNativeThinkingSignature

func NormalizeClaudeProviderNativeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) (string, error)

NormalizeClaudeProviderNativeThinkingSignature strips any cache prefix, validates the signature, and returns the single-layer E-form expected by Claude-native providers.

func NormalizeClaudeThinkingSignature

func NormalizeClaudeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) (string, error)

NormalizeClaudeThinkingSignature strips any cache prefix, validates the signature, and returns the double-layer R-form expected by Antigravity bypass mode.

func SanitizeGeminiRequestThoughtSignatures

func SanitizeGeminiRequestThoughtSignatures(payload []byte, contentsPath string) []byte

SanitizeGeminiRequestThoughtSignatures applies Gemini replay policy to a Gemini-shaped request. Existing provider signatures stay on their original model parts. Only a missing or incompatible first functionCall gets the bypass sentinel; unsigned sibling calls remain unsigned, matching native Gemini parallel-call history. functionResponse parts never carry signatures.

func SignaturePayloadWithoutProviderPrefix

func SignaturePayloadWithoutProviderPrefix(rawSignature string) string

SignaturePayloadWithoutProviderPrefix strips this repo's provider cache prefix when present. The returned string is the value that should be replayed to an upstream provider.

func StripInvalidClaudeThinkingBlocks

func StripInvalidClaudeThinkingBlocks(payload []byte, opts ...ClaudeSignatureValidationOptions) []byte

StripInvalidClaudeThinkingBlocks removes Claude thinking blocks whose signatures are empty or not valid Claude thinking signatures after stripping an optional cache prefix, unless the validation options allow an empty thinking placeholder.

func StripInvalidClaudeThinkingBlocksAndEmptyMessages

func StripInvalidClaudeThinkingBlocksAndEmptyMessages(payload []byte, opts ...ClaudeSignatureValidationOptions) []byte

StripInvalidClaudeThinkingBlocksAndEmptyMessages also removes messages whose content becomes empty after invalid thinking blocks are removed.

func ValidateClaudeThinkingSignatures

func ValidateClaudeThinkingSignatures(inputRawJSON []byte, opts ...ClaudeSignatureValidationOptions) error

ValidateClaudeThinkingSignatures validates every thinking block signature in a Claude messages payload.

func ValidateGeminiFunctionCallPairing

func ValidateGeminiFunctionCallPairing(inputRawJSON []byte) error

ValidateGeminiFunctionCallPairing validates the replay shape around Gemini functionCall and functionResponse parts. It checks id/name pairing and prevents response parts from being interleaved inside the same content as function calls. It allows a final pending functionCall group because callers may validate a freshly returned model step before tool outputs exist.

func ValidateGeminiThoughtSignatures

func ValidateGeminiThoughtSignatures(inputRawJSON []byte, opts ...GeminiThoughtSignatureValidationOptions) error

ValidateGeminiThoughtSignatures validates thoughtSignature fields in a Gemini native payload. The first functionCall in each model Content must have a valid provider signature or allowed synthetic sentinel. Later parallel sibling calls may be unsigned, but any signature they do carry must still be valid.

Types

type ClaudeCAISSignatureInfo added in v7.2.88

type ClaudeCAISSignatureInfo struct {
	FirstByte       byte
	EnvelopeVersion uint64
	ChannelID       uint64
	ModelText       string
	BlockKind       string
	ContextID       string

	SignatureLen int
}

ClaudeCAISSignatureInfo describes the locally inspected structure of a Claude CAIS thinking signature.

func InspectClaudeCAISSignature added in v7.2.88

func InspectClaudeCAISSignature(rawSignature string) (*ClaudeCAISSignatureInfo, error)

InspectClaudeCAISSignature decodes and validates a Claude CAIS thinking signature. See the CAIS envelope section in this file's package comment for the layout and for why validation is structural rather than exact.

type ClaudeMessagesSignatureSanitizeOptions

type ClaudeMessagesSignatureSanitizeOptions struct {
	TargetProvider                SignatureProvider
	TargetModel                   string
	DropEmptyMessages             bool
	DropToolSignatures            bool
	DropEmptyThinkingPlaceholders bool
}

type ClaudeSignatureTree

type ClaudeSignatureTree struct {
	EncodingLayers      int
	ChannelID           uint64
	Field2              *uint64
	RoutingClass        string
	InfrastructureClass string
	SchemaFeatures      string
	ModelText           string
	LegacyRouteHint     string
	HasField7           bool
}

ClaudeSignatureTree describes the protobuf fields currently used for Claude thinking signature routing.

func InspectClaudeDoubleLayerSignature

func InspectClaudeDoubleLayerSignature(sig string) (*ClaudeSignatureTree, error)

InspectClaudeDoubleLayerSignature decodes and inspects a double-layer Claude thinking signature.

func InspectClaudeSignaturePayload

func InspectClaudeSignaturePayload(payload []byte, encodingLayers int) (*ClaudeSignatureTree, error)

InspectClaudeSignaturePayload inspects the decoded Claude thinking signature protobuf payload.

func InspectClaudeSingleLayerSignature

func InspectClaudeSingleLayerSignature(sig string) (*ClaudeSignatureTree, error)

InspectClaudeSingleLayerSignature decodes and inspects a single-layer Claude thinking signature.

type ClaudeSignatureValidationOptions

type ClaudeSignatureValidationOptions struct {
	// PrefixOnly only checks for an optional cache prefix followed by an E/R
	// Claude signature prefix. Use it to preserve legacy shallow cleanup.
	PrefixOnly bool
	// Base64Only checks the optional cache prefix, E/R Claude signature prefix,
	// and base64 layers without validating the decoded Claude marker or protobuf
	// tree. Use it for conservative request cleanup.
	Base64Only bool
	// AllowEmptySignatureWithEmptyText preserves empty thinking placeholders with
	// no signature and no thinking/text payload during strip operations.
	AllowEmptySignatureWithEmptyText bool
	Strict                           bool
}

ClaudeSignatureValidationOptions controls how far Claude thinking signatures are inspected. The base validation always checks the cache prefix, base64 layers, and decoded 0x12 Claude payload marker. Strict mode additionally verifies the known protobuf tree used by Claude thinking signatures.

type GPTReasoningSignatureInfo

type GPTReasoningSignatureInfo struct {
	DecodedLen    int
	CiphertextLen int
}

func InspectGPTReasoningSignature

func InspectGPTReasoningSignature(rawSignature string) (*GPTReasoningSignatureInfo, error)

InspectGPTReasoningSignature validates the Fernet-like outer format used by GPT/Codex reasoning encrypted_content. This is only a transport-shape check; it does not prove decryptability.

type GeminiThoughtSignatureEnvelope

type GeminiThoughtSignatureEnvelope string
const (
	GeminiThoughtSignatureEnvelopeUnknown GeminiThoughtSignatureEnvelope = "unknown"
	// GeminiThoughtSignatureEnvelopeProtobufField2 is the only replay-safe Gemini
	// envelope. The repeated field-1 form emitted by Gemini 2.5 is no longer
	// recognized: those models are out of scope, and their signatures now fall
	// through to the bypass sentinel like any other unknown envelope.
	GeminiThoughtSignatureEnvelopeProtobufField2 GeminiThoughtSignatureEnvelope = "protobuf_field_2"
	GeminiThoughtSignatureEnvelopeASCIIUUID      GeminiThoughtSignatureEnvelope = "ascii_uuid"
)

type GeminiThoughtSignatureInfo

type GeminiThoughtSignatureInfo struct {
	IsBypassSentinel  bool
	BypassSentinel    string
	DecodedLen        int
	FirstByte         byte
	HasObservedMarker bool
	KnownEnvelope     bool
	Envelope          GeminiThoughtSignatureEnvelope
	RecordCount       int
	OpaquePayloadLen  int
}

GeminiThoughtSignatureInfo describes the locally inspectable properties of an opaque Gemini thought signature.

func InspectGeminiThoughtSignature

func InspectGeminiThoughtSignature(rawSignature string, opts ...GeminiThoughtSignatureValidationOptions) (*GeminiThoughtSignatureInfo, error)

InspectGeminiThoughtSignature validates and inspects the local transport shape of a Gemini thought signature. It intentionally treats provider-issued signatures as opaque base64 payloads.

type GeminiThoughtSignatureValidationOptions

type GeminiThoughtSignatureValidationOptions struct {
	// AllowBypassSentinel accepts Gemini's documented synthetic-history bypass
	// sentinels. Keep this false when validating provider-issued signatures.
	AllowBypassSentinel bool
	// RequireKnownEnvelope requires the decoded payload to match one of the
	// protobuf envelopes observed in Gemini samples. This rejects opaque base64
	// values such as base64 UUIDs.
	RequireKnownEnvelope bool
	// RequireObservedMarker requires the decoded payload to start with 0x12. Every
	// observed Gemini 3.x sample carries this marker, but it is only the outer
	// protobuf tag, so RequireKnownEnvelope is the stronger check and should be
	// preferred. This option exists for narrow experiments that want the marker
	// without the full envelope walk.
	RequireObservedMarker bool
}

GeminiThoughtSignatureValidationOptions controls how much local validation is applied to Gemini thought signatures. This validation checks only the opaque transport envelope; it does not prove that a signature came from Gemini or can be decrypted by Gemini.

type GrokEncryptedContentInfo added in v7.2.49

type GrokEncryptedContentInfo struct {
	RawLen     int
	DecodedLen int
}

func InspectGrokEncryptedContent added in v7.2.49

func InspectGrokEncryptedContent(raw string) (*GrokEncryptedContentInfo, error)

InspectGrokEncryptedContent validates the transport shape of xAI/Grok reasoning or compaction encrypted_content. This does not prove decryptability.

This is NOT a provider classifier and must not be used as one. Unlike Claude, Gemini and GPT, xAI emits no self-describing envelope: observed payloads are indistinguishable from uniform random bytes (no magic prefix, no version byte, no fixed suffix, and decoded lengths spread evenly modulo the AES block size). Every high-entropy unpadded standard-base64 blob therefore satisfies the checks below. Callers must establish provenance before asking this question, either from an explicit provider cache prefix or from a confirmed xAI target model, and treat the result as a replay-safety check rather than an identification.

type SignatureBlockKind

type SignatureBlockKind string
const (
	SignatureBlockKindUnknown            SignatureBlockKind = "unknown"
	SignatureBlockKindClaudeThinking     SignatureBlockKind = "claude_thinking"
	SignatureBlockKindGeminiModelPart    SignatureBlockKind = "gemini_model_part"
	SignatureBlockKindGeminiFunctionCall SignatureBlockKind = "gemini_function_call"
	SignatureBlockKindGPTReasoning       SignatureBlockKind = "gpt_reasoning"
)

type SignatureCompatibilityAction

type SignatureCompatibilityAction string
const (
	SignatureActionPreserve                SignatureCompatibilityAction = "preserve"
	SignatureActionDropBlock               SignatureCompatibilityAction = "drop_block"
	SignatureActionDropSignature           SignatureCompatibilityAction = "drop_signature"
	SignatureActionReplaceWithGeminiBypass SignatureCompatibilityAction = "replace_with_gemini_bypass"
	SignatureActionNoCompatibleReplacement SignatureCompatibilityAction = "no_compatible_replacement"
)

type SignatureCompatibilityDecision

type SignatureCompatibilityDecision struct {
	TargetProvider       SignatureProvider
	DetectedProvider     SignatureProvider
	BlockKind            SignatureBlockKind
	Compatible           bool
	Action               SignatureCompatibilityAction
	ReplacementSignature string
	NormalizedSignature  string
	Reason               string
}

func DecideSignatureCompatibility

func DecideSignatureCompatibility(targetProvider SignatureProvider, rawSignature string, blockKind SignatureBlockKind) SignatureCompatibilityDecision

DecideSignatureCompatibility returns the safe handling policy for replaying a signed block into targetProvider.

func DecideSignatureCompatibilityForModel added in v7.2.88

func DecideSignatureCompatibilityForModel(targetProvider SignatureProvider, targetModel string, rawSignature string, blockKind SignatureBlockKind) SignatureCompatibilityDecision

DecideSignatureCompatibilityForModel returns the safe handling policy for replaying a signed block into targetProvider for targetModel.

type SignatureProvider

type SignatureProvider string
const (
	SignatureProviderUnknown      SignatureProvider = "unknown"
	SignatureProviderClaude       SignatureProvider = "claude"
	SignatureProviderGemini       SignatureProvider = "gemini"
	SignatureProviderGeminiBypass SignatureProvider = "gemini_bypass"
	SignatureProviderGPT          SignatureProvider = "gpt"
)

func DetectSignatureProvider

func DetectSignatureProvider(rawSignature string) SignatureProvider

DetectSignatureProvider classifies the provider family that can replay rawSignature. It intentionally uses Claude strict validation before Gemini detection because Gemini 3 signatures also decode from an E-prefixed base64 string and can look Claude-like under shallow prefix checks.

func DetectSignatureProviderForBlock

func DetectSignatureProviderForBlock(rawSignature string, blockKind SignatureBlockKind) SignatureProvider

DetectSignatureProviderForBlock classifies rawSignature with block-kind context. UUID-shaped payloads are deliberately not classified as replay-safe provider signatures; callers targeting Gemini should replace them with the bypass sentinel.

func SignatureProviderFromCachePrefix

func SignatureProviderFromCachePrefix(prefix string) SignatureProvider

SignatureProviderFromCachePrefix maps this repo's explicit provider-prefix envelope to a provider family. This is intentionally stricter than SignatureProviderFromModelName so arbitrary model names such as "claude-cache#..." cannot be mistaken for trusted provider provenance.

func SignatureProviderFromModelName

func SignatureProviderFromModelName(modelName string) SignatureProvider

SignatureProviderFromModelName maps common model names to the provider family whose signed history can be safely replayed for that model.

func SplitSignatureProviderPrefix

func SplitSignatureProviderPrefix(rawSignature string) (SignatureProvider, string, bool)

type SignatureSanitizeReport

type SignatureSanitizeReport struct {
	TargetProvider     SignatureProvider
	Preserved          int
	DroppedBlocks      int
	DroppedSignatures  int
	ReplacedSignatures int
	Decisions          []SignatureCompatibilityDecision
}

func SanitizeClaudeMessagesForClaudeUpstream

func SanitizeClaudeMessagesForClaudeUpstream(payload []byte, targetModel string) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesForClaudeUpstream prepares a Claude /v1/messages body for Claude-compatible upstreams. Valid Claude signatures are normalized to provider-native E-form, valid Claude CAIS signatures are kept, incompatible thinking blocks are dropped, and tool_use blocks keep only their tool-call payload.

func SanitizeClaudeMessagesSignaturesForModel

func SanitizeClaudeMessagesSignaturesForModel(payload []byte, targetModel string) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesSignaturesForModel removes or preserves Claude /v1/messages signed history according to the provider family implied by targetModel.

func SanitizeClaudeMessagesSignaturesForTarget

func SanitizeClaudeMessagesSignaturesForTarget(payload []byte, opts ClaudeMessagesSignatureSanitizeOptions) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesSignaturesForTarget applies provider-aware signature compatibility rules to Claude /v1/messages history. Compatible thinking signatures are preserved. Incompatible thinking blocks are removed so a user can continue a conversation after switching between Claude, GPT/Codex, and Gemini models.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL