mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
Adds intelligent cache control preservation for Claude Code clients:
- New cacheControlPolicy.ts module with detection logic:
- isClaudeCodeClient(): Detects Claude Code via User-Agent
- providerSupportsCaching(): Checks provider (claude, anthropic, zai, qwen)
- isDeterministicStrategy(): Identifies priority/cost-optimized strategies
- shouldPreserveCacheControl(): Main policy decision
- Cache control is preserved when:
1. Client is Claude Code (detected via User-Agent)
2. Provider supports prompt caching
3. Request routing is deterministic:
- Single model requests (always)
- Combo with priority or cost-optimized strategy only
- Updated translator to accept preserveCacheControl option
- Updated chatCore and chat handler to propagate combo strategy
- Added comprehensive unit tests (24 tests)
Non-deterministic combo strategies (weighted, round-robin, random, etc.)
continue to use OmniRoute's managed caching strategy.
Refs: #cache-control-preservation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
101 lines
2.9 KiB
TypeScript
101 lines
2.9 KiB
TypeScript
/**
|
|
* Cache Control Policy
|
|
*
|
|
* Determines when to preserve client-side prompt caching headers (cache_control)
|
|
* vs. applying OmniRoute's own caching strategy.
|
|
*
|
|
* Client-side caching (e.g., Claude Code) should be preserved when:
|
|
* 1. Client is Claude Code or similar caching-aware client
|
|
* 2. Request will hit a deterministic target (single model or deterministic combo strategy)
|
|
* 3. Provider supports prompt caching (Anthropic, Alibaba Qwen, etc.)
|
|
*/
|
|
|
|
import type { RoutingStrategyValue } from "../../src/shared/constants/routingStrategies";
|
|
|
|
/**
|
|
* Routing strategies that are deterministic (same request → same provider)
|
|
*/
|
|
const DETERMINISTIC_STRATEGIES: Set<RoutingStrategyValue> = new Set([
|
|
"priority",
|
|
"cost-optimized",
|
|
]);
|
|
|
|
/**
|
|
* Providers that support prompt caching
|
|
*/
|
|
const CACHING_PROVIDERS = new Set([
|
|
"claude",
|
|
"anthropic",
|
|
"zai",
|
|
"qwen", // Alibaba Qwen Coding Plan International
|
|
]);
|
|
|
|
/**
|
|
* Detect if the client is Claude Code or another caching-aware client
|
|
*/
|
|
export function isClaudeCodeClient(userAgent: string | null | undefined): boolean {
|
|
if (!userAgent) return false;
|
|
const ua = userAgent.toLowerCase();
|
|
|
|
// Claude Code user agents
|
|
if (ua.includes("claude-code") || ua.includes("claude_code")) return true;
|
|
if (ua.includes("anthropic") && ua.includes("cli")) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if a provider supports prompt caching
|
|
*/
|
|
export function providerSupportsCaching(provider: string | null | undefined): boolean {
|
|
if (!provider) return false;
|
|
return CACHING_PROVIDERS.has(provider.toLowerCase());
|
|
}
|
|
|
|
/**
|
|
* Check if a routing strategy is deterministic
|
|
*/
|
|
export function isDeterministicStrategy(strategy: RoutingStrategyValue | null | undefined): boolean {
|
|
if (!strategy) return false;
|
|
return DETERMINISTIC_STRATEGIES.has(strategy);
|
|
}
|
|
|
|
/**
|
|
* Determine if client-side cache_control headers should be preserved
|
|
*
|
|
* @param userAgent - User-Agent header from the request
|
|
* @param isCombo - Whether this is a combo model
|
|
* @param comboStrategy - The combo's routing strategy (if applicable)
|
|
* @param targetProvider - The target provider for the request
|
|
* @returns true if cache_control should be preserved, false if OmniRoute should manage it
|
|
*/
|
|
export function shouldPreserveCacheControl({
|
|
userAgent,
|
|
isCombo,
|
|
comboStrategy,
|
|
targetProvider,
|
|
}: {
|
|
userAgent: string | null | undefined;
|
|
isCombo: boolean;
|
|
comboStrategy?: RoutingStrategyValue | null;
|
|
targetProvider: string | null | undefined;
|
|
}): boolean {
|
|
// Must be a caching-aware client
|
|
if (!isClaudeCodeClient(userAgent)) {
|
|
return false;
|
|
}
|
|
|
|
// Target provider must support caching
|
|
if (!providerSupportsCaching(targetProvider)) {
|
|
return false;
|
|
}
|
|
|
|
// Single model: always preserve (deterministic)
|
|
if (!isCombo) {
|
|
return true;
|
|
}
|
|
|
|
// Combo: only preserve if strategy is deterministic
|
|
return isDeterministicStrategy(comboStrategy);
|
|
}
|