@@ -263,10 +263,13 @@ describe("VertexHandler", () => {
263263 ] ,
264264 stream : true ,
265265 // Tools are now always present (minimum 6 from ALWAYS_AVAILABLE_TOOLS)
266- tools : expect . any ( Array ) ,
267- tool_choice : expect . any ( Object ) ,
266+ tools : [ ] ,
267+ tool_choice : {
268+ disable_parallel_tool_use : false ,
269+ type : "auto" ,
270+ } ,
268271 } ) ,
269- undefined ,
272+ { } ,
270273 )
271274 } )
272275
@@ -481,7 +484,7 @@ describe("VertexHandler", () => {
481484 } ) ,
482485 ] ,
483486 } ) ,
484- undefined ,
487+ { } ,
485488 )
486489 } )
487490
@@ -1156,7 +1159,7 @@ describe("VertexHandler", () => {
11561159 }
11571160
11581161 // Verify the API was called without the beta header
1159- expect ( mockCreate ) . toHaveBeenCalledWith ( expect . anything ( ) , undefined )
1162+ expect ( mockCreate ) . toHaveBeenCalledWith ( expect . anything ( ) , { } )
11601163 } )
11611164 } )
11621165
@@ -1246,7 +1249,7 @@ describe("VertexHandler", () => {
12461249 thinking : { type : "enabled" , budget_tokens : 4096 } ,
12471250 temperature : 1.0 , // Thinking requires temperature 1.0
12481251 } ) ,
1249- undefined ,
1252+ { } ,
12501253 )
12511254 } )
12521255
@@ -1273,7 +1276,7 @@ describe("VertexHandler", () => {
12731276 expect . objectContaining ( {
12741277 thinking : { type : "adaptive" } ,
12751278 } ) ,
1276- undefined ,
1279+ { } ,
12771280 )
12781281
12791282 const request = mockCreate . mock . calls [ 0 ] [ 0 ]
@@ -1302,7 +1305,7 @@ describe("VertexHandler", () => {
13021305 expect . objectContaining ( {
13031306 thinking : { type : "adaptive" } ,
13041307 } ) ,
1305- undefined ,
1308+ { } ,
13061309 )
13071310
13081311 const request = mockCreate . mock . calls [ 0 ] [ 0 ]
@@ -1393,7 +1396,7 @@ describe("VertexHandler", () => {
13931396 ] ) ,
13941397 tool_choice : { type : "auto" , disable_parallel_tool_use : false } ,
13951398 } ) ,
1396- undefined ,
1399+ { } ,
13971400 )
13981401 } )
13991402
@@ -1446,7 +1449,7 @@ describe("VertexHandler", () => {
14461449 } ) ,
14471450 ] ) ,
14481451 } ) ,
1449- undefined ,
1452+ { } ,
14501453 )
14511454 } )
14521455
@@ -1611,4 +1614,157 @@ describe("VertexHandler", () => {
16111614 } )
16121615 } )
16131616 } )
1617+
1618+ describe ( "abort signal" , ( ) => {
1619+ it ( "should handle abort signal triggered during request" , async ( ) => {
1620+ const controller = new AbortController ( )
1621+ const handler = new AnthropicVertexHandler ( {
1622+ apiModelId : "claude-3-sonnet" ,
1623+ vertexProjectId : "test-project" ,
1624+ vertexRegion : "us-central1" ,
1625+ } )
1626+
1627+ const mockStream = async function * ( ) {
1628+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
1629+ if ( controller . signal . aborted ) {
1630+ throw new Error ( "AbortError: The operation was aborted" )
1631+ }
1632+ yield {
1633+ type : "message_start" ,
1634+ message : { usage : { input_tokens : 10 , output_tokens : 0 } } ,
1635+ }
1636+ }
1637+
1638+ ; ( handler [ "client" ] . messages as any ) . create = vitest . fn ( ) . mockResolvedValue ( mockStream ( ) )
1639+
1640+ const stream = handler . createMessage ( "system" , [ { role : "user" , content : "Hello" } ] , {
1641+ taskId : "test" ,
1642+ tools : [ ] ,
1643+ abortSignal : controller . signal ,
1644+ } )
1645+
1646+ const chunks : any [ ] = [ ]
1647+ for await ( const chunk of stream ) {
1648+ chunks . push ( chunk )
1649+ }
1650+
1651+ expect ( chunks . length ) . toBeGreaterThan ( 0 )
1652+ } )
1653+
1654+ it ( "should not pass signal when abortSignal is undefined" , async ( ) => {
1655+ const handler = new AnthropicVertexHandler ( {
1656+ apiModelId : "claude-3-sonnet" ,
1657+ vertexProjectId : "test-project" ,
1658+ vertexRegion : "us-central1" ,
1659+ } )
1660+
1661+ const mockStream = async function * ( ) {
1662+ yield {
1663+ type : "message_start" ,
1664+ message : { usage : { input_tokens : 10 , output_tokens : 5 } } ,
1665+ }
1666+ yield {
1667+ type : "content_block_start" ,
1668+ content_block : { type : "text" , text : "" } ,
1669+ }
1670+ yield {
1671+ type : "content_block_delta" ,
1672+ delta : { type : "text_delta" , text : "response" } ,
1673+ }
1674+ }
1675+
1676+ ; ( handler [ "client" ] . messages as any ) . create = vitest . fn ( ) . mockResolvedValue ( mockStream ( ) )
1677+
1678+ const stream = handler . createMessage ( "system" , [ { role : "user" , content : "Hello" } ] )
1679+
1680+ const chunks : any [ ] = [ ]
1681+ for await ( const chunk of stream ) {
1682+ chunks . push ( chunk )
1683+ }
1684+
1685+ expect ( chunks . length ) . toBeGreaterThan ( 0 )
1686+ } )
1687+
1688+ it ( "should abort immediately if signal is already aborted" , async ( ) => {
1689+ const controller = new AbortController ( )
1690+ controller . abort ( )
1691+
1692+ const testHandler = new AnthropicVertexHandler ( {
1693+ apiModelId : "claude-3-sonnet" ,
1694+ vertexProjectId : "test-project" ,
1695+ vertexRegion : "us-central1" ,
1696+ } )
1697+
1698+ testHandler [ "client" ] . messages . create = vitest . fn ( ) . mockImplementation ( async ( options , requestOptions ) => {
1699+ // Verify that the signal was passed and is already aborted
1700+ expect ( requestOptions ) . toHaveProperty ( "signal" , controller . signal )
1701+ expect ( controller . signal . aborted ) . toBe ( true )
1702+
1703+ return {
1704+ [ Symbol . asyncIterator ] : async function * ( ) {
1705+ if ( controller . signal . aborted ) {
1706+ throw new Error ( "AbortError: The operation was aborted" )
1707+ }
1708+ yield {
1709+ type : "message_start" ,
1710+ message : { usage : { input_tokens : 10 , output_tokens : 5 } } ,
1711+ }
1712+ } ,
1713+ }
1714+ } )
1715+
1716+ const stream = testHandler . createMessage ( "system" , [ { role : "user" , content : "Hello" } ] , {
1717+ taskId : "test" ,
1718+ tools : [ ] ,
1719+ abortSignal : controller . signal ,
1720+ } )
1721+
1722+ await expect ( async ( ) => {
1723+ for await ( const _chunk of stream ) {
1724+ // consume stream
1725+ }
1726+ } ) . rejects . toThrow ( / a b o r t / i)
1727+ } )
1728+
1729+ it ( "should pass signal when provided" , async ( ) => {
1730+ const controller = new AbortController ( )
1731+ let capturedRequestOptions : any
1732+
1733+ const testHandler = new AnthropicVertexHandler ( {
1734+ apiModelId : "claude-3-sonnet" ,
1735+ vertexProjectId : "test-project" ,
1736+ vertexRegion : "us-central1" ,
1737+ } )
1738+
1739+ testHandler [ "client" ] . messages . create = vitest . fn ( ) . mockImplementation ( async ( options , requestOptions ) => {
1740+ capturedRequestOptions = requestOptions
1741+ return {
1742+ [ Symbol . asyncIterator ] : async function * ( ) {
1743+ yield {
1744+ type : "message_start" ,
1745+ message : { usage : { input_tokens : 10 , output_tokens : 5 } } ,
1746+ }
1747+ yield {
1748+ type : "content_block_delta" ,
1749+ delta : { type : "text_delta" , text : "response" } ,
1750+ }
1751+ } ,
1752+ }
1753+ } )
1754+
1755+ const stream = testHandler . createMessage ( "system" , [ { role : "user" , content : "Hello" } ] , {
1756+ taskId : "test" ,
1757+ tools : [ ] ,
1758+ abortSignal : controller . signal ,
1759+ } )
1760+
1761+ const chunks : any [ ] = [ ]
1762+ for await ( const chunk of stream ) {
1763+ chunks . push ( chunk )
1764+ }
1765+
1766+ expect ( chunks . length ) . toBeGreaterThan ( 0 )
1767+ expect ( capturedRequestOptions ) . toHaveProperty ( "signal" , controller . signal )
1768+ } )
1769+ } )
16141770} )
0 commit comments