11// npx vitest src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts
22
33import type { Anthropic } from "@anthropic-ai/sdk"
4- import { describe , it , expect , beforeEach , vi } from "vitest"
4+ import { describe , it , expect , beforeEach , vi , type Mock } from "vitest"
55import { presentAssistantMessage } from "../presentAssistantMessage"
66import { validateToolUse } from "../../tools/validateToolUse"
77import { getModeBySlug } from "../../../shared/modes"
@@ -60,6 +60,7 @@ interface MockTask {
6060 didAlreadyUseTool : boolean
6161 consecutiveMistakeCount : number
6262 clineMessages : unknown [ ]
63+ getTaskMode : Mock < ( ) => Promise < string > >
6364 api : { getModel : ( ) => { id : string ; info : Record < string , unknown > } }
6465 recordToolUsage : ReturnType < typeof vi . fn >
6566 recordToolError : ReturnType < typeof vi . fn >
@@ -75,7 +76,6 @@ interface MockTask {
7576 say : ReturnType < typeof vi . fn >
7677 ask : ReturnType < typeof vi . fn >
7778 pushToolResultToUserContent : ReturnType < typeof vi . fn >
78- getTaskMode : ReturnType < typeof vi . fn >
7979}
8080
8181describe ( "presentAssistantMessage - tool usage attribution" , ( ) => {
@@ -99,6 +99,7 @@ describe("presentAssistantMessage - tool usage attribution", () => {
9999 didAlreadyUseTool : false ,
100100 consecutiveMistakeCount : 0 ,
101101 clineMessages : [ ] ,
102+ getTaskMode : vi . fn ( ) . mockResolvedValue ( "code" ) ,
102103 api : {
103104 getModel : ( ) => ( { id : "test-model" , info : { } } ) ,
104105 } ,
@@ -118,7 +119,6 @@ describe("presentAssistantMessage - tool usage attribution", () => {
118119 say : vi . fn ( ) . mockResolvedValue ( undefined ) ,
119120 ask : vi . fn ( ) . mockResolvedValue ( { response : "yesButtonClicked" } ) ,
120121 pushToolResultToUserContent : vi . fn ( ) ,
121- getTaskMode : vi . fn ( ) . mockResolvedValue ( "code" ) ,
122122 }
123123
124124 mockTask . pushToolResultToUserContent = vi
@@ -191,6 +191,35 @@ describe("presentAssistantMessage - tool usage attribution", () => {
191191 expect ( mockTask . recordToolUsage ) . not . toHaveBeenCalledWith ( "mcp_" )
192192 } )
193193
194+ it ( "validates tools against the task-local mode when provider state differs" , async ( ) => {
195+ mockTask . getTaskMode . mockResolvedValue ( "code" )
196+ mockTask . providerRef . deref = ( ) => ( {
197+ getState : vi . fn ( ) . mockResolvedValue ( { mode : "orchestrator" , customModes : [ ] } ) ,
198+ } )
199+ mockTask . assistantMessageContent = [
200+ {
201+ type : "tool_use" ,
202+ id : "call_task_mode" ,
203+ name : "read_file" ,
204+ params : { path : "test.txt" } ,
205+ nativeArgs : { path : "test.txt" } ,
206+ partial : false ,
207+ } ,
208+ ]
209+
210+ await presentAssistantMessage ( mockTask as unknown as Task )
211+
212+ expect ( validateToolUse ) . toHaveBeenCalledWith (
213+ "read_file" ,
214+ "code" ,
215+ [ ] ,
216+ { } ,
217+ { path : "test.txt" } ,
218+ undefined ,
219+ undefined ,
220+ )
221+ } )
222+
194223 it ( "records a safe failure key without leaking the raw tool name when validation fails" , async ( ) => {
195224 vi . mocked ( validateToolUse ) . mockImplementation ( ( ) => {
196225 throw new Error ( 'Tool "read_file" is not allowed in this mode.' )
0 commit comments