+43
-41
@@ -8,7 +8,7 @@ import type { DeepMutable } from "@opencode/plugin/promise/types";
|
||||
import type { Skill } from "@opencode/schema/skill";
|
||||
import type { ModelInfo } from "@opencode/client";
|
||||
import plugin from "../src/agents.js";
|
||||
import { settings, gptAgents, workerNames } from "../src/config.js";
|
||||
import { model } from "../src/model.js";
|
||||
import { z } from "zod";
|
||||
import { AgentsRpc } from "../src/agents-rpc.js";
|
||||
|
||||
@@ -23,9 +23,17 @@ const models = ["gpt-6-luna", "gpt-6.1-sol", "gpt-6-astra"].map((id) => ({
|
||||
settings: { reasoningEffort: effort },
|
||||
})),
|
||||
}));
|
||||
const agents = {
|
||||
"fast-lo": "test/gpt-6-luna#low",
|
||||
"fast-hi": "test/gpt-6-luna#high",
|
||||
"good-lo": "test/gpt-6.1-sol#low",
|
||||
"good-hi": "test/gpt-6.1-sol#high",
|
||||
"deep-lo": "test/gpt-6-astra#low",
|
||||
"deep-hi": "test/gpt-6-astra#high",
|
||||
};
|
||||
async function host(
|
||||
catalog: ModelInfo[] = models,
|
||||
options: Plugin.Context["options"] = { provider: "test" },
|
||||
options: Plugin.Context["options"] = { agents },
|
||||
existingSkill?: Skill.Info,
|
||||
) {
|
||||
const agents = new Map<string, DeepMutable<Agent.Info>>();
|
||||
@@ -233,7 +241,7 @@ test("Agents is independently loadable with no quota, storage, MCP, or custom to
|
||||
test("preserves an existing user anti-overengineering skill", async () => {
|
||||
const first = await host();
|
||||
const original = { ...first.skills.get("anti-overengineering")!, content: "user definition" };
|
||||
const h = await host(models, { provider: "test" }, original);
|
||||
const h = await host(models, { agents }, original);
|
||||
expect(h.skills.get("anti-overengineering")).toEqual(original);
|
||||
});
|
||||
|
||||
@@ -250,26 +258,44 @@ test("worker availability, deep fallback, and model refresh remain provider awar
|
||||
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
|
||||
});
|
||||
|
||||
test("custom models use provider-qualified names and optional deep assignments", async () => {
|
||||
const assignments = Object.fromEntries(
|
||||
workerNames
|
||||
.filter((name) => !name.startsWith("deep-"))
|
||||
.map((name) => [name, { ...gptAgents[name], model: `test/${gptAgents[name].model}` }]),
|
||||
test("without agents options or with the empty skeleton nothing is registered", async () => {
|
||||
const skeleton = Object.fromEntries(Object.keys(agents).map((name) => [name, ""]));
|
||||
for (const options of [{}, { agents: skeleton }]) {
|
||||
const h = await host(models, options);
|
||||
expect([...h.agents.keys()]).toEqual(["build"]);
|
||||
expect(h.skills.size).toBe(0);
|
||||
}
|
||||
});
|
||||
|
||||
test("empty deep pair disables deep; partially filled required assignments fail", async () => {
|
||||
const h = await host(models, { agents: { ...agents, "deep-lo": "", "deep-hi": "" } });
|
||||
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol");
|
||||
expect(h.agents.has("deep-lo")).toBe(false);
|
||||
await expect(host(models, { agents: { ...agents, "good-hi": "" } })).rejects.toThrow(
|
||||
"agents good-hi is required",
|
||||
);
|
||||
await expect(host(models, { agents: { "deep-lo": agents["deep-lo"] } })).rejects.toThrow(
|
||||
"agents fast-lo is required",
|
||||
);
|
||||
});
|
||||
|
||||
test("assignments are provider-qualified with optional deep pair and variant", async () => {
|
||||
const shallow = Object.fromEntries(
|
||||
Object.entries(agents).filter(([name]) => !name.startsWith("deep-")),
|
||||
);
|
||||
const duplicate = models.map((model) => ({ ...model, providerID: Provider.ID.make("other") }));
|
||||
const h = await host([...duplicate, ...models], { mode: "custom", agents: assignments });
|
||||
const h = await host([...duplicate, ...models], { agents: shallow });
|
||||
expect(String(h.agents.get("coordinate")?.model?.providerID)).toBe("test");
|
||||
expect(String(h.agents.get("coordinate")?.model?.id)).toBe("gpt-6.1-sol");
|
||||
expect(h.agents.has("deep-hi")).toBe(false);
|
||||
expect(settings.safeParse({ mode: "gpt", provider: "test", lunaPriority: true }).success).toBe(
|
||||
false,
|
||||
expect(model("a/b/c#high", "n")).toEqual({ providerID: "a", id: "b/c", variant: "high" });
|
||||
expect(model("a/b", "n")).toEqual({ providerID: "a", id: "b" });
|
||||
expect(() => model("unqualified#low", "agents fast-lo")).toThrow(
|
||||
"agents fast-lo must be provider/model[#variant]: unqualified#low",
|
||||
);
|
||||
expect(
|
||||
settings.safeParse({
|
||||
mode: "custom",
|
||||
agents: { ...assignments, "fast-lo": { model: "unqualified", effort: "low" } },
|
||||
}).success,
|
||||
).toBe(false);
|
||||
await expect(
|
||||
host(models, { agents: { ...agents, "fast-lo": "unqualified#low" } }),
|
||||
).rejects.toThrow("agents fast-lo must be provider/model[#variant]");
|
||||
});
|
||||
|
||||
test("live final build permissions reach workers, coordinate and the native Agents RPC", async () => {
|
||||
@@ -351,30 +377,6 @@ test("reasoning uses advertised variants and falls back to request settings", as
|
||||
});
|
||||
});
|
||||
|
||||
test("Luna priority requires official or advertised support and can be disabled", async () => {
|
||||
const openai = models.map((model) => ({
|
||||
...model,
|
||||
providerID: Provider.ID.make("openai"),
|
||||
package: "@opencode/ai/providers/openai",
|
||||
}));
|
||||
const official = await host(openai, { provider: "openai" });
|
||||
expect(official.agents.get("fast-lo")?.request?.settings.serviceTier).toBe("priority");
|
||||
expect(official.agents.get("good-lo")?.request?.settings.serviceTier).toBeUndefined();
|
||||
const disabled = await host(openai, { provider: "openai", lunaPriority: false });
|
||||
expect(disabled.agents.get("fast-hi")?.request?.settings.serviceTier).toBeUndefined();
|
||||
const proxy = openai.map((model) => ({
|
||||
...model,
|
||||
settings: { baseURL: "https://proxy.example/v1" },
|
||||
}));
|
||||
const unadvertised = await host(proxy, { provider: "openai" });
|
||||
expect(unadvertised.agents.get("fast-lo")?.request?.settings.serviceTier).toBeUndefined();
|
||||
const advertised = await host(
|
||||
proxy.map((model) => ({ ...model, settings: { ...model.settings, serviceTier: "fast" } })),
|
||||
{ provider: "openai" },
|
||||
);
|
||||
expect(advertised.agents.get("fast-lo")?.request?.settings.serviceTier).toBe("fast");
|
||||
});
|
||||
|
||||
test("disabled catalog entries do not authorize worker availability", async () => {
|
||||
const h = await host(
|
||||
models.map((model) => ({ ...model, enabled: model.id !== "gpt-6-astra" })),
|
||||
|
||||
Reference in New Issue
Block a user