Skip to content

Commit 498af50

Browse files
committed
fix: avoid default workspace metadata for agent models
1 parent 51c7f54 commit 498af50

2 files changed

Lines changed: 94 additions & 4 deletions

File tree

src/agents/models-config.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,21 +151,29 @@ export async function ensureOpenClawModelsJson(
151151
agentDirOverride?: string,
152152
options: {
153153
pluginMetadataSnapshot?: Pick<PluginMetadataSnapshot, "index" | "manifestRegistry" | "owners">;
154+
workspaceDir?: string;
154155
} = {},
155156
): Promise<{ agentDir: string; wrote: boolean }> {
156157
const resolved = resolveModelsConfigInput(config);
157158
const cfg = resolved.config;
158-
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
159+
const workspaceDir =
160+
options.workspaceDir ??
161+
(agentDirOverride?.trim()
162+
? undefined
163+
: resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg)));
159164
const pluginMetadataSnapshot =
160165
options.pluginMetadataSnapshot ??
161-
getCurrentPluginMetadataSnapshot({ config: cfg, workspaceDir });
166+
getCurrentPluginMetadataSnapshot({
167+
config: cfg,
168+
...(workspaceDir ? { workspaceDir } : {}),
169+
});
162170
const agentDir = agentDirOverride?.trim() ? agentDirOverride.trim() : resolveOpenClawAgentDir();
163171
const targetPath = path.join(agentDir, "models.json");
164172
const fingerprint = await buildModelsJsonFingerprint({
165173
config: cfg,
166174
sourceConfigForSecrets: resolved.sourceConfigForSecrets,
167175
agentDir,
168-
workspaceDir,
176+
...(workspaceDir ? { workspaceDir } : {}),
169177
...(pluginMetadataSnapshot ? { pluginMetadataSnapshot } : {}),
170178
});
171179
const cached = MODELS_JSON_STATE.readyCache.get(targetPath);
@@ -187,7 +195,7 @@ export async function ensureOpenClawModelsJson(
187195
sourceConfigForSecrets: resolved.sourceConfigForSecrets,
188196
agentDir,
189197
env,
190-
workspaceDir,
198+
...(workspaceDir ? { workspaceDir } : {}),
191199
existingRaw: existingModelsFile.raw,
192200
existingParsed: existingModelsFile.parsed,
193201
...(pluginMetadataSnapshot ? { pluginMetadataSnapshot } : {}),

src/agents/models-config.write-serialization.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import fs from "node:fs/promises";
22
import path from "node:path";
33
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
4+
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
5+
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
46
import {
57
CUSTOM_PROXY_MODELS_CONFIG,
68
installModelsConfigTestHooks,
@@ -13,15 +15,63 @@ const planOpenClawModelsJsonMock = vi.fn();
1315
installModelsConfigTestHooks();
1416

1517
let ensureOpenClawModelsJson: typeof import("./models-config.js").ensureOpenClawModelsJson;
18+
let clearCurrentPluginMetadataSnapshot: typeof import("../plugins/current-plugin-metadata-snapshot.js").clearCurrentPluginMetadataSnapshot;
19+
let setCurrentPluginMetadataSnapshot: typeof import("../plugins/current-plugin-metadata-snapshot.js").setCurrentPluginMetadataSnapshot;
20+
21+
function createPluginMetadataSnapshot(workspaceDir: string): PluginMetadataSnapshot {
22+
const policyHash = resolveInstalledPluginIndexPolicyHash({});
23+
return {
24+
policyHash,
25+
workspaceDir,
26+
index: {
27+
version: 1,
28+
hostContractVersion: "test",
29+
compatRegistryVersion: "test",
30+
migrationVersion: 1,
31+
policyHash,
32+
generatedAtMs: 1,
33+
installRecords: {},
34+
plugins: [],
35+
diagnostics: [],
36+
},
37+
registryDiagnostics: [],
38+
manifestRegistry: { plugins: [], diagnostics: [] },
39+
plugins: [],
40+
diagnostics: [],
41+
byPluginId: new Map(),
42+
normalizePluginId: (pluginId) => pluginId,
43+
owners: {
44+
channels: new Map(),
45+
channelConfigs: new Map(),
46+
providers: new Map(),
47+
modelCatalogProviders: new Map(),
48+
cliBackends: new Map(),
49+
setupProviders: new Map(),
50+
commandAliases: new Map(),
51+
contracts: new Map(),
52+
},
53+
metrics: {
54+
registrySnapshotMs: 0,
55+
manifestRegistryMs: 0,
56+
ownerMapsMs: 0,
57+
totalMs: 0,
58+
indexPluginCount: 0,
59+
manifestPluginCount: 0,
60+
},
61+
};
62+
}
1663

1764
beforeAll(async () => {
1865
vi.doMock("./models-config.plan.js", () => ({
1966
planOpenClawModelsJson: (...args: unknown[]) => planOpenClawModelsJsonMock(...args),
2067
}));
2168
({ ensureOpenClawModelsJson } = await import("./models-config.js"));
69+
({ clearCurrentPluginMetadataSnapshot, setCurrentPluginMetadataSnapshot } =
70+
await import("../plugins/current-plugin-metadata-snapshot.js"));
2271
});
2372

2473
beforeEach(() => {
74+
clearCurrentPluginMetadataSnapshot();
2575
planOpenClawModelsJsonMock
2676
.mockReset()
2777
.mockImplementation(async (params: { cfg?: typeof CUSTOM_PROXY_MODELS_CONFIG }) => ({
@@ -31,6 +81,38 @@ beforeEach(() => {
3181
});
3282

3383
describe("models-config write serialization", () => {
84+
it("does not reuse default workspace plugin metadata for explicit agent dirs without workspace", async () => {
85+
await withModelsTempHome(async (home) => {
86+
const snapshot = createPluginMetadataSnapshot(path.join(home, "default-workspace"));
87+
setCurrentPluginMetadataSnapshot(snapshot, { config: {} });
88+
const agentDir = path.join(home, "agent-non-default");
89+
90+
await ensureOpenClawModelsJson({}, agentDir);
91+
92+
expect(planOpenClawModelsJsonMock).toHaveBeenCalledWith(
93+
expect.not.objectContaining({ pluginMetadataSnapshot: snapshot }),
94+
);
95+
});
96+
});
97+
98+
it("reuses current plugin metadata for explicit agent dirs with matching workspace", async () => {
99+
await withModelsTempHome(async (home) => {
100+
const workspaceDir = path.join(home, "agent-workspace");
101+
const snapshot = createPluginMetadataSnapshot(workspaceDir);
102+
setCurrentPluginMetadataSnapshot(snapshot, { config: {} });
103+
const agentDir = path.join(home, "agent-non-default");
104+
105+
await ensureOpenClawModelsJson({}, agentDir, { workspaceDir });
106+
107+
expect(planOpenClawModelsJsonMock).toHaveBeenCalledWith(
108+
expect.objectContaining({
109+
workspaceDir,
110+
pluginMetadataSnapshot: snapshot,
111+
}),
112+
);
113+
});
114+
});
115+
34116
it("serializes concurrent models.json writes to avoid overlap", async () => {
35117
await withModelsTempHome(async () => {
36118
const first = structuredClone(CUSTOM_PROXY_MODELS_CONFIG);

0 commit comments

Comments
 (0)