@@ -3,6 +3,8 @@ import { codebaseSearchTool } from "../codebaseSearchTool"
33import { CodeIndexManager } from "../../../services/code-index/manager"
44import { Task } from "../../task/Task"
55import { ToolUse } from "../../../shared/tools"
6+ import { TelemetryService } from "@roo-code/telemetry"
7+ import { TelemetryEventName } from "@roo-code/types"
68
79// Mock dependencies
810vi . mock ( "../../../services/code-index/manager" )
@@ -19,6 +21,13 @@ vi.mock("vscode", () => ({
1921 asRelativePath : vi . fn ( ( path : string ) => path . replace ( "/test/workspace/" , "" ) ) ,
2022 } ,
2123} ) )
24+ vi . mock ( "@roo-code/telemetry" , ( ) => ( {
25+ TelemetryService : {
26+ instance : {
27+ captureEvent : vi . fn ( ) ,
28+ } ,
29+ } ,
30+ } ) )
2231
2332describe ( "codebaseSearchTool" , ( ) => {
2433 let mockTask : Task
@@ -274,6 +283,145 @@ describe("codebaseSearchTool", () => {
274283 expect . stringContaining ( "Semantic search is not available yet (currently Standby)" ) ,
275284 )
276285 } )
286+
287+ it ( "should track telemetry when indexing is in Standby state" , async ( ) => {
288+ mockCodeIndexManager . state = "Standby"
289+
290+ const block : ToolUse = {
291+ type : "tool_use" ,
292+ name : "codebase_search" ,
293+ params : { query : "test query" } ,
294+ partial : false ,
295+ }
296+
297+ await codebaseSearchTool (
298+ mockTask ,
299+ block ,
300+ mockAskApproval ,
301+ mockHandleError ,
302+ mockPushToolResult ,
303+ mockRemoveClosingTag ,
304+ )
305+
306+ expect ( TelemetryService . instance . captureEvent ) . toHaveBeenCalledWith ( TelemetryEventName . TOOL_USED , {
307+ tool : "codebase_search" ,
308+ codeIndexState : "Standby" ,
309+ hasQuery : true ,
310+ result : "unavailable_not_indexed" ,
311+ } )
312+ } )
313+
314+ it ( "should track telemetry when indexing is in progress" , async ( ) => {
315+ mockCodeIndexManager . state = "Indexing"
316+
317+ const block : ToolUse = {
318+ type : "tool_use" ,
319+ name : "codebase_search" ,
320+ params : { query : "test query" } ,
321+ partial : false ,
322+ }
323+
324+ await codebaseSearchTool (
325+ mockTask ,
326+ block ,
327+ mockAskApproval ,
328+ mockHandleError ,
329+ mockPushToolResult ,
330+ mockRemoveClosingTag ,
331+ )
332+
333+ expect ( TelemetryService . instance . captureEvent ) . toHaveBeenCalledWith ( TelemetryEventName . TOOL_USED , {
334+ tool : "codebase_search" ,
335+ codeIndexState : "Indexing" ,
336+ hasQuery : true ,
337+ result : "unavailable_not_indexed" ,
338+ } )
339+ expect ( mockPushToolResult ) . toHaveBeenCalledWith (
340+ expect . stringContaining ( "Code indexing is currently in progress" ) ,
341+ )
342+ } )
343+
344+ it ( "should track telemetry when indexing is in error state" , async ( ) => {
345+ mockCodeIndexManager . state = "Error"
346+
347+ const block : ToolUse = {
348+ type : "tool_use" ,
349+ name : "codebase_search" ,
350+ params : { query : "test query" } ,
351+ partial : false ,
352+ }
353+
354+ await codebaseSearchTool (
355+ mockTask ,
356+ block ,
357+ mockAskApproval ,
358+ mockHandleError ,
359+ mockPushToolResult ,
360+ mockRemoveClosingTag ,
361+ )
362+
363+ expect ( TelemetryService . instance . captureEvent ) . toHaveBeenCalledWith ( TelemetryEventName . TOOL_USED , {
364+ tool : "codebase_search" ,
365+ codeIndexState : "Error" ,
366+ hasQuery : true ,
367+ result : "unavailable_not_indexed" ,
368+ } )
369+ expect ( mockPushToolResult ) . toHaveBeenCalledWith (
370+ expect . stringContaining ( "Code indexing encountered an error" ) ,
371+ )
372+ } )
373+
374+ it ( "should not track telemetry when indexing is complete" , async ( ) => {
375+ mockCodeIndexManager . state = "Indexed"
376+ mockCodeIndexManager . searchIndex . mockResolvedValue ( [ ] )
377+
378+ const block : ToolUse = {
379+ type : "tool_use" ,
380+ name : "codebase_search" ,
381+ params : { query : "test query" } ,
382+ partial : false ,
383+ }
384+
385+ await codebaseSearchTool (
386+ mockTask ,
387+ block ,
388+ mockAskApproval ,
389+ mockHandleError ,
390+ mockPushToolResult ,
391+ mockRemoveClosingTag ,
392+ )
393+
394+ // Should not capture telemetry event for non-indexed states
395+ expect ( TelemetryService . instance . captureEvent ) . not . toHaveBeenCalledWith (
396+ TelemetryEventName . TOOL_USED ,
397+ expect . objectContaining ( {
398+ result : "unavailable_not_indexed" ,
399+ } ) ,
400+ )
401+ } )
402+
403+ it ( "should track telemetry with hasQuery false when query is missing" , async ( ) => {
404+ mockCodeIndexManager . state = "Standby"
405+
406+ const block : ToolUse = {
407+ type : "tool_use" ,
408+ name : "codebase_search" ,
409+ params : { } ,
410+ partial : false ,
411+ }
412+
413+ await codebaseSearchTool (
414+ mockTask ,
415+ block ,
416+ mockAskApproval ,
417+ mockHandleError ,
418+ mockPushToolResult ,
419+ mockRemoveClosingTag ,
420+ )
421+
422+ // Even though query is missing, telemetry should still be tracked before parameter validation
423+ expect ( mockTask . sayAndCreateMissingParamError ) . toHaveBeenCalledWith ( "codebase_search" , "query" )
424+ } )
277425 } )
278426
279427 describe ( "parameter validation" , ( ) => {
0 commit comments