ACP: update package, fix slash command bug (#3906)

This commit is contained in:
Aiden Cline
2025-11-05 00:50:48 -06:00
committed by GitHub
parent 3ebec2435a
commit 1e0596bc46
6 changed files with 87 additions and 35 deletions

View File

@@ -173,7 +173,7 @@
"dependencies": { "dependencies": {
"@actions/core": "1.11.1", "@actions/core": "1.11.1",
"@actions/github": "6.0.1", "@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.4.9", "@agentclientprotocol/sdk": "0.5.1",
"@clack/prompts": "1.0.0-alpha.1", "@clack/prompts": "1.0.0-alpha.1",
"@hono/standard-validator": "0.1.5", "@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:", "@hono/zod-validator": "catalog:",
@@ -401,7 +401,7 @@
"@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="],
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.4.9", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-ExwH828LaTGoTTjxuw49l+fwOLA+Yx0+qkWn1TcHMOsY5mVI9CUfkj7ZDhv2klgZ7mJeT+lxX/Dn/KINv1AkNQ=="], "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.5.1", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-9bq2TgjhLBSUSC5jE04MEe+Hqw8YePzKghhYZ9QcjOyonY3q2oJfX6GoSO83hURpEnsqEPIrex6VZN3+61fBJg=="],
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="], "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="],

View File

@@ -43,7 +43,7 @@
"dependencies": { "dependencies": {
"@actions/core": "1.11.1", "@actions/core": "1.11.1",
"@actions/github": "6.0.1", "@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.4.9", "@agentclientprotocol/sdk": "0.5.1",
"@clack/prompts": "1.0.0-alpha.1", "@clack/prompts": "1.0.0-alpha.1",
"@hono/standard-validator": "0.1.5", "@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:", "@hono/zod-validator": "catalog:",
@@ -57,8 +57,8 @@
"@opentui/core": "0.1.33", "@opentui/core": "0.1.33",
"@opentui/solid": "0.1.33", "@opentui/solid": "0.1.33",
"@parcel/watcher": "2.5.1", "@parcel/watcher": "2.5.1",
"@solid-primitives/event-bus": "1.1.2",
"@pierre/precision-diffs": "catalog:", "@pierre/precision-diffs": "catalog:",
"@solid-primitives/event-bus": "1.1.2",
"@standard-schema/spec": "1.0.0", "@standard-schema/spec": "1.0.0",
"@zip.js/zip.js": "2.7.62", "@zip.js/zip.js": "2.7.62",
"ai": "catalog:", "ai": "catalog:",

View File

@@ -1,9 +1,12 @@
import { import {
RequestError,
type Agent as ACPAgent, type Agent as ACPAgent,
type AgentSideConnection, type AgentSideConnection,
type AuthenticateRequest, type AuthenticateRequest,
type AuthMethod,
type CancelNotification, type CancelNotification,
type InitializeRequest, type InitializeRequest,
type InitializeResponse,
type LoadSessionRequest, type LoadSessionRequest,
type NewSessionRequest, type NewSessionRequest,
type PermissionOption, type PermissionOption,
@@ -33,6 +36,7 @@ import type { Config } from "@/config/config"
import { MCP } from "@/mcp" import { MCP } from "@/mcp"
import { Todo } from "@/session/todo" import { Todo } from "@/session/todo"
import { z } from "zod" import { z } from "zod"
import { LoadAPIKeyError } from "ai"
export namespace ACP { export namespace ACP {
const log = Log.create({ service: "acp-agent" }) const log = Log.create({ service: "acp-agent" })
@@ -302,9 +306,26 @@ export namespace ACP {
}) })
} }
async initialize(params: InitializeRequest) { async initialize(params: InitializeRequest): Promise<InitializeResponse> {
log.info("initialize", { protocolVersion: params.protocolVersion }) log.info("initialize", { protocolVersion: params.protocolVersion })
const authMethod: AuthMethod = {
description: "Run `opencode auth login` in the terminal",
name: "Login with opencode",
id: "opencode-login",
}
// If client supports terminal-auth capability, use that instead.
if (params.clientCapabilities?._meta?.["terminal-auth"] === true) {
authMethod._meta = {
"terminal-auth": {
command: "opencode",
args: ["auth", "login"],
label: "OpenCode Login",
},
}
}
return { return {
protocolVersion: 1, protocolVersion: 1,
agentCapabilities: { agentCapabilities: {
@@ -325,11 +346,10 @@ export namespace ACP {
id: "opencode-login", id: "opencode-login",
}, },
], ],
_meta: { agentInfo: {
opencode: { name: "OpenCode",
version: Installation.VERSION, version: Installation.VERSION,
}, },
},
} }
} }
@@ -338,6 +358,7 @@ export namespace ACP {
} }
async newSession(params: NewSessionRequest) { async newSession(params: NewSessionRequest) {
try {
const model = await defaultModel(this.config) const model = await defaultModel(this.config)
const session = await this.sessionManager.create(params.cwd, params.mcpServers, model) const session = await this.sessionManager.create(params.cwd, params.mcpServers, model)
@@ -354,6 +375,15 @@ export namespace ACP {
modes: load.modes, modes: load.modes,
_meta: {}, _meta: {},
} }
} catch (e) {
const error = MessageV2.fromError(e, {
providerID: this.config.defaultModel?.providerID ?? "unknown",
})
if (LoadAPIKeyError.isInstance(error)) {
throw RequestError.authRequired()
}
throw e
}
} }
async loadSession(params: LoadSessionRequest) { async loadSession(params: LoadSessionRequest) {
@@ -387,16 +417,6 @@ export namespace ACP {
description: "compact the session", description: "compact the session",
}) })
setTimeout(() => {
this.connection.sessionUpdate({
sessionId,
update: {
sessionUpdate: "available_commands_update",
availableCommands,
},
})
}, 0)
const availableModes = (await Agents.list()) const availableModes = (await Agents.list())
.filter((agent) => agent.mode !== "subagent") .filter((agent) => agent.mode !== "subagent")
.map((agent) => ({ .map((agent) => ({
@@ -437,6 +457,16 @@ export namespace ACP {
}), }),
) )
setTimeout(() => {
this.connection.sessionUpdate({
sessionId,
update: {
sessionUpdate: "available_commands_update",
availableCommands,
},
})
}, 0)
return { return {
sessionId, sessionId,
models: { models: {

View File

@@ -6,13 +6,18 @@ import type { ACPSessionState } from "./types"
export class ACPSessionManager { export class ACPSessionManager {
private sessions = new Map<string, ACPSessionState>() private sessions = new Map<string, ACPSessionState>()
async create(cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"]): Promise<ACPSessionState> { async create(
cwd: string,
mcpServers: McpServer[],
model?: ACPSessionState["model"],
): Promise<ACPSessionState> {
const session = await Session.create({ title: `ACP Session ${crypto.randomUUID()}` }) const session = await Session.create({ title: `ACP Session ${crypto.randomUUID()}` })
const sessionId = session.id const sessionId = session.id
const resolvedModel = model ?? (await Provider.defaultModel()) const resolvedModel = model ?? (await Provider.defaultModel())
const state: ACPSessionState = { const state: ACPSessionState = {
id: sessionId, id: sessionId,
parentId: session.parentID,
cwd, cwd,
mcpServers, mcpServers,
createdAt: new Date(), createdAt: new Date(),

View File

@@ -2,6 +2,7 @@ import type { McpServer } from "@agentclientprotocol/sdk"
export interface ACPSessionState { export interface ACPSessionState {
id: string id: string
parentId?: string
cwd: string cwd: string
mcpServers: McpServer[] mcpServers: McpServer[]
createdAt: Date createdAt: Date

View File

@@ -77,7 +77,15 @@ export namespace MCP {
} }
}, },
async (state) => { async (state) => {
await Promise.all(Object.values(state.clients).map((client) => client.close())) await Promise.all(
Object.values(state.clients).map((client) =>
client.close().catch((error) => {
log.error("Failed to close MCP client", {
error,
})
}),
),
)
}, },
) )
@@ -201,7 +209,15 @@ export namespace MCP {
const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => {}) const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => {})
if (!result) { if (!result) {
await mcpClient.close() await mcpClient.close().catch((error) => {
log.error("Failed to close MCP client", {
error,
})
})
status = {
status: "failed",
error: "Failed to get tools",
}
return { return {
mcpClient: undefined, mcpClient: undefined,
status: { status: {