@@ -1252,6 +1252,92 @@ describe("OpenAiHandler", () => {
12521252 } )
12531253 } )
12541254
1255+ describe ( "Grok xAI false-positive prevention" , ( ) => {
1256+ it ( "should NOT detect as Grok xAI when host contains 'x.ai' as a substring but is not x.ai (e.g. box.ai)" , ( ) => {
1257+ const nonGrokOptions = {
1258+ ...mockOptions ,
1259+ openAiBaseUrl : "https://box.ai/v1" ,
1260+ openAiModelId : "gpt-4o" ,
1261+ }
1262+ const handler = new OpenAiHandler ( nonGrokOptions )
1263+ expect ( handler [ "_isGrokXAI" ] ( nonGrokOptions . openAiBaseUrl ) ) . toBe ( false )
1264+ } )
1265+
1266+ it ( "should NOT detect as Grok xAI for other domains containing 'x.ai' substring (e.g. fox.ai, max.ai)" , ( ) => {
1267+ const handler = new OpenAiHandler ( { ...mockOptions , openAiBaseUrl : "https://fox.ai/v1" } )
1268+ expect ( handler [ "_isGrokXAI" ] ( "https://fox.ai/v1" ) ) . toBe ( false )
1269+ expect ( handler [ "_isGrokXAI" ] ( "https://max.ai/v1" ) ) . toBe ( false )
1270+ } )
1271+
1272+ it ( "should detect as Grok xAI for api.x.ai" , ( ) => {
1273+ const handler = new OpenAiHandler ( { ...mockOptions , openAiBaseUrl : "https://api.x.ai/v1" } )
1274+ expect ( handler [ "_isGrokXAI" ] ( "https://api.x.ai/v1" ) ) . toBe ( true )
1275+ } )
1276+
1277+ it ( "should detect as Grok xAI for subdomains of x.ai (e.g. custom.x.ai)" , ( ) => {
1278+ const handler = new OpenAiHandler ( { ...mockOptions , openAiBaseUrl : "https://custom.x.ai/v1" } )
1279+ expect ( handler [ "_isGrokXAI" ] ( "https://custom.x.ai/v1" ) ) . toBe ( true )
1280+ } )
1281+
1282+ it ( "should detect as Grok xAI when api.x.ai uses a non-default port" , ( ) => {
1283+ const handler = new OpenAiHandler ( { ...mockOptions , openAiBaseUrl : "https://api.x.ai:8443/v1" } )
1284+ expect ( handler [ "_isGrokXAI" ] ( "https://api.x.ai:8443/v1" ) ) . toBe ( true )
1285+ } )
1286+
1287+ it ( "should exclude stream_options when streaming with api.x.ai on a non-default port" , async ( ) => {
1288+ const portOptions = {
1289+ ...mockOptions ,
1290+ openAiBaseUrl : "https://api.x.ai:8443/v1" ,
1291+ openAiModelId : "grok-1" ,
1292+ }
1293+ const handler = new OpenAiHandler ( portOptions )
1294+ const systemPrompt = "You are a helpful assistant."
1295+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1296+
1297+ const stream = handler . createMessage ( systemPrompt , messages )
1298+ await stream . next ( )
1299+
1300+ expect ( mockCreate ) . toHaveBeenCalledWith (
1301+ expect . objectContaining ( {
1302+ model : portOptions . openAiModelId ,
1303+ stream : true ,
1304+ } ) ,
1305+ { } ,
1306+ )
1307+
1308+ const mockCalls = mockCreate . mock . calls
1309+ const lastCall = mockCalls [ mockCalls . length - 1 ]
1310+ expect ( lastCall [ 0 ] ) . not . toHaveProperty ( "stream_options" )
1311+ } )
1312+
1313+ it ( "should include stream_options when using a non-Grok provider whose URL contains 'x.ai' substring" , async ( ) => {
1314+ const nonGrokOptions = {
1315+ ...mockOptions ,
1316+ openAiBaseUrl : "https://box.ai/v1" ,
1317+ openAiModelId : "gpt-4o" ,
1318+ }
1319+ const handler = new OpenAiHandler ( nonGrokOptions )
1320+ const systemPrompt = "You are a helpful assistant."
1321+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1322+
1323+ const stream = handler . createMessage ( systemPrompt , messages )
1324+ await stream . next ( )
1325+
1326+ expect ( mockCreate ) . toHaveBeenCalledWith (
1327+ expect . objectContaining ( {
1328+ model : nonGrokOptions . openAiModelId ,
1329+ stream : true ,
1330+ } ) ,
1331+ { } ,
1332+ )
1333+
1334+ const mockCalls = mockCreate . mock . calls
1335+ const lastCall = mockCalls [ mockCalls . length - 1 ]
1336+ expect ( lastCall [ 0 ] ) . toHaveProperty ( "stream_options" )
1337+ expect ( lastCall [ 0 ] . stream_options ) . toEqual ( { include_usage : true } )
1338+ } )
1339+ } )
1340+
12551341 describe ( "O3 Family Models" , ( ) => {
12561342 const o3Options = {
12571343 ...mockOptions ,
@@ -1630,6 +1716,25 @@ describe("OpenAiHandler", () => {
16301716 { path : "/models/chat/completions" } ,
16311717 )
16321718 } )
1719+
1720+ it ( "should exclude stream_options when O3 model uses Grok xAI base URL" , async ( ) => {
1721+ const handler = new OpenAiHandler ( { ...o3Options , openAiBaseUrl : "https://api.x.ai/v1" } )
1722+ const stream = handler . createMessage ( "You are a helpful assistant." , [ { role : "user" , content : "Hello!" } ] )
1723+ await stream . next ( )
1724+
1725+ const lastCall = mockCreate . mock . calls [ mockCreate . mock . calls . length - 1 ]
1726+ expect ( lastCall [ 0 ] ) . not . toHaveProperty ( "stream_options" )
1727+ } )
1728+
1729+ it ( "should include stream_options when O3 model uses non-Grok URL containing 'x.ai' substring" , async ( ) => {
1730+ const handler = new OpenAiHandler ( { ...o3Options , openAiBaseUrl : "https://box.ai/v1" } )
1731+ const stream = handler . createMessage ( "You are a helpful assistant." , [ { role : "user" , content : "Hello!" } ] )
1732+ await stream . next ( )
1733+
1734+ const lastCall = mockCreate . mock . calls [ mockCreate . mock . calls . length - 1 ]
1735+ expect ( lastCall [ 0 ] ) . toHaveProperty ( "stream_options" )
1736+ expect ( lastCall [ 0 ] . stream_options ) . toEqual ( { include_usage : true } )
1737+ } )
16331738 } )
16341739} )
16351740
0 commit comments