+84
-16
@@ -10,8 +10,9 @@ import type { JsonValue, ModelInfo, SessionGetInput } from "@opencode/client";
|
||||
import type { SessionContext } from "@opencode/plugin/promise/session";
|
||||
import { z } from "zod";
|
||||
import { gptAgents } from "../src/config.js";
|
||||
import plugin from "../src/index.js";
|
||||
import { basePlugin as plugin } from "../src/index.js";
|
||||
import { playwrightMcpCommand } from "../src/playwright.js";
|
||||
import { bindingKey } from "../src/multi-work.js";
|
||||
|
||||
const providerID = Provider.ID.make("test");
|
||||
function model(id: string): ModelInfo {
|
||||
@@ -63,6 +64,7 @@ async function host(
|
||||
let before!: (event: { tool: string; agent: string; input: unknown }) => Promise<void> | void;
|
||||
let parent = "build";
|
||||
let child = "fast-lo";
|
||||
let childDirectory = directory;
|
||||
let defaultAgent = "build";
|
||||
const registration = { async dispose() {} };
|
||||
let transform!: (editor: AgentEditor) => void;
|
||||
@@ -218,8 +220,13 @@ async function host(
|
||||
},
|
||||
async get({ sessionID }: { sessionID: string }) {
|
||||
return sessionID === "child"
|
||||
? { agent: child, parentID: "parent" }
|
||||
: { agent: parent };
|
||||
? {
|
||||
agent: child,
|
||||
projectID: "project-fixture",
|
||||
parentID: "parent",
|
||||
location: { directory: childDirectory },
|
||||
}
|
||||
: { agent: parent, projectID: "project-fixture", location: { directory } };
|
||||
},
|
||||
},
|
||||
tool: {
|
||||
@@ -299,6 +306,19 @@ async function host(
|
||||
child = target;
|
||||
for (const hook of sessionHooks.prompt ?? []) await hook({ sessionID: "child" });
|
||||
},
|
||||
bindCoordinate(ready: boolean, moved = true) {
|
||||
childDirectory = moved ? `${directory}/worktree` : directory;
|
||||
storage.set(bindingKey("child"), {
|
||||
owner: "parent",
|
||||
child: "child",
|
||||
projectID: "project-fixture",
|
||||
ready,
|
||||
root: { directory, workspaceID: "w1", repo: `${directory}/.git` },
|
||||
directory: `${directory}/worktree`,
|
||||
workspaceID: "w2",
|
||||
branch: "multi-work/test",
|
||||
});
|
||||
},
|
||||
async tools(caller: string) {
|
||||
const event: ModelContext = {
|
||||
agent: Agent.ID.make(caller),
|
||||
@@ -318,28 +338,52 @@ async function host(
|
||||
};
|
||||
}
|
||||
|
||||
test("missing required models disables registration; only GPT mode degrades without Astra", async () => {
|
||||
test("orchestration inherits deep-lo and falls back to good-lo with available worker sets", async () => {
|
||||
const full = await host();
|
||||
expect(full.agents.has("deep-hi")).toBe(true);
|
||||
expect(String(full.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
|
||||
expect(String(full.agents.get("coordinate")?.model?.variant)).toBe("low");
|
||||
const reduced = await host(allModels.slice(0, 2));
|
||||
expect(reduced.agents.has("deep-hi")).toBe(false);
|
||||
expect(String(reduced.agents.get("coordinate")?.model?.id)).toBe("gpt-5.6-sol");
|
||||
expect(String(reduced.agents.get("coordinate")?.model?.variant)).toBe("low");
|
||||
expect(reduced.agents.get("coordinate")?.system).toContain("Deep agents are unavailable");
|
||||
expect((await host([])).agents.has("coordinate")).toBe(false);
|
||||
expect((await host(allModels.slice(1))).agents.has("coordinate")).toBe(false);
|
||||
const custom = await host([...allModels, model("local")], {
|
||||
|
||||
const customAgents = {
|
||||
...gptAgents,
|
||||
"good-lo": { model: "custom-good", effort: "high" as const },
|
||||
"deep-lo": { model: "custom-deep", effort: "medium" as const },
|
||||
};
|
||||
const custom = await host(
|
||||
[...allModels, reasoningModel("custom-good"), reasoningModel("custom-deep")],
|
||||
{
|
||||
mode: "custom",
|
||||
provider: "test",
|
||||
agents: customAgents,
|
||||
},
|
||||
);
|
||||
expect(custom.agents.get("coordinate")?.model).toMatchObject({
|
||||
id: "custom-deep",
|
||||
variant: "medium",
|
||||
});
|
||||
const customFallback = await host([...allModels, reasoningModel("custom-good")], {
|
||||
mode: "custom",
|
||||
provider: "test",
|
||||
agents: { ...gptAgents, coordinate: { model: "local", effort: "low" } },
|
||||
agents: customAgents,
|
||||
});
|
||||
expect(String(custom.agents.get("coordinate")?.model?.id)).toBe("local");
|
||||
expect(customFallback.agents.get("coordinate")?.model).toMatchObject({
|
||||
id: "custom-good",
|
||||
variant: "high",
|
||||
});
|
||||
expect(customFallback.agents.has("deep-lo")).toBe(false);
|
||||
expect(
|
||||
(
|
||||
await host(allModels.slice(0, 2), {
|
||||
await host(allModels, {
|
||||
mode: "custom",
|
||||
provider: "test",
|
||||
agents: gptAgents,
|
||||
agents: customAgents,
|
||||
})
|
||||
).agents.has("coordinate"),
|
||||
).toBe(false);
|
||||
@@ -619,6 +663,27 @@ test("manual calls and command-created child sessions cannot bypass delegation r
|
||||
expect((await result.tools("build")).subagent?.description).toBe("Native subagents");
|
||||
});
|
||||
|
||||
test("coordinate prompt admission requires both owned provenance and a completed move; multi-work cannot be a child", async () => {
|
||||
const result = await host();
|
||||
await expect(result.command("multi-work", "coordinate")).rejects.toThrow(
|
||||
"ready worktree binding",
|
||||
);
|
||||
result.bindCoordinate(false);
|
||||
await expect(result.command("multi-work", "coordinate")).rejects.toThrow(
|
||||
"ready worktree binding",
|
||||
);
|
||||
result.bindCoordinate(true, false);
|
||||
await expect(result.command("multi-work", "coordinate")).rejects.toThrow(
|
||||
"ready worktree binding",
|
||||
);
|
||||
result.bindCoordinate(true);
|
||||
await result.command("multi-work", "coordinate");
|
||||
await expect(result.command("build", "coordinate")).rejects.toThrow("ready worktree binding");
|
||||
await expect(result.command("multi-work", "fast-lo")).rejects.toThrow("local fast-lo");
|
||||
for (const invoke of [result.delegate, result.command])
|
||||
await expect(invoke("build", "multi-work")).rejects.toThrow("primary only");
|
||||
});
|
||||
|
||||
test("reasoning settings and Luna priority use native advertised or official support", async () => {
|
||||
const luna = {
|
||||
...model("gpt-5.6-luna"),
|
||||
@@ -650,12 +715,12 @@ test("reasoning settings and Luna priority use native advertised or official sup
|
||||
expect(disabled.agents.get("fast-lo")?.request.settings).toEqual({ reasoningEffort: "low" });
|
||||
});
|
||||
|
||||
test("coordinator defaults expose their effort variant without relying on it for requests", async () => {
|
||||
test("coordinator uses inherited effort and ignores the legacy custom assignment", async () => {
|
||||
for (const options of [{ provider: "test" }, { mode: "gpt", provider: "test" }] as const) {
|
||||
const result = await host(allModels, options);
|
||||
expect(result.agents.get("coordinate")?.model).toMatchObject({
|
||||
id: "gpt-6-astra",
|
||||
variant: "medium",
|
||||
variant: "low",
|
||||
});
|
||||
expect(result.agents.get("coordinate")?.request.settings.reasoningEffort).toBeUndefined();
|
||||
}
|
||||
@@ -663,7 +728,7 @@ test("coordinator defaults expose their effort variant without relying on it for
|
||||
const fallback = await host(allModels.slice(0, 2));
|
||||
expect(fallback.agents.get("coordinate")?.model).toMatchObject({
|
||||
id: "gpt-5.6-sol",
|
||||
variant: "medium",
|
||||
variant: "low",
|
||||
});
|
||||
expect(fallback.agents.get("coordinate")?.request.settings.reasoningEffort).toBeUndefined();
|
||||
|
||||
@@ -672,8 +737,11 @@ test("coordinator defaults expose their effort variant without relying on it for
|
||||
provider: "test",
|
||||
agents: { ...gptAgents, coordinate: { model: "local", effort: "xhigh" } },
|
||||
});
|
||||
expect(custom.agents.get("coordinate")?.model?.variant).toBeUndefined();
|
||||
expect(custom.agents.get("coordinate")?.request.settings.reasoningEffort).toBe("xhigh");
|
||||
expect(custom.agents.get("coordinate")?.model).toMatchObject({
|
||||
id: "gpt-6-astra",
|
||||
variant: "low",
|
||||
});
|
||||
expect(custom.agents.get("coordinate")?.request.settings.reasoningEffort).toBeUndefined();
|
||||
});
|
||||
|
||||
test("the current host model API filters discovery and reloads changed availability", async () => {
|
||||
@@ -685,12 +753,12 @@ test("the current host model API filters discovery and reloads changed availabil
|
||||
const result = await host([]);
|
||||
await result.refresh(allModels);
|
||||
expect(String(result.agents.get("coordinate")?.model?.id)).toBe("gpt-6-astra");
|
||||
expect(String(result.agents.get("coordinate")?.model?.variant)).toBe("medium");
|
||||
expect(String(result.agents.get("coordinate")?.model?.variant)).toBe("low");
|
||||
expect(result.agents.get("coordinate")?.request.settings.reasoningEffort).toBeUndefined();
|
||||
await result.refresh(allModels.slice(0, 2));
|
||||
expect(result.agents.has("deep-lo")).toBe(false);
|
||||
expect(String(result.agents.get("coordinate")?.model?.id)).toBe("gpt-5.6-sol");
|
||||
expect(String(result.agents.get("coordinate")?.model?.variant)).toBe("medium");
|
||||
expect(String(result.agents.get("coordinate")?.model?.variant)).toBe("low");
|
||||
expect(result.agents.get("coordinate")?.request.settings.reasoningEffort).toBeUndefined();
|
||||
await result.refresh([]);
|
||||
expect(result.agents.has("coordinate")).toBe(false);
|
||||
|
||||
Reference in New Issue
Block a user