Files
openclaw/extensions/migrate-hermes/model.plan.test.ts
Vincent Koc 1fc5b2b703 feat(migrations): add plugin-owned Hermes import
* feat: add migration providers

* feat: offer Hermes migration during onboarding

* feat(hermes): map imported config surfaces

* feat(onboard): require fresh migration imports

* docs(cli): clarify Hermes import coverage

* chore(migrations): rename Hermes importer package

* chore(migrations): rewire Hermes importer id

* fix(migrations): redact migration JSON details

* fix(hermes): use provider runtime for config imports

* test(hermes): cover missing source planning

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-27 00:34:29 -07:00

108 lines
3.3 KiB
TypeScript

import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/provider-auth";
import { afterEach, describe, expect, it } from "vitest";
import { HERMES_REASON_DEFAULT_MODEL_CONFIGURED } from "./items.js";
import { buildHermesMigrationProvider } from "./provider.js";
import { cleanupTempRoots, makeContext, makeTempRoot, writeFile } from "./test/provider-helpers.js";
describe("Hermes migration model planning", () => {
afterEach(async () => {
await cleanupTempRoots();
});
it("preserves the provider for top-level string model refs", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
await writeFile(path.join(source, "config.yaml"), "provider: openai\nmodel: gpt-5.4\n");
const provider = buildHermesMigrationProvider();
const plan = await provider.plan(makeContext({ source, stateDir, workspaceDir }));
expect(plan.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "config:default-model",
details: { model: "openai/gpt-5.4" },
status: "planned",
}),
]),
);
});
it("treats existing object-form default model primaries as conflicts", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
await writeFile(
path.join(source, "config.yaml"),
"model:\n provider: openai\n model: gpt-5.4\n",
);
const provider = buildHermesMigrationProvider();
const plan = await provider.plan(
makeContext({
source,
stateDir,
workspaceDir,
model: {
primary: "anthropic/claude-sonnet-4.6",
fallbacks: ["openai/gpt-5.4"],
timeoutMs: 120_000,
},
}),
);
expect(plan.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "config:default-model",
status: "conflict",
reason: HERMES_REASON_DEFAULT_MODEL_CONFIGURED,
}),
]),
);
});
it("treats default-agent model overrides as conflicts", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
await writeFile(
path.join(source, "config.yaml"),
"model:\n provider: openai\n model: gpt-5.4\n",
);
const config = {
agents: {
defaults: {
workspace: workspaceDir,
model: "openai/gpt-5.4",
},
list: [
{
id: "main",
default: true,
model: "anthropic/claude-sonnet-4.6",
},
],
},
} as OpenClawConfig;
const provider = buildHermesMigrationProvider();
const plan = await provider.plan(makeContext({ source, stateDir, workspaceDir, config }));
expect(plan.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "config:default-model",
status: "conflict",
reason: HERMES_REASON_DEFAULT_MODEL_CONFIGURED,
}),
]),
);
});
});