mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 02:36:57 -04:00
111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import type { AgentSideConnection } from "@agentclientprotocol/sdk"
|
|
import { OpenCode } from "@opencode-ai/client/promise"
|
|
import { ACPService } from "../../src/acp/service"
|
|
|
|
describe("acp service", () => {
|
|
test("creates a v2 session, registers mcp, and publishes commands", async () => {
|
|
const requests: Array<{ method: string; path: string; body?: unknown }> = []
|
|
const updates: Parameters<AgentSideConnection["sessionUpdate"]>[0][] = []
|
|
const server = Bun.serve({
|
|
port: 0,
|
|
async fetch(request) {
|
|
const url = new URL(request.url)
|
|
requests.push({
|
|
method: request.method,
|
|
path: url.pathname,
|
|
body: request.method === "GET" ? undefined : await request.json().catch(() => undefined),
|
|
})
|
|
const location = { directory: "/workspace", project: { id: "global", directory: "/workspace" } }
|
|
if (url.pathname === "/api/model") return Response.json({ location, data: [model] })
|
|
if (url.pathname === "/api/model/default") return Response.json({ location, data: model })
|
|
if (url.pathname === "/api/agent") return Response.json({ location, data: [agent] })
|
|
if (url.pathname === "/api/command")
|
|
return Response.json({ location, data: [{ name: "review", template: "" }] })
|
|
if (url.pathname === "/api/skill") return Response.json({ location, data: [skill] })
|
|
if (url.pathname === "/api/session" && request.method === "POST") return Response.json({ data: session })
|
|
if (url.pathname === "/api/mcp/docs" && request.method === "PUT") return new Response(null, { status: 204 })
|
|
return new Response(null, { status: 404 })
|
|
},
|
|
})
|
|
const service = ACPService.make({
|
|
client: OpenCode.make({ baseUrl: server.url.toString() }),
|
|
connection: {
|
|
sessionUpdate: async (update) => {
|
|
updates.push(update)
|
|
},
|
|
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
},
|
|
})
|
|
|
|
try {
|
|
const result = await service.newSession({
|
|
cwd: "/workspace",
|
|
mcpServers: [{ name: "docs", command: "bun", args: ["docs.ts"], env: [{ name: "TOKEN", value: "x" }] }],
|
|
})
|
|
expect(result.sessionId).toBe("ses_acp")
|
|
expect(result.configOptions?.map((option) => option.id)).toEqual(["model", "effort", "mode"])
|
|
expect(requests).toContainEqual({
|
|
method: "PUT",
|
|
path: "/api/mcp/docs",
|
|
body: {
|
|
config: { type: "local", command: ["bun", "docs.ts"], environment: { TOKEN: "x" } },
|
|
},
|
|
})
|
|
expect(updates.at(-1)).toMatchObject({
|
|
sessionId: "ses_acp",
|
|
update: {
|
|
sessionUpdate: "available_commands_update",
|
|
availableCommands: [{ name: "review" }, { name: "verify", description: "Verify work" }],
|
|
},
|
|
})
|
|
} finally {
|
|
await server.stop(true)
|
|
}
|
|
})
|
|
})
|
|
|
|
const model = {
|
|
id: "test-model",
|
|
modelID: "test-model",
|
|
providerID: "test",
|
|
name: "Test Model",
|
|
capabilities: { tools: true, input: ["text"], output: ["text"] },
|
|
variants: [{ id: "default" }, { id: "high" }],
|
|
time: { released: 0 },
|
|
cost: [],
|
|
status: "active" as const,
|
|
enabled: true,
|
|
limit: { context: 100_000, output: 10_000 },
|
|
}
|
|
|
|
const agent = {
|
|
id: "build",
|
|
name: "Build",
|
|
request: { settings: {}, headers: {}, body: {} },
|
|
mode: "primary" as const,
|
|
hidden: false,
|
|
permissions: [],
|
|
}
|
|
|
|
const skill = {
|
|
id: "verify",
|
|
name: "verify",
|
|
description: "Verify work",
|
|
slash: true,
|
|
location: "/skills/verify.md",
|
|
content: "verify",
|
|
}
|
|
|
|
const session = {
|
|
id: "ses_acp",
|
|
projectID: "global",
|
|
agent: "build",
|
|
model: { providerID: "test", id: "test-model", variant: "default" },
|
|
cost: 0,
|
|
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
time: { created: 0, updated: 0 },
|
|
title: "New session",
|
|
location: { directory: "/workspace" },
|
|
}
|