@@ -6,6 +6,7 @@ import { withTempDir } from "../test-helpers/temp-dir.js";
66import { withEnvAsync } from "../test-utils/env.js" ;
77import { runCapability } from "./runner.js" ;
88import { withVideoFixture } from "./runner.test-utils.js" ;
9+ import type { MediaUnderstandingProvider } from "./types.js" ;
910
1011vi . mock ( "../media/channel-inbound-roots.js" , ( ) => ( {
1112 resolveChannelInboundAttachmentRoots : ( ) => undefined ,
@@ -84,7 +85,7 @@ describe("runCapability video provider wiring", () => {
8485 agentDir : isolatedAgentDir ,
8586 attachments : cache ,
8687 media,
87- providerRegistry : new Map ( [
88+ providerRegistry : new Map < string , MediaUnderstandingProvider > ( [
8889 [
8990 "moonshot" ,
9091 {
@@ -150,7 +151,7 @@ describe("runCapability video provider wiring", () => {
150151 agentDir : isolatedAgentDir ,
151152 attachments : cache ,
152153 media,
153- providerRegistry : new Map ( [
154+ providerRegistry : new Map < string , MediaUnderstandingProvider > ( [
154155 [
155156 "google" ,
156157 {
@@ -164,7 +165,8 @@ describe("runCapability video provider wiring", () => {
164165 {
165166 id : "moonshot" ,
166167 capabilities : [ "video" ] ,
167- describeVideo : async ( ) => ( { text : "moonshot" , model : "kimi-k2.5" } ) ,
168+ defaultModels : { video : "kimi-k2.5" } ,
169+ describeVideo : async ( req ) => ( { text : "moonshot" , model : req . model } ) ,
168170 } ,
169171 ] ,
170172 ] ) ,
@@ -180,6 +182,122 @@ describe("runCapability video provider wiring", () => {
180182 } ) ;
181183 } ) ;
182184
185+ it ( "uses the provider video default when the active provider has no model" , async ( ) => {
186+ let seenModel : string | undefined ;
187+
188+ await withTempDir ( { prefix : "openclaw-video-active-provider-" } , async ( isolatedAgentDir ) => {
189+ await withVideoFixture ( "openclaw-video-active-default" , async ( { ctx, media, cache } ) => {
190+ const cfg = {
191+ models : {
192+ providers : {
193+ moonshot : {
194+ auth : "api-key" ,
195+ apiKey : "moonshot-key" , // pragma: allowlist secret
196+ models : [ ] ,
197+ } ,
198+ } ,
199+ } ,
200+ tools : {
201+ media : {
202+ video : {
203+ enabled : true ,
204+ } ,
205+ } ,
206+ } ,
207+ } as unknown as OpenClawConfig ;
208+
209+ const result = await runCapability ( {
210+ capability : "video" ,
211+ cfg,
212+ ctx,
213+ agentDir : isolatedAgentDir ,
214+ attachments : cache ,
215+ media,
216+ providerRegistry : new Map < string , MediaUnderstandingProvider > ( [
217+ [
218+ "moonshot" ,
219+ {
220+ id : "moonshot" ,
221+ capabilities : [ "video" ] ,
222+ defaultModels : { video : "kimi-k2.5" } ,
223+ describeVideo : async ( req ) => {
224+ seenModel = req . model ;
225+ return { text : "moonshot" , model : req . model } ;
226+ } ,
227+ } ,
228+ ] ,
229+ ] ) ,
230+ activeModel : { provider : "moonshot" } ,
231+ } ) ;
232+
233+ expect ( result . decision . outcome ) . toBe ( "success" ) ;
234+ const output = requireCapabilityOutput ( result , 0 ) ;
235+ expect ( output . provider ) . toBe ( "moonshot" ) ;
236+ expect ( output . model ) . toBe ( "kimi-k2.5" ) ;
237+ expect ( seenModel ) . toBe ( "kimi-k2.5" ) ;
238+ } ) ;
239+ } ) ;
240+ } ) ;
241+
242+ it ( "preserves self-defaulting video providers without registry model metadata" , async ( ) => {
243+ let seenModel : string | undefined ;
244+
245+ await withTempDir (
246+ { prefix : "openclaw-video-no-default-provider-" } ,
247+ async ( isolatedAgentDir ) => {
248+ await withVideoFixture ( "openclaw-video-no-default" , async ( { ctx, media, cache } ) => {
249+ const cfg = {
250+ models : {
251+ providers : {
252+ moonshot : {
253+ auth : "api-key" ,
254+ apiKey : "moonshot-key" , // pragma: allowlist secret
255+ models : [ ] ,
256+ } ,
257+ } ,
258+ } ,
259+ tools : {
260+ media : {
261+ video : {
262+ enabled : true ,
263+ } ,
264+ } ,
265+ } ,
266+ } as unknown as OpenClawConfig ;
267+
268+ const result = await runCapability ( {
269+ capability : "video" ,
270+ cfg,
271+ ctx,
272+ agentDir : isolatedAgentDir ,
273+ attachments : cache ,
274+ media,
275+ providerRegistry : new Map < string , MediaUnderstandingProvider > ( [
276+ [
277+ "moonshot" ,
278+ {
279+ id : "moonshot" ,
280+ capabilities : [ "video" ] ,
281+ describeVideo : async ( req ) => {
282+ seenModel = req . model ;
283+ return { text : "moonshot" , model : "provider-default" } ;
284+ } ,
285+ } ,
286+ ] ,
287+ ] ) ,
288+ activeModel : { provider : "moonshot" } ,
289+ } ) ;
290+
291+ expect ( result . decision . outcome ) . toBe ( "success" ) ;
292+ const output = requireCapabilityOutput ( result , 0 ) ;
293+ expect ( output . provider ) . toBe ( "moonshot" ) ;
294+ expect ( output . model ) . toBe ( "provider-default" ) ;
295+ expect ( seenModel ) . toBeUndefined ( ) ;
296+ } ) ;
297+ } ,
298+ ) ;
299+ } ) ;
300+
183301 it ( "does not use provider api config as video auth modelApi" , async ( ) => {
184302 const modelAuth = await import ( "../agents/model-auth.js" ) ;
185303 const resolveApiKeyForProvider = vi . mocked ( modelAuth . resolveApiKeyForProvider ) ;
@@ -214,7 +332,7 @@ describe("runCapability video provider wiring", () => {
214332 agentDir : isolatedAgentDir ,
215333 attachments : cache ,
216334 media,
217- providerRegistry : new Map ( [
335+ providerRegistry : new Map < string , MediaUnderstandingProvider > ( [
218336 [
219337 "openai" ,
220338 {
0 commit comments