@@ -1830,6 +1830,186 @@ describe('Rate Limiting and Retry Logic', () => {
18301830 } )
18311831} )
18321832
1833+ describe ( 'stripInternalFields Safety' , ( ) => {
1834+ let cleanupEnvVars : ( ) => void
1835+
1836+ beforeEach ( ( ) => {
1837+ process . env . NEXT_PUBLIC_APP_URL = 'http://localhost:3000'
1838+ cleanupEnvVars = setupEnvVars ( { NEXT_PUBLIC_APP_URL : 'http://localhost:3000' } )
1839+ } )
1840+
1841+ afterEach ( ( ) => {
1842+ vi . resetAllMocks ( )
1843+ cleanupEnvVars ( )
1844+ } )
1845+
1846+ it ( 'should preserve string output from tools without character-indexing' , async ( ) => {
1847+ const stringOutput = '{"type":"button","phone":"917899658001"}'
1848+
1849+ const mockTool = {
1850+ id : 'test_string_output' ,
1851+ name : 'Test String Output' ,
1852+ description : 'A tool that returns a string as output' ,
1853+ version : '1.0.0' ,
1854+ params : { } ,
1855+ request : {
1856+ url : '/api/test/string-output' ,
1857+ method : 'POST' as const ,
1858+ headers : ( ) => ( { 'Content-Type' : 'application/json' } ) ,
1859+ } ,
1860+ transformResponse : vi . fn ( ) . mockResolvedValue ( {
1861+ success : true ,
1862+ output : stringOutput ,
1863+ } ) ,
1864+ }
1865+
1866+ const originalTools = { ...tools }
1867+ ; ( tools as any ) . test_string_output = mockTool
1868+
1869+ global . fetch = Object . assign (
1870+ vi . fn ( ) . mockImplementation ( async ( ) => ( {
1871+ ok : true ,
1872+ status : 200 ,
1873+ headers : new Headers ( ) ,
1874+ json : ( ) => Promise . resolve ( { success : true } ) ,
1875+ } ) ) ,
1876+ { preconnect : vi . fn ( ) }
1877+ ) as typeof fetch
1878+
1879+ const result = await executeTool ( 'test_string_output' , { } , true )
1880+
1881+ expect ( result . success ) . toBe ( true )
1882+ expect ( result . output ) . toBe ( stringOutput )
1883+ expect ( typeof result . output ) . toBe ( 'string' )
1884+
1885+ Object . assign ( tools , originalTools )
1886+ } )
1887+
1888+ it ( 'should preserve array output from tools' , async ( ) => {
1889+ const arrayOutput = [ { id : 1 } , { id : 2 } ]
1890+
1891+ const mockTool = {
1892+ id : 'test_array_output' ,
1893+ name : 'Test Array Output' ,
1894+ description : 'A tool that returns an array as output' ,
1895+ version : '1.0.0' ,
1896+ params : { } ,
1897+ request : {
1898+ url : '/api/test/array-output' ,
1899+ method : 'POST' as const ,
1900+ headers : ( ) => ( { 'Content-Type' : 'application/json' } ) ,
1901+ } ,
1902+ transformResponse : vi . fn ( ) . mockResolvedValue ( {
1903+ success : true ,
1904+ output : arrayOutput ,
1905+ } ) ,
1906+ }
1907+
1908+ const originalTools = { ...tools }
1909+ ; ( tools as any ) . test_array_output = mockTool
1910+
1911+ global . fetch = Object . assign (
1912+ vi . fn ( ) . mockImplementation ( async ( ) => ( {
1913+ ok : true ,
1914+ status : 200 ,
1915+ headers : new Headers ( ) ,
1916+ json : ( ) => Promise . resolve ( { success : true } ) ,
1917+ } ) ) ,
1918+ { preconnect : vi . fn ( ) }
1919+ ) as typeof fetch
1920+
1921+ const result = await executeTool ( 'test_array_output' , { } , true )
1922+
1923+ expect ( result . success ) . toBe ( true )
1924+ expect ( Array . isArray ( result . output ) ) . toBe ( true )
1925+ expect ( result . output ) . toEqual ( arrayOutput )
1926+
1927+ Object . assign ( tools , originalTools )
1928+ } )
1929+
1930+ it ( 'should still strip __-prefixed fields from object output' , async ( ) => {
1931+ const mockTool = {
1932+ id : 'test_strip_internal' ,
1933+ name : 'Test Strip Internal' ,
1934+ description : 'A tool with __internal fields in output' ,
1935+ version : '1.0.0' ,
1936+ params : { } ,
1937+ request : {
1938+ url : '/api/test/strip-internal' ,
1939+ method : 'POST' as const ,
1940+ headers : ( ) => ( { 'Content-Type' : 'application/json' } ) ,
1941+ } ,
1942+ transformResponse : vi . fn ( ) . mockResolvedValue ( {
1943+ success : true ,
1944+ output : { result : 'ok' , __costDollars : 0.05 , _id : 'keep-this' } ,
1945+ } ) ,
1946+ }
1947+
1948+ const originalTools = { ...tools }
1949+ ; ( tools as any ) . test_strip_internal = mockTool
1950+
1951+ global . fetch = Object . assign (
1952+ vi . fn ( ) . mockImplementation ( async ( ) => ( {
1953+ ok : true ,
1954+ status : 200 ,
1955+ headers : new Headers ( ) ,
1956+ json : ( ) => Promise . resolve ( { success : true } ) ,
1957+ } ) ) ,
1958+ { preconnect : vi . fn ( ) }
1959+ ) as typeof fetch
1960+
1961+ const result = await executeTool ( 'test_strip_internal' , { } , true )
1962+
1963+ expect ( result . success ) . toBe ( true )
1964+ expect ( result . output . result ) . toBe ( 'ok' )
1965+ expect ( result . output . __costDollars ) . toBeUndefined ( )
1966+ expect ( result . output . _id ) . toBe ( 'keep-this' )
1967+
1968+ Object . assign ( tools , originalTools )
1969+ } )
1970+
1971+ it ( 'should preserve __-prefixed fields in custom tool output' , async ( ) => {
1972+ const mockTool = {
1973+ id : 'custom_test-preserve-dunder' ,
1974+ name : 'Custom Preserve Dunder' ,
1975+ description : 'A custom tool whose output has __ fields' ,
1976+ version : '1.0.0' ,
1977+ params : { } ,
1978+ request : {
1979+ url : '/api/function/execute' ,
1980+ method : 'POST' as const ,
1981+ headers : ( ) => ( { 'Content-Type' : 'application/json' } ) ,
1982+ } ,
1983+ transformResponse : vi . fn ( ) . mockResolvedValue ( {
1984+ success : true ,
1985+ output : { result : 'ok' , __metadata : { source : 'user' } , __tag : 'important' } ,
1986+ } ) ,
1987+ }
1988+
1989+ const originalTools = { ...tools }
1990+ ; ( tools as any ) [ 'custom_test-preserve-dunder' ] = mockTool
1991+
1992+ global . fetch = Object . assign (
1993+ vi . fn ( ) . mockImplementation ( async ( ) => ( {
1994+ ok : true ,
1995+ status : 200 ,
1996+ headers : new Headers ( ) ,
1997+ json : ( ) => Promise . resolve ( { success : true } ) ,
1998+ } ) ) ,
1999+ { preconnect : vi . fn ( ) }
2000+ ) as typeof fetch
2001+
2002+ const result = await executeTool ( 'custom_test-preserve-dunder' , { } , true )
2003+
2004+ expect ( result . success ) . toBe ( true )
2005+ expect ( result . output . result ) . toBe ( 'ok' )
2006+ expect ( result . output . __metadata ) . toEqual ( { source : 'user' } )
2007+ expect ( result . output . __tag ) . toBe ( 'important' )
2008+
2009+ Object . assign ( tools , originalTools )
2010+ } )
2011+ } )
2012+
18332013describe ( 'Cost Field Handling' , ( ) => {
18342014 let cleanupEnvVars : ( ) => void
18352015
0 commit comments