@@ -9,10 +9,21 @@ import OpenAI from "openai"
99import { OpenRouterHandler } from "../openrouter"
1010import { ApiHandlerOptions } from "../../../shared/api"
1111import { Package } from "../../../shared/package"
12+ import { ApiProviderError } from "@roo-code/types"
1213
1314// Mock dependencies
1415vitest . mock ( "openai" )
1516vitest . mock ( "delay" , ( ) => ( { default : vitest . fn ( ( ) => Promise . resolve ( ) ) } ) )
17+
18+ // Mock TelemetryService
19+ const mockCaptureException = vitest . fn ( )
20+ vitest . mock ( "@roo-code/telemetry" , ( ) => ( {
21+ TelemetryService : {
22+ instance : {
23+ captureException : ( ...args : unknown [ ] ) => mockCaptureException ( ...args ) ,
24+ } ,
25+ } ,
26+ } ) )
1627vitest . mock ( "../fetchers/modelCache" , ( ) => ( {
1728 getModels : vitest . fn ( ) . mockImplementation ( ( ) => {
1829 return Promise . resolve ( {
@@ -267,7 +278,7 @@ describe("OpenRouterHandler", () => {
267278 )
268279 } )
269280
270- it ( "handles API errors" , async ( ) => {
281+ it ( "handles API errors and captures telemetry " , async ( ) => {
271282 const handler = new OpenRouterHandler ( mockOptions )
272283 const mockStream = {
273284 async * [ Symbol . asyncIterator ] ( ) {
@@ -282,6 +293,52 @@ describe("OpenRouterHandler", () => {
282293
283294 const generator = handler . createMessage ( "test" , [ ] )
284295 await expect ( generator . next ( ) ) . rejects . toThrow ( "OpenRouter API Error 500: API Error" )
296+
297+ // Verify telemetry was captured
298+ expect ( mockCaptureException ) . toHaveBeenCalledWith ( expect . any ( ApiProviderError ) , {
299+ provider : "OpenRouter" ,
300+ modelId : mockOptions . openRouterModelId ,
301+ operation : "createMessage" ,
302+ errorCode : 500 ,
303+ } )
304+ } )
305+
306+ it ( "captures telemetry when createMessage throws an exception" , async ( ) => {
307+ const handler = new OpenRouterHandler ( mockOptions )
308+ const mockCreate = vitest . fn ( ) . mockRejectedValue ( new Error ( "Connection failed" ) )
309+ ; ( OpenAI as any ) . prototype . chat = {
310+ completions : { create : mockCreate } ,
311+ } as any
312+
313+ const generator = handler . createMessage ( "test" , [ ] )
314+ await expect ( generator . next ( ) ) . rejects . toThrow ( )
315+
316+ // Verify telemetry was captured
317+ expect ( mockCaptureException ) . toHaveBeenCalledWith ( expect . any ( ApiProviderError ) , {
318+ provider : "OpenRouter" ,
319+ modelId : mockOptions . openRouterModelId ,
320+ operation : "createMessage" ,
321+ } )
322+ } )
323+
324+ it ( "does NOT capture telemetry for 429 rate limit errors" , async ( ) => {
325+ const handler = new OpenRouterHandler ( mockOptions )
326+ const mockStream = {
327+ async * [ Symbol . asyncIterator ] ( ) {
328+ yield { error : { message : "Rate limit exceeded" , code : 429 } }
329+ } ,
330+ }
331+
332+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockStream )
333+ ; ( OpenAI as any ) . prototype . chat = {
334+ completions : { create : mockCreate } ,
335+ } as any
336+
337+ const generator = handler . createMessage ( "test" , [ ] )
338+ await expect ( generator . next ( ) ) . rejects . toThrow ( "OpenRouter API Error 429: Rate limit exceeded" )
339+
340+ // Verify telemetry was NOT captured for 429 errors
341+ expect ( mockCaptureException ) . not . toHaveBeenCalled ( )
285342 } )
286343
287344 it ( "yields tool_call_end events when finish_reason is tool_calls" , async ( ) => {
@@ -384,7 +441,7 @@ describe("OpenRouterHandler", () => {
384441 )
385442 } )
386443
387- it ( "handles API errors" , async ( ) => {
444+ it ( "handles API errors and captures telemetry " , async ( ) => {
388445 const handler = new OpenRouterHandler ( mockOptions )
389446 const mockError = {
390447 error : {
@@ -399,16 +456,53 @@ describe("OpenRouterHandler", () => {
399456 } as any
400457
401458 await expect ( handler . completePrompt ( "test prompt" ) ) . rejects . toThrow ( "OpenRouter API Error 500: API Error" )
459+
460+ // Verify telemetry was captured
461+ expect ( mockCaptureException ) . toHaveBeenCalledWith ( expect . any ( ApiProviderError ) , {
462+ provider : "OpenRouter" ,
463+ modelId : mockOptions . openRouterModelId ,
464+ operation : "completePrompt" ,
465+ errorCode : 500 ,
466+ } )
402467 } )
403468
404- it ( "handles unexpected errors" , async ( ) => {
469+ it ( "handles unexpected errors and captures telemetry " , async ( ) => {
405470 const handler = new OpenRouterHandler ( mockOptions )
406471 const mockCreate = vitest . fn ( ) . mockRejectedValue ( new Error ( "Unexpected error" ) )
407472 ; ( OpenAI as any ) . prototype . chat = {
408473 completions : { create : mockCreate } ,
409474 } as any
410475
411476 await expect ( handler . completePrompt ( "test prompt" ) ) . rejects . toThrow ( "Unexpected error" )
477+
478+ // Verify telemetry was captured
479+ expect ( mockCaptureException ) . toHaveBeenCalledWith ( expect . any ( ApiProviderError ) , {
480+ provider : "OpenRouter" ,
481+ modelId : mockOptions . openRouterModelId ,
482+ operation : "completePrompt" ,
483+ } )
484+ } )
485+
486+ it ( "does NOT capture telemetry for 429 rate limit errors" , async ( ) => {
487+ const handler = new OpenRouterHandler ( mockOptions )
488+ const mockError = {
489+ error : {
490+ message : "Rate limit exceeded" ,
491+ code : 429 ,
492+ } ,
493+ }
494+
495+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( mockError )
496+ ; ( OpenAI as any ) . prototype . chat = {
497+ completions : { create : mockCreate } ,
498+ } as any
499+
500+ await expect ( handler . completePrompt ( "test prompt" ) ) . rejects . toThrow (
501+ "OpenRouter API Error 429: Rate limit exceeded" ,
502+ )
503+
504+ // Verify telemetry was NOT captured for 429 errors
505+ expect ( mockCaptureException ) . not . toHaveBeenCalled ( )
412506 } )
413507 } )
414508} )
0 commit comments