import { afterEach, describe, expect, it, vi } from "vitest" ;
import {
clearAgentHarnesses,
disposeRegisteredAgentHarnesses,
getAgentHarness,
getRegisteredAgentHarness,
listAgentHarnessIds,
listRegisteredAgentHarnesses,
registerAgentHarness,
resetRegisteredAgentHarnessSessions,
restoreRegisteredAgentHarnesses,
} from "./registry.js" ;
import { selectAgentHarness } from "./selection.js" ;
import type { AgentHarness } from "./types.js" ;
const originalRuntime = process.env.OPENCLAW_AGENT_RUNTIME;
const originalHarnessFallback = process.env.OPENCLAW_AGENT_HARNESS_FALLBACK;
afterEach(() => {
clearAgentHarnesses();
if (originalRuntime == null ) {
delete process.env.OPENCLAW_AGENT_RUNTIME;
} else {
process.env.OPENCLAW_AGENT_RUNTIME = originalRuntime;
}
if (originalHarnessFallback == null ) {
delete process.env.OPENCLAW_AGENT_HARNESS_FALLBACK;
} else {
process.env.OPENCLAW_AGENT_HARNESS_FALLBACK = originalHarnessFallback;
}
});
function makeHarness(
id: string,
options: {
priority?: number;
providers?: string[];
} = {},
): AgentHarness {
const providers = options.providers?.map((provider) => provider.trim().toLowerCase());
return {
id,
label: id,
supports: (ctx) =>
!providers || providers.includes(ctx.provider.trim().toLowerCase())
? { supported: true , priority: options.priority ?? 10 }
: { supported: false },
async runAttempt() {
throw new Error("not used" );
},
};
}
describe("agent harness registry" , () => {
it("registers and retrieves a harness with owner metadata" , () => {
const harness = makeHarness("custom" );
registerAgentHarness(harness, { ownerPluginId: "plugin-a" });
expect(getAgentHarness("custom" )).toMatchObject({ id: "custom" , pluginId: "plugin-a" });
expect(getRegisteredAgentHarness("custom" )?.ownerPluginId).toBe("plugin-a" );
expect(listAgentHarnessIds()).toEqual(["custom" ]);
});
it("restores a registry snapshot" , () => {
registerAgentHarness(makeHarness("a" ));
const snapshot = listRegisteredAgentHarnesses();
registerAgentHarness(makeHarness("b" ));
restoreRegisteredAgentHarnesses(snapshot);
expect(listAgentHarnessIds()).toEqual(["a" ]);
});
it("dispatches generic session reset to registered harnesses" , async () => {
const resets: unknown[] = [];
registerAgentHarness({
...makeHarness("custom" ),
reset: async (params) => {
resets.push(params);
},
});
await resetRegisteredAgentHarnessSessions({
sessionId: "session-1" ,
sessionKey: "agent:main:session-1" ,
sessionFile: "/tmp/session.jsonl" ,
reason: "reset" ,
});
expect(resets).toEqual([
{
sessionId: "session-1" ,
sessionKey: "agent:main:session-1" ,
sessionFile: "/tmp/session.jsonl" ,
reason: "reset" ,
},
]);
});
it("disposes registered harness runtime state" , async () => {
const dispose = vi.fn(async () => undefined);
registerAgentHarness({
...makeHarness("custom" ),
dispose,
});
await disposeRegisteredAgentHarnesses();
expect(dispose).toHaveBeenCalledTimes(1 );
});
it("keeps model-specific harnesses behind plugin registration in auto mode" , () => {
process.env.OPENCLAW_AGENT_RUNTIME = "auto" ;
expect(selectAgentHarness({ provider: "plugin-models" , modelId: "custom-1" }).id).toBe("pi" );
registerAgentHarness(makeHarness("custom" , { providers: ["plugin-models" ] }), {
ownerPluginId: "plugin-a" ,
});
expect(selectAgentHarness({ provider: "plugin-models" , modelId: "custom-1" }).id).toBe(
"custom" ,
);
});
it("falls back to PI for other models" , () => {
process.env.OPENCLAW_AGENT_RUNTIME = "auto" ;
expect(selectAgentHarness({ provider: "anthropic" , modelId: "sonnet-4.6" }).id).toBe("pi" );
});
it("lets a plugin harness win in auto mode by priority" , () => {
process.env.OPENCLAW_AGENT_RUNTIME = "auto" ;
registerAgentHarness(makeHarness("plugin-harness" , { priority: 200 }), {
ownerPluginId: "plugin-a" ,
});
expect(selectAgentHarness({ provider: "codex" , modelId: "gpt-5.4" }).id).toBe("plugin-harness" );
});
it("honors explicit PI mode" , () => {
process.env.OPENCLAW_AGENT_RUNTIME = "pi" ;
registerAgentHarness(makeHarness("plugin-harness" , { priority: 200 }), {
ownerPluginId: "plugin-a" ,
});
expect(selectAgentHarness({ provider: "codex" , modelId: "gpt-5.4" }).id).toBe("pi" );
});
it("honors explicit plugin harness mode when the plugin harness is registered" , () => {
process.env.OPENCLAW_AGENT_RUNTIME = "custom" ;
registerAgentHarness(makeHarness("custom" , { providers: ["custom-provider" ] }), {
ownerPluginId: "plugin-a" ,
});
expect(selectAgentHarness({ provider: "anthropic" , modelId: "sonnet-4.6" }).id).toBe("custom" );
});
});
Messung V0.5 in Prozent C=100 H=97 G=98
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland