





















@@ -556,6 +556,119 @@ describe("resolveModel", () => {
556556expect(discoverModels).not.toHaveBeenCalled();
557557});
558558559+it("falls back to bundled static catalog rows without agent discovery", async () => {
560+const cfg = {
561+models: {
562+providers: {
563+openai: {
564+api: "openai-responses",
565+baseUrl: "https://api.openai.com/v1",
566+models: [],
567+},
568+},
569+},
570+} as unknown as OpenClawConfig;
571+resolveBundledStaticCatalogModelMock.mockReturnValueOnce({
572+provider: "openai",
573+id: "gpt-5.3-codex",
574+name: "GPT-5.3 Codex",
575+api: "openai-chatgpt-responses",
576+baseUrl: "https://chatgpt.com/backend-api",
577+reasoning: true,
578+input: ["text", "image"],
579+cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
580+contextWindow: 400_000,
581+maxTokens: 128_000,
582+});
583+const baseRuntimeHooks = createRuntimeHooks();
584+const prepareProviderDynamicModel = vi.fn(baseRuntimeHooks.prepareProviderDynamicModel);
585+const runProviderDynamicModel = vi.fn(() => undefined);
586+587+const result = await resolveModelAsync("openai", "gpt-5.3-codex", "/tmp/agent", cfg, {
588+allowBundledStaticCatalogFallback: true,
589+preferBundledStaticCatalogTransport: true,
590+runtimeHooks: {
591+ ...baseRuntimeHooks,
592+ prepareProviderDynamicModel,
593+ runProviderDynamicModel,
594+},
595+skipAgentDiscovery: true,
596+});
597+598+expectRecordFields(expectResolvedModel(result), {
599+provider: "openai",
600+id: "gpt-5.3-codex",
601+api: "openai-chatgpt-responses",
602+baseUrl: "https://chatgpt.com/backend-api",
603+contextWindow: 400_000,
604+maxTokens: 128_000,
605+});
606+expect(resolveBundledStaticCatalogModelMock).toHaveBeenCalledTimes(1);
607+expect(resolveBundledStaticCatalogModelMock).toHaveBeenCalledWith(
608+expect.objectContaining({
609+provider: "openai",
610+modelId: "gpt-5.3-codex",
611+ cfg,
612+}),
613+);
614+expect(prepareProviderDynamicModel).toHaveBeenCalled();
615+expect(runProviderDynamicModel).toHaveBeenCalled();
616+expect(discoverAuthStorage).not.toHaveBeenCalled();
617+expect(discoverModels).not.toHaveBeenCalled();
618+});
619+620+it("keeps provider dynamic metadata for runtime-preferred models", async () => {
621+resolveBundledStaticCatalogModelMock.mockReturnValueOnce({
622+provider: "openai",
623+id: "gpt-5.5-pro",
624+name: "GPT-5.5 Pro",
625+api: "openai-chatgpt-responses",
626+baseUrl: "https://chatgpt.com/backend-api",
627+reasoning: true,
628+input: ["text", "image"],
629+cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
630+contextWindow: 123_456,
631+maxTokens: 64_000,
632+});
633+const baseRuntimeHooks = createRuntimeHooks();
634+const prepareProviderDynamicModel = vi.fn(baseRuntimeHooks.prepareProviderDynamicModel);
635+const runProviderDynamicModel = vi.fn(() => ({
636+provider: "openai",
637+id: "gpt-5.5-pro",
638+name: "GPT-5.5 Pro",
639+api: "openai-chatgpt-responses" as const,
640+baseUrl: "https://chatgpt.com/backend-api",
641+reasoning: true,
642+input: ["text", "image"],
643+cost: { input: 30, output: 180, cacheRead: 0, cacheWrite: 0 },
644+contextWindow: 1_000_000,
645+maxTokens: 128_000,
646+}));
647+const shouldPreferProviderRuntimeResolvedModel = vi.fn(() => true);
648+649+const result = await resolveModelAsync("openai", "gpt-5.5-pro", "/tmp/agent", undefined, {
650+allowBundledStaticCatalogFallback: true,
651+runtimeHooks: {
652+ ...baseRuntimeHooks,
653+ prepareProviderDynamicModel,
654+ runProviderDynamicModel,
655+ shouldPreferProviderRuntimeResolvedModel,
656+},
657+skipAgentDiscovery: true,
658+});
659+660+expectRecordFields(expectResolvedModel(result), {
661+provider: "openai",
662+id: "gpt-5.5-pro",
663+api: "openai-chatgpt-responses",
664+contextWindow: 1_000_000,
665+maxTokens: 128_000,
666+});
667+expect(prepareProviderDynamicModel).toHaveBeenCalled();
668+expect(runProviderDynamicModel).toHaveBeenCalled();
669+expect(shouldPreferProviderRuntimeResolvedModel).toHaveBeenCalled();
670+});
671+559672it("looks up each static fallback candidate with its own normalized model id", async () => {
560673resolveBundledStaticCatalogModelMock.mockImplementation(({ provider, modelId }) => ({
561674 provider,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。