@@ -2,30 +2,32 @@ import type { Model } from "@mariozechner/pi-ai";
22import { beforeAll , beforeEach , describe , expect , it , vi } from "vitest" ;
33import { attachModelProviderRequestTransport } from "./provider-request-config.js" ;
44
5- const {
6- anthropicCtorMock,
7- anthropicMessagesStreamMock,
8- buildGuardedModelFetchMock,
9- guardedFetchMock,
10- } = vi . hoisted ( ( ) => ( {
11- anthropicCtorMock : vi . fn ( ) ,
12- anthropicMessagesStreamMock : vi . fn ( ) ,
5+ const { buildGuardedModelFetchMock, guardedFetchMock } = vi . hoisted ( ( ) => ( {
136 buildGuardedModelFetchMock : vi . fn ( ) ,
147 guardedFetchMock : vi . fn ( ) ,
158} ) ) ;
169
17- vi . mock ( "@anthropic-ai/sdk" , ( ) => ( {
18- default : anthropicCtorMock ,
19- } ) ) ;
20-
2110vi . mock ( "./provider-transport-fetch.js" , ( ) => ( {
2211 buildGuardedModelFetch : buildGuardedModelFetchMock ,
2312} ) ) ;
2413
2514let createAnthropicMessagesTransportStreamFn : typeof import ( "./anthropic-transport-stream.js" ) . createAnthropicMessagesTransportStreamFn ;
2615
27- function emptyEventStream ( ) : AsyncIterable < Record < string , unknown > > {
28- return ( async function * ( ) { } ) ( ) ;
16+ function createSseResponse ( events : Record < string , unknown > [ ] = [ ] ) : Response {
17+ const body = events . map ( ( event ) => `data: ${ JSON . stringify ( event ) } \n\n` ) . join ( "" ) ;
18+ return new Response ( body , {
19+ status : 200 ,
20+ headers : { "content-type" : "text/event-stream" } ,
21+ } ) ;
22+ }
23+
24+ function latestAnthropicRequest ( ) {
25+ const [ , init ] = guardedFetchMock . mock . calls . at ( - 1 ) ?? [ ] ;
26+ const body = init ?. body ;
27+ return {
28+ init,
29+ payload : typeof body === "string" ? ( JSON . parse ( body ) as Record < string , unknown > ) : { } ,
30+ } ;
2931}
3032
3133describe ( "anthropic transport stream" , ( ) => {
@@ -35,19 +37,10 @@ describe("anthropic transport stream", () => {
3537 } ) ;
3638
3739 beforeEach ( ( ) => {
38- anthropicCtorMock . mockReset ( ) ;
39- anthropicMessagesStreamMock . mockReset ( ) ;
4040 buildGuardedModelFetchMock . mockReset ( ) ;
4141 guardedFetchMock . mockReset ( ) ;
4242 buildGuardedModelFetchMock . mockReturnValue ( guardedFetchMock ) ;
43- anthropicMessagesStreamMock . mockReturnValue ( emptyEventStream ( ) ) ;
44- anthropicCtorMock . mockImplementation ( function mockAnthropicClient ( ) {
45- return {
46- messages : {
47- stream : anthropicMessagesStreamMock ,
48- } ,
49- } ;
50- } ) ;
43+ guardedFetchMock . mockResolvedValue ( createSseResponse ( ) ) ;
5144 } ) ;
5245
5346 it ( "uses the guarded fetch transport for api-key Anthropic requests" , async ( ) => {
@@ -89,26 +82,25 @@ describe("anthropic transport stream", () => {
8982 await stream . result ( ) ;
9083
9184 expect ( buildGuardedModelFetchMock ) . toHaveBeenCalledWith ( model ) ;
92- expect ( anthropicCtorMock ) . toHaveBeenCalledWith (
85+ expect ( guardedFetchMock ) . toHaveBeenCalledWith (
86+ "https://api.anthropic.com/v1/messages" ,
9387 expect . objectContaining ( {
94- apiKey : "sk-ant-api" ,
95- baseURL : "https://api.anthropic.com" ,
96- fetch : guardedFetchMock ,
97- defaultHeaders : expect . objectContaining ( {
88+ method : "POST" ,
89+ headers : expect . objectContaining ( {
90+ "x-api-key" : "sk-ant-api" ,
91+ "anthropic-version" : "2023-06-01" ,
92+ "content-type" : "application/json" ,
9893 accept : "application/json" ,
9994 "anthropic-dangerous-direct-browser-access" : "true" ,
10095 "X-Provider" : "anthropic" ,
10196 "X-Call" : "1" ,
10297 } ) ,
10398 } ) ,
10499 ) ;
105- expect ( anthropicMessagesStreamMock ) . toHaveBeenCalledWith (
106- expect . objectContaining ( {
107- model : "claude-sonnet-4-6" ,
108- stream : true ,
109- } ) ,
110- undefined ,
111- ) ;
100+ expect ( latestAnthropicRequest ( ) . payload ) . toMatchObject ( {
101+ model : "claude-sonnet-4-6" ,
102+ stream : true ,
103+ } ) ;
112104 } ) ;
113105
114106 it ( "ignores non-positive runtime maxTokens overrides and falls back to the model limit" , async ( ) => {
@@ -147,14 +139,11 @@ describe("anthropic transport stream", () => {
147139 ) ;
148140 await stream . result ( ) ;
149141
150- expect ( anthropicMessagesStreamMock ) . toHaveBeenCalledWith (
151- expect . objectContaining ( {
152- model : "claude-sonnet-4-6" ,
153- max_tokens : 8192 ,
154- stream : true ,
155- } ) ,
156- undefined ,
157- ) ;
142+ expect ( latestAnthropicRequest ( ) . payload ) . toMatchObject ( {
143+ model : "claude-sonnet-4-6" ,
144+ max_tokens : 8192 ,
145+ stream : true ,
146+ } ) ;
158147 } ) ;
159148
160149 it ( "ignores fractional runtime maxTokens overrides that floor to zero" , async ( ) => {
@@ -193,14 +182,11 @@ describe("anthropic transport stream", () => {
193182 ) ;
194183 await stream . result ( ) ;
195184
196- expect ( anthropicMessagesStreamMock ) . toHaveBeenCalledWith (
197- expect . objectContaining ( {
198- model : "claude-sonnet-4-6" ,
199- max_tokens : 8192 ,
200- stream : true ,
201- } ) ,
202- undefined ,
203- ) ;
185+ expect ( latestAnthropicRequest ( ) . payload ) . toMatchObject ( {
186+ model : "claude-sonnet-4-6" ,
187+ max_tokens : 8192 ,
188+ stream : true ,
189+ } ) ;
204190 } ) ;
205191
206192 it ( "fails locally when Anthropic maxTokens is non-positive after resolution" , async ( ) => {
@@ -243,17 +229,17 @@ describe("anthropic transport stream", () => {
243229 expect ( result . errorMessage ) . toContain (
244230 "Anthropic Messages transport requires a positive maxTokens value" ,
245231 ) ;
246- expect ( anthropicMessagesStreamMock ) . not . toHaveBeenCalled ( ) ;
232+ expect ( guardedFetchMock ) . not . toHaveBeenCalled ( ) ;
247233 } ) ;
248234
249235 it ( "preserves Anthropic OAuth identity and tool-name remapping with transport overrides" , async ( ) => {
250- anthropicMessagesStreamMock . mockReturnValueOnce (
251- ( async function * ( ) {
252- yield {
236+ guardedFetchMock . mockResolvedValueOnce (
237+ createSseResponse ( [
238+ {
253239 type : "message_start" ,
254240 message : { id : "msg_1" , usage : { input_tokens : 10 , output_tokens : 0 } } ,
255- } ;
256- yield {
241+ } ,
242+ {
257243 type : "content_block_start" ,
258244 index : 0 ,
259245 content_block : {
@@ -262,17 +248,17 @@ describe("anthropic transport stream", () => {
262248 name : "Read" ,
263249 input : { path : "/tmp/a" } ,
264250 } ,
265- } ;
266- yield {
251+ } ,
252+ {
267253 type : "content_block_stop" ,
268254 index : 0 ,
269- } ;
270- yield {
255+ } ,
256+ {
271257 type : "message_delta" ,
272258 delta : { stop_reason : "tool_use" } ,
273259 usage : { input_tokens : 10 , output_tokens : 5 } ,
274- } ;
275- } ) ( ) ,
260+ } ,
261+ ] ) ,
276262 ) ;
277263 const model = attachModelProviderRequestTransport (
278264 {
@@ -321,21 +307,17 @@ describe("anthropic transport stream", () => {
321307 ) ;
322308 const result = await stream . result ( ) ;
323309
324- expect ( anthropicCtorMock ) . toHaveBeenCalledWith (
310+ expect ( guardedFetchMock ) . toHaveBeenCalledWith (
311+ "https://api.anthropic.com/v1/messages" ,
325312 expect . objectContaining ( {
326- apiKey : null ,
327- authToken : "sk-ant-oat-example" ,
328- fetch : guardedFetchMock ,
329- defaultHeaders : expect . objectContaining ( {
313+ headers : expect . objectContaining ( {
314+ authorization : "Bearer sk-ant-oat-example" ,
330315 "x-app" : "cli" ,
331316 "user-agent" : expect . stringContaining ( "claude-cli/" ) ,
332317 } ) ,
333318 } ) ,
334319 ) ;
335- const firstCallParams = anthropicMessagesStreamMock . mock . calls [ 0 ] ?. [ 0 ] as Record <
336- string ,
337- unknown
338- > ;
320+ const firstCallParams = latestAnthropicRequest ( ) . payload ;
339321 expect ( firstCallParams . system ) . toEqual (
340322 expect . arrayContaining ( [
341323 expect . objectContaining ( {
@@ -407,10 +389,7 @@ describe("anthropic transport stream", () => {
407389 ) ;
408390 await stream . result ( ) ;
409391
410- const firstCallParams = anthropicMessagesStreamMock . mock . calls [ 0 ] ?. [ 0 ] as Record <
411- string ,
412- unknown
413- > ;
392+ const firstCallParams = latestAnthropicRequest ( ) . payload ;
414393 expect ( firstCallParams . messages ) . toEqual (
415394 expect . arrayContaining ( [
416395 expect . objectContaining ( {
@@ -463,13 +442,10 @@ describe("anthropic transport stream", () => {
463442 ) ;
464443 await stream . result ( ) ;
465444
466- expect ( anthropicMessagesStreamMock ) . toHaveBeenCalledWith (
467- expect . objectContaining ( {
468- thinking : { type : "adaptive" } ,
469- output_config : { effort : "max" } ,
470- } ) ,
471- undefined ,
472- ) ;
445+ expect ( latestAnthropicRequest ( ) . payload ) . toMatchObject ( {
446+ thinking : { type : "adaptive" } ,
447+ output_config : { effort : "max" } ,
448+ } ) ;
473449 } ) ;
474450
475451 it ( "maps xhigh thinking effort for Claude Opus 4.7 transport runs" , async ( ) => {
@@ -508,12 +484,9 @@ describe("anthropic transport stream", () => {
508484 ) ;
509485 await stream . result ( ) ;
510486
511- expect ( anthropicMessagesStreamMock ) . toHaveBeenCalledWith (
512- expect . objectContaining ( {
513- thinking : { type : "adaptive" } ,
514- output_config : { effort : "xhigh" } ,
515- } ) ,
516- undefined ,
517- ) ;
487+ expect ( latestAnthropicRequest ( ) . payload ) . toMatchObject ( {
488+ thinking : { type : "adaptive" } ,
489+ output_config : { effort : "xhigh" } ,
490+ } ) ;
518491 } ) ;
519492} ) ;
0 commit comments