diff --git a/src/main/apiServer/adapters/AiSdkToAnthropicSSE.ts b/src/main/apiServer/adapters/AiSdkToAnthropicSSE.ts index f24d8304a7..9ef19c0b9d 100644 --- a/src/main/apiServer/adapters/AiSdkToAnthropicSSE.ts +++ b/src/main/apiServer/adapters/AiSdkToAnthropicSSE.ts @@ -38,7 +38,7 @@ import type { import { loggerService } from '@logger' import { type FinishReason, type LanguageModelUsage, type TextStreamPart, type ToolSet } from 'ai' -import { googleReasoningCache, openRouterReasoningCache } from '../../services/CacheService' +import { googleReasoningCache, openRouterReasoningCache } from '../services/reasoning-cache' const logger = loggerService.withContext('AiSdkToAnthropicSSE') diff --git a/src/main/apiServer/services/reasoning-cache.ts b/src/main/apiServer/services/reasoning-cache.ts new file mode 100644 index 0000000000..eb39e691d8 --- /dev/null +++ b/src/main/apiServer/services/reasoning-cache.ts @@ -0,0 +1,45 @@ +/** + * Reasoning Cache Service + * + * Manages reasoning-related caching for AI providers that support thinking/reasoning modes. + * This includes Google Gemini's thought signatures and OpenRouter's reasoning details. + */ + +import type { ReasoningDetailUnion } from '@main/apiServer/adapters/openrouter' +import { CacheService } from '@main/services/CacheService' + +/** + * Interface for reasoning cache + */ +export interface IReasoningCache { + set(key: string, value: T): void + get(key: string): T | undefined +} + +/** + * Cache duration: 30 minutes + * Reasoning data is typically only needed within a short conversation context + */ +const REASONING_CACHE_DURATION = 30 * 60 * 1000 + +/** + * Google Gemini reasoning cache + * + * Stores thought signatures for Gemini 3 models to handle multi-turn conversations + * where the model needs to maintain thinking context across tool calls. + */ +export const googleReasoningCache: IReasoningCache = { + set: (key, value) => CacheService.set(`google-reasoning:${key}`, value, REASONING_CACHE_DURATION), + get: (key) => CacheService.get(`google-reasoning:${key}`) || undefined +} + +/** + * OpenRouter reasoning cache + * + * Stores reasoning details from OpenRouter responses to preserve thinking tokens + * and reasoning metadata across the conversation flow. + */ +export const openRouterReasoningCache: IReasoningCache = { + set: (key, value) => CacheService.set(`openrouter-reasoning:${key}`, value, REASONING_CACHE_DURATION), + get: (key) => CacheService.get(`openrouter-reasoning:${key}`) || undefined +} diff --git a/src/main/apiServer/services/unified-messages.ts b/src/main/apiServer/services/unified-messages.ts index e1b8301515..b9c306b2f9 100644 --- a/src/main/apiServer/services/unified-messages.ts +++ b/src/main/apiServer/services/unified-messages.ts @@ -42,7 +42,7 @@ import { net } from 'electron' import type { Response } from 'express' import * as z from 'zod' -import { googleReasoningCache, openRouterReasoningCache } from '../../services/CacheService' +import { googleReasoningCache, openRouterReasoningCache } from './reasoning-cache' const logger = loggerService.withContext('UnifiedMessagesService') diff --git a/src/main/services/CacheService.ts b/src/main/services/CacheService.ts index 84c6935d3d..d2984a9984 100644 --- a/src/main/services/CacheService.ts +++ b/src/main/services/CacheService.ts @@ -1,19 +1,9 @@ -import type { ReasoningDetailUnion } from '@main/apiServer/adapters/openrouter' - interface CacheItem { data: T timestamp: number duration: number } -/** - * Interface for reasoning cache - */ -export interface IReasoningCache { - set(key: string, value: T): void - get(key: string): T | undefined -} - export class CacheService { private static cache: Map> = new Map() @@ -82,14 +72,3 @@ export class CacheService { return true } } - -// Singleton cache instances using CacheService -export const googleReasoningCache: IReasoningCache = { - set: (key, value) => CacheService.set(`google-reasoning:${key}`, value, 30 * 60 * 1000), - get: (key) => CacheService.get(`google-reasoning:${key}`) || undefined -} - -export const openRouterReasoningCache: IReasoningCache = { - set: (key, value) => CacheService.set(`openrouter-reasoning:${key}`, value, 30 * 60 * 1000), - get: (key) => CacheService.get(`openrouter-reasoning:${key}`) || undefined -}