@@ -51,6 +51,17 @@ vitest.mock("../fetchers/modelCache", () => ({
5151 cacheReadsPrice : 0.3 ,
5252 description : "Claude 3.7 Sonnet with thinking" ,
5353 } ,
54+ "deepseek/deepseek-v3.1-terminus" : {
55+ maxTokens : 8192 ,
56+ contextWindow : 128000 ,
57+ supportsImages : false ,
58+ supportsPromptCache : false ,
59+ inputPrice : 0.3 ,
60+ outputPrice : 1.2 ,
61+ description : "DeepSeek V3.1 Terminus" ,
62+ supportsReasoningEffort : true ,
63+ supportedReasoningEfforts : [ "low" , "medium" , "high" ] ,
64+ } ,
5465 } )
5566 } ) ,
5667} ) )
@@ -330,4 +341,144 @@ describe("OpenRouterHandler", () => {
330341 await expect ( handler . completePrompt ( "test prompt" ) ) . rejects . toThrow ( "Unexpected error" )
331342 } )
332343 } )
344+
345+ describe ( "DeepSeek V3.1 Terminus handling" , ( ) => {
346+ it ( "should use chat_template_kwargs with thinking:true when reasoning is enabled for V3.1 Terminus" , async ( ) => {
347+ const handler = new OpenRouterHandler ( {
348+ openRouterApiKey : "test-key" ,
349+ openRouterModelId : "deepseek/deepseek-v3.1-terminus" ,
350+ reasoningEffort : "medium" ,
351+ } )
352+
353+ const mockStream = {
354+ async * [ Symbol . asyncIterator ] ( ) {
355+ yield {
356+ id : "test-id" ,
357+ choices : [ { delta : { content : "test response" } } ] ,
358+ }
359+ } ,
360+ }
361+
362+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockStream )
363+ ; ( OpenAI as any ) . prototype . chat = {
364+ completions : { create : mockCreate } ,
365+ } as any
366+
367+ await handler . createMessage ( "test" , [ ] ) . next ( )
368+
369+ // Should include chat_template_kwargs with thinking:true and NOT include reasoning parameter
370+ expect ( mockCreate ) . toHaveBeenCalledWith (
371+ expect . objectContaining ( {
372+ model : "deepseek/deepseek-v3.1-terminus" ,
373+ chat_template_kwargs : { thinking : true } ,
374+ } ) ,
375+ )
376+ // Ensure reasoning parameter is NOT included
377+ expect ( mockCreate ) . not . toHaveBeenCalledWith (
378+ expect . objectContaining ( {
379+ reasoning : expect . anything ( ) ,
380+ } ) ,
381+ )
382+ } )
383+
384+ it ( "should use chat_template_kwargs with thinking:false when reasoning is disabled for V3.1 Terminus" , async ( ) => {
385+ const handler = new OpenRouterHandler ( {
386+ openRouterApiKey : "test-key" ,
387+ openRouterModelId : "deepseek/deepseek-v3.1-terminus" ,
388+ // No reasoning effort specified
389+ } )
390+
391+ const mockStream = {
392+ async * [ Symbol . asyncIterator ] ( ) {
393+ yield {
394+ id : "test-id" ,
395+ choices : [ { delta : { content : "test response" } } ] ,
396+ }
397+ } ,
398+ }
399+
400+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockStream )
401+ ; ( OpenAI as any ) . prototype . chat = {
402+ completions : { create : mockCreate } ,
403+ } as any
404+
405+ await handler . createMessage ( "test" , [ ] ) . next ( )
406+
407+ // Should include chat_template_kwargs with thinking:false
408+ expect ( mockCreate ) . toHaveBeenCalledWith (
409+ expect . objectContaining ( {
410+ model : "deepseek/deepseek-v3.1-terminus" ,
411+ chat_template_kwargs : { thinking : false } ,
412+ } ) ,
413+ )
414+ // Ensure reasoning parameter is NOT included
415+ expect ( mockCreate ) . not . toHaveBeenCalledWith (
416+ expect . objectContaining ( {
417+ reasoning : expect . anything ( ) ,
418+ } ) ,
419+ )
420+ } )
421+
422+ it ( "should not use chat_template_kwargs for non-Terminus models" , async ( ) => {
423+ const handler = new OpenRouterHandler ( {
424+ openRouterApiKey : "test-key" ,
425+ openRouterModelId : "anthropic/claude-sonnet-4" ,
426+ reasoningEffort : "medium" ,
427+ } )
428+
429+ const mockStream = {
430+ async * [ Symbol . asyncIterator ] ( ) {
431+ yield {
432+ id : "test-id" ,
433+ choices : [ { delta : { content : "test response" } } ] ,
434+ }
435+ } ,
436+ }
437+
438+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockStream )
439+ ; ( OpenAI as any ) . prototype . chat = {
440+ completions : { create : mockCreate } ,
441+ } as any
442+
443+ await handler . createMessage ( "test" , [ ] ) . next ( )
444+
445+ // Should NOT include chat_template_kwargs for non-Terminus models
446+ expect ( mockCreate ) . not . toHaveBeenCalledWith (
447+ expect . objectContaining ( {
448+ chat_template_kwargs : expect . anything ( ) ,
449+ } ) ,
450+ )
451+ } )
452+
453+ it ( "should handle chat_template_kwargs in completePrompt for V3.1 Terminus" , async ( ) => {
454+ const handler = new OpenRouterHandler ( {
455+ openRouterApiKey : "test-key" ,
456+ openRouterModelId : "deepseek/deepseek-v3.1-terminus" ,
457+ reasoningEffort : "high" ,
458+ } )
459+
460+ const mockResponse = { choices : [ { message : { content : "test completion" } } ] }
461+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockResponse )
462+ ; ( OpenAI as any ) . prototype . chat = {
463+ completions : { create : mockCreate } ,
464+ } as any
465+
466+ await handler . completePrompt ( "test prompt" )
467+
468+ // Should include chat_template_kwargs with thinking:true for non-streaming as well
469+ expect ( mockCreate ) . toHaveBeenCalledWith (
470+ expect . objectContaining ( {
471+ model : "deepseek/deepseek-v3.1-terminus" ,
472+ chat_template_kwargs : { thinking : true } ,
473+ stream : false ,
474+ } ) ,
475+ )
476+ // Ensure reasoning parameter is NOT included
477+ expect ( mockCreate ) . not . toHaveBeenCalledWith (
478+ expect . objectContaining ( {
479+ reasoning : expect . anything ( ) ,
480+ } ) ,
481+ )
482+ } )
483+ } )
333484} )
0 commit comments