How OpenClaude Handles Gemini Credential Handling and Thought‑Signature Behavior
OpenClaude resolves Gemini credentials through a unified auth-resolution layer in src/utils/geminiAuth.ts and preserves thought-signatures across the request pipeline via encoding in tool-use IDs and OpenAI-shim compatibility bridging.
OpenClaude is an open-source AI gateway that normalizes multiple provider APIs behind a unified interface. Understanding how it handles Gemini credential handling and thought-signature behavior reveals the architecture for secure authentication and accurate chain-of-thought preservation with Google's Gemini models.
Gemini Credential Handling Architecture
OpenClaude implements a three-tier credential resolution system that supports multiple authentication patterns without hardcoding provider-specific logic into the core application.
Auth-Mode Detection in resolveGeminiCredential
The entry point for all Gemini authentication is resolveGeminiCredential in src/utils/geminiAuth.ts. This function inspects the runtime environment and determines which of three auth modes to activate:
- API-key mode — activated when
GEMINI_API_KEYis present - Access-token mode — activated when
GEMINI_ACCESS_TOKENis present [🔗 src/utils/geminiAuth.ts#L76] - ADC mode — activated when
GEMINI_AUTH_MODEis explicitly set to"adc"[🔗 src/utils/geminiAuth.ts#L80]
The function prioritizes explicit configuration over implicit discovery, ensuring predictable behavior across deployment environments.
Resolution Flow and Fallback Behavior
The credential resolution follows a strict precedence chain in src/utils/geminiAuth.ts:
- Check for user-provided resolver in
options.resolveGeminiCredential - Fall back to built-in resolver that reads environment variables
- For ADC mode, load credentials from the local Google Cloud SDK installation [🔗 src/utils/geminiAuth.ts#L212-L226]
This design allows test injection and custom credential sources without modifying core logic.
Provider Profile Integration
The buildGeminiProfileEnv function in src/utils/providerProfile.ts synthesizes resolved credentials into the startup environment for Gemini-enabled provider profiles:
// Build a startup environment for a Gemini-enabled profile
import { buildGeminiProfileEnv } from './utils/providerProfile.js';
const env = buildGeminiProfileEnv({
persistedGeminiModel: 'gemini-1.5-flash',
persistedGeminiBaseUrl: undefined,
persistedGeminiAuthMode: 'access-token',
readGeminiAccessToken: () => process.env.GEMINI_ACCESS_TOKEN,
});
console.log(env.GEMINI_ACCESS_TOKEN); // token used by the Vertex client
The function maps internal state to environment variables:
GEMINI_AUTH_MODEstores the chosen auth mode [🔗 src/utils/providerProfile.ts#L1778-L1788]GEMINI_API_KEYreceives the key when mode is"api-key"[🔗 src/utils/providerProfile.ts#L1784]GEMINI_ACCESS_TOKENreceives the token when mode is"access-token"[🔗 src/utils/providerProfile.ts#L1788]
Pre-Flight Validation
Before any request executes, providerValidation.ts verifies that at least one Gemini credential source is available:
// Resolve Gemini credentials from the current process environment
import { resolveGeminiCredential } from './utils/geminiAuth.js';
const cred = await resolveGeminiCredential(process.env);
console.log(cred);
// { apiKey?: string, accessToken?: string, authMode: 'api-key'|'access-token'|'adc' }
Validation fails with a descriptive error if no credential source is detected [🔗 src/utils/providerValidation.ts#L405-L437].
Thought-Signature Handling Pipeline
Gemini models with "thinking" capability attach a thought-signature—a token identifying the model's internal chain-of-thought—to function-call parts. OpenClaude preserves this signature through encoding, streaming conversion, and OpenAI-shim bridging.
Vertex Client Signature Encoding
In src/services/api/geminiVertexClient.ts, the thought-signature is attached to functionCall payloads during thinking turns. Two helper functions manage the signature lifecycle:
encodeToolUseId— appends the signature to the internal tool-use IDdecodeToolUseId— extracts the signature for later processing [🔗 src/services/api/geminiVertexClient.ts#L509-L515]
This encoding ensures the signature survives round-trips through tool execution history.
Streaming Token Accounting
The geminiStreamConversion.ts module handles streaming responses and extracts thoughtsTokenCount from response metadata:
// Sending a Gemini request that includes a thought-signature
import { geminiVertexClient } from './services/api/geminiVertexClient.js';
const response = await geminiVertexClient.chat({
model: 'gemini-1.5-pro',
messages: [{ role: 'user', content: 'Explain recursion' }],
// The client will automatically attach the stored thoughtSignature, if any
});
console.log(response.thoughtSignature); // e.g. "SIG_ABC_123"
The extracted count forwards to the OpenAI-shim layer for accurate billing and rate-limit tracking [🔗 src/services/api/geminiStreamConversion.ts#L186-L190].
OpenAI-Shim Compatibility Bridging
The providerCompatibility.ts module in the OpenAI-shim layer merges Gemini-specific fields into the normalized response format. The thought_signature from extra_content is preserved unchanged for downstream tooling [🔗 src/services/api/openaiShim/providerCompatibility.ts#L73-L88].
This bridging guarantees that:
- Tool-use handlers receive the original signature
- Response formats remain consistent across providers
- Billing systems account for thinking tokens correctly
Test Coverage for Signature Integrity
The test suite verifies signature preservation across all execution paths:
- Round-trip integrity —
geminiVertexClient.test.tsconfirms signatures survive history traversal [🔗 src/services/api/geminiVertexClient.test.ts#L387-L456] - Conversion layer preservation —
providerCompatibility.test.tsvalidates OpenAI-shim output [🔗 src/services/api/openaiShim/providerCompatibility.test.ts#L395-L409]
Key Implementation Files
| File | Responsibility |
|---|---|
src/utils/geminiAuth.ts |
Core resolver for GEMINI_API_KEY, GEMINI_ACCESS_TOKEN, and ADC credentials |
src/utils/providerProfile.ts |
Runtime environment construction for Gemini profiles |
src/utils/providerValidation.ts |
Pre-flight credential validation |
src/services/api/geminiVertexClient.ts |
HTTP client with thought-signature encoding/decoding |
src/services/api/geminiStreamConversion.ts |
Streaming response handling with thoughtsTokenCount extraction |
src/services/api/openaiShim/providerCompatibility.ts |
Bridge for thought_signature in OpenAI-shim format |
src/services/api/geminiVertexClient.test.ts |
Round-trip signature tests |
src/services/api/openaiShim/providerCompatibility.test.ts |
Conversion layer signature tests |
Summary
- Three auth modes — API-key, access-token, and ADC — resolved through
resolveGeminiCredentialwith explicit precedence - Environment synthesis —
buildGeminiProfileEnvmaps credentials to standard environment variables for runtime consumption - Pre-flight validation —
providerValidation.tsguarantees credential presence before request execution - Signature encoding — tool-use ID manipulation preserves thought-signatures through tool execution cycles
- Streaming accuracy —
thoughtsTokenCountextraction enables correct token accounting for thinking models - Cross-provider compatibility — OpenAI-shim bridging maintains signature integrity for downstream consumers
Frequently Asked Questions
How does OpenClaude choose between API-key and access-token authentication for Gemini?
resolveGeminiCredential checks environment variables in priority order: explicit GEMINI_AUTH_MODE overrides detection, otherwise presence of GEMINI_API_KEY selects API-key mode and GEMINI_ACCESS_TOKEN selects access-token mode. ADC mode requires explicit GEMINI_AUTH_MODE=adc configuration.
What happens if no Gemini credentials are configured?
providerValidation.ts throws a descriptive validation error before any network request occurs, preventing runtime failures and providing clear guidance on required environment variables.
Why does OpenClaude encode the thought-signature into the tool-use ID?
The encoding ensures the signature survives round-trips through tool execution history without requiring schema changes to the underlying message format. decodeToolUseId recovers the signature when processing responses.
Does thought-signature handling affect streaming performance?
No. The geminiStreamConversion.ts layer extracts thoughtsTokenCount incrementally during streaming, with minimal overhead. The signature extraction occurs once per function-call part, not per token.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →