@@ -1732,5 +1732,187 @@ describe("GPT-5 streaming event coverage (additional)", () => {
17321732 expect ( bodyStr ) . not . toContain ( '"verbosity"' )
17331733 } )
17341734 } )
1735+
1736+ describe ( "Stateless mode configuration" , ( ) => {
1737+ it ( "should use stateless mode when openAiNativeStatelessMode is true" , async ( ) => {
1738+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
1739+ ok : true ,
1740+ body : new ReadableStream ( {
1741+ start ( controller ) {
1742+ controller . enqueue (
1743+ new TextEncoder ( ) . encode ( 'data: {"type":"response.done","response":{}}\n\n' ) ,
1744+ )
1745+ controller . enqueue ( new TextEncoder ( ) . encode ( "data: [DONE]\n\n" ) )
1746+ controller . close ( )
1747+ } ,
1748+ } ) ,
1749+ } )
1750+ ; ( global as any ) . fetch = mockFetch as any
1751+
1752+ // Force SDK path to fail so we use fetch fallback
1753+ mockResponsesCreate . mockRejectedValue ( new Error ( "SDK not available" ) )
1754+
1755+ const handler = new OpenAiNativeHandler ( {
1756+ apiModelId : "gpt-5-2025-08-07" ,
1757+ openAiNativeApiKey : "test-api-key" ,
1758+ openAiNativeStatelessMode : true , // Enable stateless mode
1759+ } )
1760+
1761+ const systemPrompt = "You are a helpful assistant."
1762+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1763+ const stream = handler . createMessage ( systemPrompt , messages )
1764+
1765+ for await ( const _ of stream ) {
1766+ // drain
1767+ }
1768+
1769+ const bodyStr = ( mockFetch . mock . calls [ 0 ] [ 1 ] as any ) . body as string
1770+ const parsedBody = JSON . parse ( bodyStr )
1771+ expect ( parsedBody . store ) . toBe ( false ) // Should be false when stateless mode is enabled
1772+ } )
1773+
1774+ it ( "should default to store: true when openAiNativeStatelessMode is false" , async ( ) => {
1775+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
1776+ ok : true ,
1777+ body : new ReadableStream ( {
1778+ start ( controller ) {
1779+ controller . enqueue (
1780+ new TextEncoder ( ) . encode ( 'data: {"type":"response.done","response":{}}\n\n' ) ,
1781+ )
1782+ controller . enqueue ( new TextEncoder ( ) . encode ( "data: [DONE]\n\n" ) )
1783+ controller . close ( )
1784+ } ,
1785+ } ) ,
1786+ } )
1787+ ; ( global as any ) . fetch = mockFetch as any
1788+
1789+ // Force SDK path to fail so we use fetch fallback
1790+ mockResponsesCreate . mockRejectedValue ( new Error ( "SDK not available" ) )
1791+
1792+ const handler = new OpenAiNativeHandler ( {
1793+ apiModelId : "gpt-5-2025-08-07" ,
1794+ openAiNativeApiKey : "test-api-key" ,
1795+ openAiNativeStatelessMode : false , // Explicitly disable stateless mode
1796+ } )
1797+
1798+ const systemPrompt = "You are a helpful assistant."
1799+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1800+ const stream = handler . createMessage ( systemPrompt , messages )
1801+
1802+ for await ( const _ of stream ) {
1803+ // drain
1804+ }
1805+
1806+ const bodyStr = ( mockFetch . mock . calls [ 0 ] [ 1 ] as any ) . body as string
1807+ const parsedBody = JSON . parse ( bodyStr )
1808+ expect ( parsedBody . store ) . toBe ( true ) // Should be true when stateless mode is disabled
1809+ } )
1810+
1811+ it ( "should default to store: true when openAiNativeStatelessMode is not set" , async ( ) => {
1812+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
1813+ ok : true ,
1814+ body : new ReadableStream ( {
1815+ start ( controller ) {
1816+ controller . enqueue (
1817+ new TextEncoder ( ) . encode ( 'data: {"type":"response.done","response":{}}\n\n' ) ,
1818+ )
1819+ controller . enqueue ( new TextEncoder ( ) . encode ( "data: [DONE]\n\n" ) )
1820+ controller . close ( )
1821+ } ,
1822+ } ) ,
1823+ } )
1824+ ; ( global as any ) . fetch = mockFetch as any
1825+
1826+ // Force SDK path to fail so we use fetch fallback
1827+ mockResponsesCreate . mockRejectedValue ( new Error ( "SDK not available" ) )
1828+
1829+ const handler = new OpenAiNativeHandler ( {
1830+ apiModelId : "gpt-5-2025-08-07" ,
1831+ openAiNativeApiKey : "test-api-key" ,
1832+ // openAiNativeStatelessMode not set
1833+ } )
1834+
1835+ const systemPrompt = "You are a helpful assistant."
1836+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1837+ const stream = handler . createMessage ( systemPrompt , messages )
1838+
1839+ for await ( const _ of stream ) {
1840+ // drain
1841+ }
1842+
1843+ const bodyStr = ( mockFetch . mock . calls [ 0 ] [ 1 ] as any ) . body as string
1844+ const parsedBody = JSON . parse ( bodyStr )
1845+ expect ( parsedBody . store ) . toBe ( true ) // Should default to true
1846+ } )
1847+
1848+ it ( "should override metadata.store when openAiNativeStatelessMode is true" , async ( ) => {
1849+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
1850+ ok : true ,
1851+ body : new ReadableStream ( {
1852+ start ( controller ) {
1853+ controller . enqueue (
1854+ new TextEncoder ( ) . encode ( 'data: {"type":"response.done","response":{}}\n\n' ) ,
1855+ )
1856+ controller . enqueue ( new TextEncoder ( ) . encode ( "data: [DONE]\n\n" ) )
1857+ controller . close ( )
1858+ } ,
1859+ } ) ,
1860+ } )
1861+ ; ( global as any ) . fetch = mockFetch as any
1862+
1863+ // Force SDK path to fail so we use fetch fallback
1864+ mockResponsesCreate . mockRejectedValue ( new Error ( "SDK not available" ) )
1865+
1866+ const handler = new OpenAiNativeHandler ( {
1867+ apiModelId : "gpt-5-2025-08-07" ,
1868+ openAiNativeApiKey : "test-api-key" ,
1869+ openAiNativeStatelessMode : true , // Enable stateless mode
1870+ } )
1871+
1872+ const systemPrompt = "You are a helpful assistant."
1873+ const messages : Anthropic . Messages . MessageParam [ ] = [ { role : "user" , content : "Hello!" } ]
1874+ // Even if metadata.store is true, stateless mode should override it
1875+ const stream = handler . createMessage ( systemPrompt , messages , { taskId : "test" , store : true } )
1876+
1877+ for await ( const _ of stream ) {
1878+ // drain
1879+ }
1880+
1881+ const bodyStr = ( mockFetch . mock . calls [ 0 ] [ 1 ] as any ) . body as string
1882+ const parsedBody = JSON . parse ( bodyStr )
1883+ expect ( parsedBody . store ) . toBe ( false ) // Should be false even when metadata.store is true
1884+ } )
1885+
1886+ it ( "should use stateless mode in completePrompt when openAiNativeStatelessMode is true" , async ( ) => {
1887+ // Mock the responses.create method
1888+ mockResponsesCreate . mockResolvedValue ( {
1889+ output : [
1890+ {
1891+ type : "message" ,
1892+ content : [
1893+ {
1894+ type : "output_text" ,
1895+ text : "Test response" ,
1896+ } ,
1897+ ] ,
1898+ } ,
1899+ ] ,
1900+ } )
1901+
1902+ const handler = new OpenAiNativeHandler ( {
1903+ apiModelId : "gpt-5-2025-08-07" ,
1904+ openAiNativeApiKey : "test-api-key" ,
1905+ openAiNativeStatelessMode : true , // Enable stateless mode
1906+ } )
1907+
1908+ await handler . completePrompt ( "Test prompt" )
1909+
1910+ expect ( mockResponsesCreate ) . toHaveBeenCalledWith (
1911+ expect . objectContaining ( {
1912+ store : false , // Should always be false in completePrompt with stateless mode
1913+ } ) ,
1914+ )
1915+ } )
1916+ } )
17351917 } )
17361918} )
0 commit comments