33 augmentPromptForSchema ,
44 enforceAgentSchema ,
55 formatAjvErrors ,
6+ NATIVE_SCHEMA_PROVIDERS ,
67} from "./workflow-schema.js" ;
78import { WorkflowEngineError } from "./workflow-api.js" ;
89
@@ -21,6 +22,10 @@ assert.equal(
2122 "/n must be number" ,
2223) ;
2324
25+ assert . ok ( NATIVE_SCHEMA_PROVIDERS . has ( "codex" ) ) ;
26+ assert . ok ( NATIVE_SCHEMA_PROVIDERS . has ( "claude" ) ) ;
27+ assert . ok ( ! NATIVE_SCHEMA_PROVIDERS . has ( "opencode" ) ) ;
28+
2429{
2530 let attempts = 0 ;
2631 const result = await enforceAgentSchema ( {
@@ -40,6 +45,7 @@ assert.equal(
4045 assert . deepEqual ( result . value , { n : 2 } ) ;
4146 assert . equal ( result . attempts , 2 ) ;
4247 assert . equal ( result . providerSessionId , "sess" ) ;
48+ assert . equal ( result . mode , "prompt" ) ;
4349}
4450
4551{
@@ -56,4 +62,85 @@ assert.equal(
5662 ) ;
5763}
5864
65+ // Native provider: structured on attempt 0 → single attempt, raw prompt.
66+ {
67+ const seen : Array < { prompt : string ; mode ?: string } > = [ ] ;
68+ const result = await enforceAgentSchema ( {
69+ schema : {
70+ type : "object" ,
71+ properties : { n : { type : "number" } } ,
72+ required : [ "n" ] ,
73+ additionalProperties : false ,
74+ } ,
75+ prompt : "give n" ,
76+ provider : "codex" ,
77+ run : async ( prompt , opts ) => {
78+ seen . push ( { prompt, mode : opts ?. mode } ) ;
79+ return { finalResponse : "noise" , structured : { n : 7 } } ;
80+ } ,
81+ } ) ;
82+ assert . deepEqual ( result . value , { n : 7 } ) ;
83+ assert . equal ( result . attempts , 1 ) ;
84+ assert . equal ( result . mode , "native" ) ;
85+ assert . equal ( seen . length , 1 ) ;
86+ assert . equal ( seen [ 0 ] ?. prompt , "give n" ) ;
87+ assert . equal ( seen [ 0 ] ?. mode , "native" ) ;
88+ assert . ok ( ! seen [ 0 ] ?. prompt . includes ( "ONLY a JSON" ) ) ;
89+ }
90+
91+ // Native fail then prompt repair.
92+ {
93+ const seen : Array < { prompt : string ; mode ?: string } > = [ ] ;
94+ const retries : Array < { attempt : number ; mode : string } > = [ ] ;
95+ const result = await enforceAgentSchema ( {
96+ schema : {
97+ type : "object" ,
98+ properties : { n : { type : "number" } } ,
99+ required : [ "n" ] ,
100+ additionalProperties : false ,
101+ } ,
102+ prompt : "give n" ,
103+ provider : "claude" ,
104+ onRetry : ( { attempt, mode } ) => {
105+ retries . push ( { attempt, mode } ) ;
106+ } ,
107+ run : async ( prompt , opts ) => {
108+ seen . push ( { prompt, mode : opts ?. mode } ) ;
109+ if ( opts ?. mode === "native" ) {
110+ return { finalResponse : '{"n":"bad"}' , structured : { n : "bad" } } ;
111+ }
112+ return { finalResponse : '{"n":3}' , structured : { n : 3 } } ;
113+ } ,
114+ } ) ;
115+ assert . deepEqual ( result . value , { n : 3 } ) ;
116+ assert . equal ( result . attempts , 2 ) ;
117+ assert . equal ( result . mode , "prompt" ) ;
118+ assert . equal ( seen [ 0 ] ?. mode , "native" ) ;
119+ assert . equal ( seen [ 1 ] ?. mode , "prompt" ) ;
120+ assert . ok ( seen [ 1 ] ?. prompt . includes ( "ONLY a JSON" ) ) ;
121+ assert . deepEqual ( retries [ 0 ] , { attempt : 1 , mode : "native" } ) ;
122+ }
123+
124+ // Non-native never gets native mode.
125+ {
126+ const modes : string [ ] = [ ] ;
127+ const result = await enforceAgentSchema ( {
128+ schema : {
129+ type : "object" ,
130+ properties : { n : { type : "number" } } ,
131+ required : [ "n" ] ,
132+ } ,
133+ prompt : "give n" ,
134+ provider : "opencode" ,
135+ run : async ( prompt , opts ) => {
136+ modes . push ( opts ?. mode ?? "missing" ) ;
137+ assert . ok ( prompt . includes ( "ONLY a JSON" ) ) ;
138+ return { finalResponse : '{"n":1}' } ;
139+ } ,
140+ } ) ;
141+ assert . deepEqual ( result . value , { n : 1 } ) ;
142+ assert . deepEqual ( modes , [ "prompt" ] ) ;
143+ assert . equal ( result . mode , "prompt" ) ;
144+ }
145+
59146console . log ( "workflow-schema.test.ts: ok" ) ;
0 commit comments