@@ -360,6 +360,64 @@ describe("OpenAI Responses route", () => {
360360 } ) ,
361361 )
362362
363+ it . effect ( "preserves structured tool errors for the model" , ( ) =>
364+ Effect . gen ( function * ( ) {
365+ const error = {
366+ error : { type : "unknown" , message : "Tool execution interrupted" } ,
367+ content : [ ] ,
368+ structured : { } ,
369+ }
370+ const prepared = yield * LLMClient . prepare < OpenAIResponses . OpenAIResponsesBody > (
371+ LLM . request ( {
372+ model,
373+ messages : [
374+ Message . assistant ( [ ToolCallPart . make ( { id : "call_1" , name : "bash" , input : { command : "sleep 10" } } ) ] ) ,
375+ Message . tool ( {
376+ id : "call_1" ,
377+ name : "bash" ,
378+ resultType : "error" ,
379+ result : error ,
380+ } ) ,
381+ ] ,
382+ } ) ,
383+ )
384+
385+ expect ( expectToolOutput ( prepared . body ) . output ) . toBe ( ProviderShared . encodeJson ( error ) )
386+ } ) ,
387+ )
388+
389+ it . effect ( "keeps primitive tool errors as plain text" , ( ) =>
390+ Effect . gen ( function * ( ) {
391+ const prepared = yield * LLMClient . prepare < OpenAIResponses . OpenAIResponsesBody > (
392+ LLM . request ( {
393+ model,
394+ messages : [
395+ Message . assistant ( [ ToolCallPart . make ( { id : "call_1" , name : "bash" , input : { } } ) ] ) ,
396+ Message . tool ( { id : "call_1" , name : "bash" , resultType : "error" , result : 503 } ) ,
397+ ] ,
398+ } ) ,
399+ )
400+
401+ expect ( expectToolOutput ( prepared . body ) . output ) . toBe ( "503" )
402+ } ) ,
403+ )
404+
405+ it . effect ( "keeps non-JSON tool errors as plain text" , ( ) =>
406+ Effect . gen ( function * ( ) {
407+ const prepared = yield * LLMClient . prepare < OpenAIResponses . OpenAIResponsesBody > (
408+ LLM . request ( {
409+ model,
410+ messages : [
411+ Message . assistant ( [ ToolCallPart . make ( { id : "call_1" , name : "bash" , input : { } } ) ] ) ,
412+ Message . tool ( { id : "call_1" , name : "bash" , resultType : "error" , result : new Error ( "boom" ) } ) ,
413+ ] ,
414+ } ) ,
415+ )
416+
417+ expect ( expectToolOutput ( prepared . body ) . output ) . toBe ( "Error: boom" )
418+ } ) ,
419+ )
420+
363421 // Regression: screenshot/read tool results must stay structured so base64
364422 // image data is not JSON-stringified into `function_call_output.output`.
365423 it . effect ( "lowers image tool-result content as structured input_image items" , ( ) =>
0 commit comments