@@ -776,6 +776,253 @@ describe("runtime tool fixture", () => {
776776 expect ( details ) . toContain ( "read mock provider failure planned args" ) ;
777777 } ) ;
778778
779+ it ( "accepts non-required mock fixtures when both paths are planned without direct output" , async ( ) => {
780+ const env = await makeEnv ( {
781+ mock : { baseUrl : "http://127.0.0.1:9999" } ,
782+ } ) ;
783+ const fetchJson = vi
784+ . fn ( )
785+ . mockResolvedValueOnce ( [ ] )
786+ . mockResolvedValueOnce ( [
787+ {
788+ allInputText : "target=image_generate" ,
789+ plannedToolCallId : "call-image-happy" ,
790+ plannedToolName : "image_generate" ,
791+ plannedToolArgs : { prompt : "QA lighthouse" , filename : "runtime-tool-fixture" } ,
792+ } ,
793+ {
794+ allInputText : "failure target=image_generate" ,
795+ plannedToolCallId : "call-image-failure" ,
796+ plannedToolName : "image_generate" ,
797+ plannedToolArgs : { __qaFailureMode : "denied-input" } ,
798+ } ,
799+ ] ) ;
800+
801+ const details = await runRuntimeToolFixture (
802+ env ,
803+ {
804+ toolName : "image_generate" ,
805+ toolCoverage : {
806+ bucket : "openclaw-dynamic-integration" ,
807+ expectedLayer : "openclaw-dynamic" ,
808+ required : false ,
809+ action : "optional runtime parity gate with async image completion coverage" ,
810+ } ,
811+ promptSnippet : "target=image_generate" ,
812+ failurePromptSnippet : "failure target=image_generate" ,
813+ } ,
814+ {
815+ createSession : vi . fn ( async ( _env , _label , key ) => key ! ) ,
816+ readEffectiveTools : vi . fn ( async ( ) => new Set ( [ "image_generate" ] ) ) ,
817+ runAgentPrompt : vi . fn ( async ( ) => ( { } ) ) ,
818+ fetchJson,
819+ ensureImageGenerationConfigured : vi . fn ( ) ,
820+ } ,
821+ ) ;
822+
823+ expect ( details ) . toContain ( "image_generate mock provider report-only" ) ;
824+ expect ( details ) . toContain ( "image_generate mock provider happy planned args" ) ;
825+ expect ( details ) . toContain ( "image_generate mock provider failure planned args" ) ;
826+ } ) ;
827+
828+ it ( "still rejects failed happy output for non-required mock fixtures" , async ( ) => {
829+ const env = await makeEnv ( {
830+ mock : { baseUrl : "http://127.0.0.1:9999" } ,
831+ } ) ;
832+ const fetchJson = vi
833+ . fn ( )
834+ . mockResolvedValueOnce ( [ ] )
835+ . mockResolvedValueOnce ( [
836+ {
837+ allInputText : "target=image_generate" ,
838+ plannedToolCallId : "call-image-happy" ,
839+ plannedToolName : "image_generate" ,
840+ plannedToolArgs : { prompt : "QA lighthouse" } ,
841+ } ,
842+ {
843+ allInputText : "target=image_generate" ,
844+ toolOutputCallId : "call-image-happy" ,
845+ toolOutput : "Failed: provider rejected image request" ,
846+ } ,
847+ {
848+ allInputText : "failure target=image_generate" ,
849+ plannedToolCallId : "call-image-failure" ,
850+ plannedToolName : "image_generate" ,
851+ plannedToolArgs : { __qaFailureMode : "denied-input" } ,
852+ } ,
853+ ] ) ;
854+
855+ await expect (
856+ runRuntimeToolFixture (
857+ env ,
858+ {
859+ toolName : "image_generate" ,
860+ toolCoverage : {
861+ bucket : "openclaw-dynamic-integration" ,
862+ expectedLayer : "openclaw-dynamic" ,
863+ required : false ,
864+ action : "optional runtime parity gate with async image completion coverage" ,
865+ } ,
866+ promptSnippet : "target=image_generate" ,
867+ failurePromptSnippet : "failure target=image_generate" ,
868+ } ,
869+ {
870+ createSession : vi . fn ( async ( _env , _label , key ) => key ! ) ,
871+ readEffectiveTools : vi . fn ( async ( ) => new Set ( [ "image_generate" ] ) ) ,
872+ runAgentPrompt : vi . fn ( async ( ) => ( { } ) ) ,
873+ fetchJson,
874+ ensureImageGenerationConfigured : vi . fn ( ) ,
875+ } ,
876+ ) ,
877+ ) . rejects . toThrow ( "expected mock happy-path successful tool output for image_generate" ) ;
878+ } ) ;
879+
880+ it ( "still rejects successful failure output for non-required mock fixtures" , async ( ) => {
881+ const env = await makeEnv ( {
882+ mock : { baseUrl : "http://127.0.0.1:9999" } ,
883+ } ) ;
884+ const fetchJson = vi
885+ . fn ( )
886+ . mockResolvedValueOnce ( [ ] )
887+ . mockResolvedValueOnce ( [
888+ {
889+ allInputText : "target=image_generate" ,
890+ plannedToolCallId : "call-image-happy" ,
891+ plannedToolName : "image_generate" ,
892+ plannedToolArgs : { prompt : "QA lighthouse" } ,
893+ } ,
894+ {
895+ allInputText : "failure target=image_generate" ,
896+ plannedToolCallId : "call-image-failure" ,
897+ plannedToolName : "image_generate" ,
898+ plannedToolArgs : { __qaFailureMode : "denied-input" } ,
899+ } ,
900+ {
901+ allInputText : "failure target=image_generate" ,
902+ toolOutputCallId : "call-image-failure" ,
903+ toolOutput : "Task queued for async image delivery" ,
904+ } ,
905+ ] ) ;
906+
907+ await expect (
908+ runRuntimeToolFixture (
909+ env ,
910+ {
911+ toolName : "image_generate" ,
912+ toolCoverage : {
913+ bucket : "openclaw-dynamic-integration" ,
914+ expectedLayer : "openclaw-dynamic" ,
915+ required : false ,
916+ action : "optional runtime parity gate with async image completion coverage" ,
917+ } ,
918+ promptSnippet : "target=image_generate" ,
919+ failurePromptSnippet : "failure target=image_generate" ,
920+ } ,
921+ {
922+ createSession : vi . fn ( async ( _env , _label , key ) => key ! ) ,
923+ readEffectiveTools : vi . fn ( async ( ) => new Set ( [ "image_generate" ] ) ) ,
924+ runAgentPrompt : vi . fn ( async ( ) => ( { } ) ) ,
925+ fetchJson,
926+ ensureImageGenerationConfigured : vi . fn ( ) ,
927+ } ,
928+ ) ,
929+ ) . rejects . toThrow ( "expected mock failure-path tool failure output for image_generate" ) ;
930+ } ) ;
931+
932+ it ( "rejects malformed report-only failure plans for non-required mock fixtures" , async ( ) => {
933+ const env = await makeEnv ( {
934+ mock : { baseUrl : "http://127.0.0.1:9999" } ,
935+ } ) ;
936+ const fetchJson = vi
937+ . fn ( )
938+ . mockResolvedValueOnce ( [ ] )
939+ . mockResolvedValueOnce ( [
940+ {
941+ allInputText : "target=image_generate" ,
942+ plannedToolCallId : "call-image-happy" ,
943+ plannedToolName : "image_generate" ,
944+ plannedToolArgs : { prompt : "QA lighthouse" } ,
945+ } ,
946+ {
947+ allInputText : "failure target=image_generate" ,
948+ plannedToolCallId : "call-image-failure" ,
949+ plannedToolName : "image_generate" ,
950+ plannedToolArgs : { prompt : "not a denied-input failure" } ,
951+ } ,
952+ ] ) ;
953+
954+ await expect (
955+ runRuntimeToolFixture (
956+ env ,
957+ {
958+ toolName : "image_generate" ,
959+ toolCoverage : {
960+ bucket : "openclaw-dynamic-integration" ,
961+ expectedLayer : "openclaw-dynamic" ,
962+ required : false ,
963+ action : "optional runtime parity gate with async image completion coverage" ,
964+ } ,
965+ promptSnippet : "target=image_generate" ,
966+ failurePromptSnippet : "failure target=image_generate" ,
967+ } ,
968+ {
969+ createSession : vi . fn ( async ( _env , _label , key ) => key ! ) ,
970+ readEffectiveTools : vi . fn ( async ( ) => new Set ( [ "image_generate" ] ) ) ,
971+ runAgentPrompt : vi . fn ( async ( ) => ( { } ) ) ,
972+ fetchJson,
973+ ensureImageGenerationConfigured : vi . fn ( ) ,
974+ } ,
975+ ) ,
976+ ) . rejects . toThrow ( "expected mock failure-path denied-input args for image_generate" ) ;
977+ } ) ;
978+
979+ it ( "rejects malformed report-only happy plans for non-required mock fixtures" , async ( ) => {
980+ const env = await makeEnv ( {
981+ mock : { baseUrl : "http://127.0.0.1:9999" } ,
982+ } ) ;
983+ const fetchJson = vi
984+ . fn ( )
985+ . mockResolvedValueOnce ( [ ] )
986+ . mockResolvedValueOnce ( [
987+ {
988+ allInputText : "target=image_generate" ,
989+ plannedToolCallId : "call-image-happy" ,
990+ plannedToolName : "image_generate" ,
991+ plannedToolArgs : { } ,
992+ } ,
993+ {
994+ allInputText : "failure target=image_generate" ,
995+ plannedToolCallId : "call-image-failure" ,
996+ plannedToolName : "image_generate" ,
997+ plannedToolArgs : { __qaFailureMode : "denied-input" } ,
998+ } ,
999+ ] ) ;
1000+
1001+ await expect (
1002+ runRuntimeToolFixture (
1003+ env ,
1004+ {
1005+ toolName : "image_generate" ,
1006+ toolCoverage : {
1007+ bucket : "openclaw-dynamic-integration" ,
1008+ expectedLayer : "openclaw-dynamic" ,
1009+ required : false ,
1010+ action : "optional runtime parity gate with async image completion coverage" ,
1011+ } ,
1012+ promptSnippet : "target=image_generate" ,
1013+ failurePromptSnippet : "failure target=image_generate" ,
1014+ } ,
1015+ {
1016+ createSession : vi . fn ( async ( _env , _label , key ) => key ! ) ,
1017+ readEffectiveTools : vi . fn ( async ( ) => new Set ( [ "image_generate" ] ) ) ,
1018+ runAgentPrompt : vi . fn ( async ( ) => ( { } ) ) ,
1019+ fetchJson,
1020+ ensureImageGenerationConfigured : vi . fn ( ) ,
1021+ } ,
1022+ ) ,
1023+ ) . rejects . toThrow ( "expected mock happy-path prompt args for image_generate" ) ;
1024+ } ) ;
1025+
7791026 it ( "rejects failure-shaped mock happy-path tool output" , async ( ) => {
7801027 const env = await makeEnv ( {
7811028 mock : { baseUrl : "http://127.0.0.1:9999" } ,
0 commit comments