@@ -3,40 +3,75 @@ import { normalizeProviderId } from "./model-selection.js";
33export type ProviderCapabilities = {
44 anthropicToolSchemaMode : "native" | "openai-functions" ;
55 anthropicToolChoiceMode : "native" | "openai-string-modes" ;
6+ providerFamily : "default" | "openai" | "anthropic" ;
67 preserveAnthropicThinkingSignatures : boolean ;
78 openAiCompatTurnValidation : boolean ;
89 geminiThoughtSignatureSanitization : boolean ;
910 transcriptToolCallIdMode : "default" | "strict9" ;
11+ transcriptToolCallIdModelHints : string [ ] ;
12+ geminiThoughtSignatureModelHints : string [ ] ;
13+ dropThinkingBlockModelHints : string [ ] ;
1014} ;
1115
1216const DEFAULT_PROVIDER_CAPABILITIES : ProviderCapabilities = {
1317 anthropicToolSchemaMode : "native" ,
1418 anthropicToolChoiceMode : "native" ,
19+ providerFamily : "default" ,
1520 preserveAnthropicThinkingSignatures : true ,
1621 openAiCompatTurnValidation : true ,
1722 geminiThoughtSignatureSanitization : false ,
1823 transcriptToolCallIdMode : "default" ,
24+ transcriptToolCallIdModelHints : [ ] ,
25+ geminiThoughtSignatureModelHints : [ ] ,
26+ dropThinkingBlockModelHints : [ ] ,
1927} ;
2028
2129const PROVIDER_CAPABILITIES : Record < string , Partial < ProviderCapabilities > > = {
30+ anthropic : {
31+ providerFamily : "anthropic" ,
32+ } ,
33+ "amazon-bedrock" : {
34+ providerFamily : "anthropic" ,
35+ } ,
2236 "kimi-coding" : {
2337 anthropicToolSchemaMode : "openai-functions" ,
2438 anthropicToolChoiceMode : "openai-string-modes" ,
2539 preserveAnthropicThinkingSignatures : false ,
2640 } ,
2741 mistral : {
2842 transcriptToolCallIdMode : "strict9" ,
43+ transcriptToolCallIdModelHints : [
44+ "mistral" ,
45+ "mixtral" ,
46+ "codestral" ,
47+ "pixtral" ,
48+ "devstral" ,
49+ "ministral" ,
50+ "mistralai" ,
51+ ] ,
52+ } ,
53+ openai : {
54+ providerFamily : "openai" ,
55+ } ,
56+ "openai-codex" : {
57+ providerFamily : "openai" ,
2958 } ,
3059 openrouter : {
3160 openAiCompatTurnValidation : false ,
3261 geminiThoughtSignatureSanitization : true ,
62+ geminiThoughtSignatureModelHints : [ "gemini" ] ,
3363 } ,
3464 opencode : {
3565 openAiCompatTurnValidation : false ,
3666 geminiThoughtSignatureSanitization : true ,
67+ geminiThoughtSignatureModelHints : [ "gemini" ] ,
3768 } ,
3869 kilocode : {
3970 geminiThoughtSignatureSanitization : true ,
71+ geminiThoughtSignatureModelHints : [ "gemini" ] ,
72+ } ,
73+ "github-copilot" : {
74+ dropThinkingBlockModelHints : [ "claude" ] ,
4075 } ,
4176} ;
4277
@@ -76,7 +111,51 @@ export function sanitizesGeminiThoughtSignatures(provider?: string | null): bool
76111 return resolveProviderCapabilities ( provider ) . geminiThoughtSignatureSanitization ;
77112}
78113
79- export function resolveTranscriptToolCallIdMode ( provider ?: string | null ) : "strict9" | undefined {
80- const mode = resolveProviderCapabilities ( provider ) . transcriptToolCallIdMode ;
114+ function modelIncludesAnyHint ( modelId : string | null | undefined , hints : string [ ] ) : boolean {
115+ const normalized = ( modelId ?? "" ) . toLowerCase ( ) ;
116+ return Boolean ( normalized ) && hints . some ( ( hint ) => normalized . includes ( hint ) ) ;
117+ }
118+
119+ export function isOpenAiProviderFamily ( provider ?: string | null ) : boolean {
120+ return resolveProviderCapabilities ( provider ) . providerFamily === "openai" ;
121+ }
122+
123+ export function isAnthropicProviderFamily ( provider ?: string | null ) : boolean {
124+ return resolveProviderCapabilities ( provider ) . providerFamily === "anthropic" ;
125+ }
126+
127+ export function shouldDropThinkingBlocksForModel ( params : {
128+ provider ?: string | null ;
129+ modelId ?: string | null ;
130+ } ) : boolean {
131+ return modelIncludesAnyHint (
132+ params . modelId ,
133+ resolveProviderCapabilities ( params . provider ) . dropThinkingBlockModelHints ,
134+ ) ;
135+ }
136+
137+ export function shouldSanitizeGeminiThoughtSignaturesForModel ( params : {
138+ provider ?: string | null ;
139+ modelId ?: string | null ;
140+ } ) : boolean {
141+ const capabilities = resolveProviderCapabilities ( params . provider ) ;
142+ return (
143+ capabilities . geminiThoughtSignatureSanitization &&
144+ modelIncludesAnyHint ( params . modelId , capabilities . geminiThoughtSignatureModelHints )
145+ ) ;
146+ }
147+
148+ export function resolveTranscriptToolCallIdMode (
149+ provider ?: string | null ,
150+ modelId ?: string | null ,
151+ ) : "strict9" | undefined {
152+ const capabilities = resolveProviderCapabilities ( provider ) ;
153+ const mode = capabilities . transcriptToolCallIdMode ;
154+ if ( mode === "strict9" ) {
155+ return mode ;
156+ }
157+ if ( modelIncludesAnyHint ( modelId , capabilities . transcriptToolCallIdModelHints ) ) {
158+ return "strict9" ;
159+ }
81160 return mode === "strict9" ? mode : undefined ;
82161}
0 commit comments