
















@@ -0,0 +1,130 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+import type { OpenClawConfig } from "../config/types.openclaw.js";
3+4+const loadManifestMetadataSnapshotMock = vi.hoisted(() => vi.fn());
5+const getCurrentPluginMetadataSnapshotMock = vi.hoisted(() => vi.fn());
6+const getActivePluginRegistryWorkspaceDirFromStateMock = vi.hoisted(() => vi.fn());
7+8+vi.mock("../plugins/current-plugin-metadata-snapshot.js", () => ({
9+getCurrentPluginMetadataSnapshot: getCurrentPluginMetadataSnapshotMock,
10+}));
11+12+vi.mock("../plugins/manifest-contract-eligibility.js", () => ({
13+loadManifestMetadataSnapshot: loadManifestMetadataSnapshotMock,
14+}));
15+16+vi.mock("../plugins/runtime-state.js", () => ({
17+getActivePluginRegistryWorkspaceDirFromState: getActivePluginRegistryWorkspaceDirFromStateMock,
18+}));
19+20+vi.mock("./provider-model-normalization.runtime.js", () => ({
21+normalizeProviderModelIdWithRuntime: () => undefined,
22+}));
23+24+describe("configured model manifest workspace scope", () => {
25+beforeEach(() => {
26+vi.resetModules();
27+loadManifestMetadataSnapshotMock.mockReset();
28+getCurrentPluginMetadataSnapshotMock.mockReset();
29+getActivePluginRegistryWorkspaceDirFromStateMock.mockReset();
30+getCurrentPluginMetadataSnapshotMock.mockReturnValue(undefined);
31+loadManifestMetadataSnapshotMock.mockReturnValue({
32+plugins: [
33+{
34+modelIdNormalization: {
35+providers: {
36+custom: {
37+prefixWhenBare: "workspace-custom",
38+},
39+},
40+},
41+},
42+],
43+});
44+});
45+46+it("does not reuse workspace manifest policies without a workspace context", async () => {
47+const { buildConfiguredModelCatalog } = await import("./model-selection-shared.js");
48+const cfg = {
49+models: {
50+providers: {
51+custom: {
52+models: [{ id: "fast-model" }],
53+},
54+},
55+},
56+} as unknown as OpenClawConfig;
57+58+expect(buildConfiguredModelCatalog({ cfg })).toMatchObject([
59+{
60+provider: "custom",
61+id: "fast-model",
62+},
63+]);
64+expect(getCurrentPluginMetadataSnapshotMock).toHaveBeenCalledWith({
65+config: cfg,
66+env: process.env,
67+});
68+expect(loadManifestMetadataSnapshotMock).not.toHaveBeenCalled();
69+});
70+71+it("uses manifest policies when the workspace context is explicit", async () => {
72+const { buildConfiguredModelCatalog } = await import("./model-selection-shared.js");
73+const cfg = {
74+models: {
75+providers: {
76+custom: {
77+models: [{ id: "fast-model" }],
78+},
79+},
80+},
81+} as unknown as OpenClawConfig;
82+83+expect(buildConfiguredModelCatalog({ cfg, workspaceDir: "/workspace/a" })).toMatchObject([
84+{
85+provider: "custom",
86+id: "workspace-custom/fast-model",
87+},
88+]);
89+expect(loadManifestMetadataSnapshotMock).toHaveBeenCalledWith({
90+config: cfg,
91+workspaceDir: "/workspace/a",
92+env: process.env,
93+});
94+expect(getCurrentPluginMetadataSnapshotMock).not.toHaveBeenCalled();
95+});
96+97+it("uses an unscoped current snapshot without falling back to a metadata scan", async () => {
98+getCurrentPluginMetadataSnapshotMock.mockReturnValue({
99+plugins: [
100+{
101+modelIdNormalization: {
102+providers: {
103+custom: {
104+prefixWhenBare: "global-custom",
105+},
106+},
107+},
108+},
109+],
110+});
111+const { buildConfiguredModelCatalog } = await import("./model-selection-shared.js");
112+const cfg = {
113+models: {
114+providers: {
115+custom: {
116+models: [{ id: "fast-model" }],
117+},
118+},
119+},
120+} as unknown as OpenClawConfig;
121+122+expect(buildConfiguredModelCatalog({ cfg })).toMatchObject([
123+{
124+provider: "custom",
125+id: "global-custom/fast-model",
126+},
127+]);
128+expect(loadManifestMetadataSnapshotMock).not.toHaveBeenCalled();
129+});
130+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。