mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 12:40:32 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9d5d3bb9c | ||
|
|
cee383c67c | ||
|
|
041aa44d00 | ||
|
|
3db76b2d20 | ||
|
|
db965a31aa | ||
|
|
5280246773 | ||
|
|
9f3dd402ea | ||
|
|
d19e399018 | ||
|
|
24d1050f7a |
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 0.13.0
|
||||
|
||||
- Update to @anthropic-ai/claude-agent-sdk@0.2.6
|
||||
- Update to @agentclientprotocol/sdk@0.13.0
|
||||
|
||||
## 0.12.6
|
||||
|
||||
- Fix model selection
|
||||
|
||||
12
README.md
12
README.md
@@ -4,7 +4,7 @@
|
||||
|
||||
Use [Claude Code](https://www.anthropic.com/claude-code) from [ACP-compatible](https://agentclientprotocol.com) clients such as [Zed](https://zed.dev)!
|
||||
|
||||
This tool implements an ACP agent by using the official [Claude Code SDK](https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-overview), supporting:
|
||||
This tool implements an ACP agent by using the official [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview), supporting:
|
||||
|
||||
- Context @-mentions
|
||||
- Images
|
||||
@@ -32,20 +32,14 @@ Read the docs on [External Agent](https://zed.dev/docs/ai/external-agents) suppo
|
||||
|
||||
### Other clients
|
||||
|
||||
- Emacs via [agent-shell.el](https://github.com/xenodium/agent-shell)
|
||||
- [marimo notebook](https://github.com/marimo-team/marimo)
|
||||
- Neovim
|
||||
- via [CodeCompanion.nvim](https://codecompanion.olimorris.dev/configuration/adapters#setup-claude-code-via-acp)
|
||||
- via [yetone/avante.nvim](https://github.com/yetone/avante.nvim)
|
||||
|
||||
[Submit a PR](https://github.com/zed-industries/claude-code-acp/pulls) to add yours!
|
||||
Or try it with any of the other [ACP compatible clients](https://agentclientprotocol.com/overview/clients)!
|
||||
|
||||
#### Installation
|
||||
|
||||
Install the adapter from `npm`:
|
||||
|
||||
```bash
|
||||
npm install @zed-industries/claude-code-acp
|
||||
npm install -g @zed-industries/claude-code-acp
|
||||
```
|
||||
|
||||
You can then use `claude-code-acp` as a regular ACP agent:
|
||||
|
||||
833
package-lock.json
generated
833
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -3,7 +3,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "0.12.6",
|
||||
"version": "0.13.0",
|
||||
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
|
||||
"main": "dist/lib.js",
|
||||
"bin": {
|
||||
@@ -51,23 +51,23 @@
|
||||
"author": "Zed Industries",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "0.12.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.1.70",
|
||||
"@modelcontextprotocol/sdk": "1.25.0",
|
||||
"diff": "8.0.2",
|
||||
"minimatch": "^10.1.1"
|
||||
"@agentclientprotocol/sdk": "0.13.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.6",
|
||||
"@modelcontextprotocol/sdk": "1.25.2",
|
||||
"diff": "8.0.3",
|
||||
"minimatch": "10.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.71.2",
|
||||
"@types/node": "25.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.50.0",
|
||||
"@typescript-eslint/parser": "8.50.0",
|
||||
"@types/node": "25.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "8.53.0",
|
||||
"@typescript-eslint/parser": "8.53.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "16.5.0",
|
||||
"globals": "17.0.0",
|
||||
"prettier": "3.7.4",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.0.15"
|
||||
"vitest": "4.0.17"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,6 @@ export class ClaudeAcpAgent implements Agent {
|
||||
};
|
||||
client: AgentSideConnection;
|
||||
toolUseCache: ToolUseCache;
|
||||
fileContentCache: { [key: string]: string };
|
||||
backgroundTerminals: { [key: string]: BackgroundTerminal } = {};
|
||||
clientCapabilities?: ClientCapabilities;
|
||||
logger: Logger;
|
||||
@@ -152,7 +151,6 @@ export class ClaudeAcpAgent implements Agent {
|
||||
this.sessions = {};
|
||||
this.client = client;
|
||||
this.toolUseCache = {};
|
||||
this.fileContentCache = {};
|
||||
this.logger = logger ?? console;
|
||||
}
|
||||
|
||||
@@ -191,8 +189,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
sse: true,
|
||||
},
|
||||
sessionCapabilities: {
|
||||
// TODO: announce fork capability when sessionId handling is fixed
|
||||
// fork: {},
|
||||
fork: {},
|
||||
resume: {},
|
||||
},
|
||||
},
|
||||
@@ -330,7 +327,6 @@ export class ClaudeAcpAgent implements Agent {
|
||||
message,
|
||||
params.sessionId,
|
||||
this.toolUseCache,
|
||||
this.fileContentCache,
|
||||
this.client,
|
||||
this.logger,
|
||||
)) {
|
||||
@@ -394,7 +390,6 @@ export class ClaudeAcpAgent implements Agent {
|
||||
message.message.role,
|
||||
params.sessionId,
|
||||
this.toolUseCache,
|
||||
this.fileContentCache,
|
||||
this.client,
|
||||
this.logger,
|
||||
)) {
|
||||
@@ -459,15 +454,11 @@ export class ClaudeAcpAgent implements Agent {
|
||||
|
||||
async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {
|
||||
const response = await this.client.readTextFile(params);
|
||||
if (!params.limit && !params.line) {
|
||||
this.fileContentCache[params.path] = response.content;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {
|
||||
const response = await this.client.writeTextFile(params);
|
||||
this.fileContentCache[params.path] = params.content;
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -497,11 +488,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
toolCall: {
|
||||
toolCallId: toolUseID,
|
||||
rawInput: toolInput,
|
||||
title: toolInfoFromToolUse(
|
||||
{ name: toolName, input: toolInput },
|
||||
this.fileContentCache,
|
||||
this.logger,
|
||||
).title,
|
||||
title: toolInfoFromToolUse({ name: toolName, input: toolInput }).title,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -564,11 +551,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
toolCall: {
|
||||
toolCallId: toolUseID,
|
||||
rawInput: toolInput,
|
||||
title: toolInfoFromToolUse(
|
||||
{ name: toolName, input: toolInput },
|
||||
this.fileContentCache,
|
||||
this.logger,
|
||||
).title,
|
||||
title: toolInfoFromToolUse({ name: toolName, input: toolInput }).title,
|
||||
},
|
||||
});
|
||||
if (signal.aborted || response.outcome?.outcome === "cancelled") {
|
||||
@@ -611,7 +594,17 @@ export class ClaudeAcpAgent implements Agent {
|
||||
params: NewSessionRequest,
|
||||
creationOpts: { resume?: string; forkSession?: boolean } = {},
|
||||
): Promise<NewSessionResponse> {
|
||||
const sessionId = creationOpts.resume ?? randomUUID();
|
||||
// We want to create a new session id unless it is resume,
|
||||
// but not resume + forkSession.
|
||||
let sessionId;
|
||||
if (creationOpts.forkSession) {
|
||||
sessionId = randomUUID();
|
||||
} else if (creationOpts.resume) {
|
||||
sessionId = creationOpts.resume;
|
||||
} else {
|
||||
sessionId = randomUUID();
|
||||
}
|
||||
|
||||
const input = new Pushable<SDKUserMessage>();
|
||||
|
||||
const settingsManager = new SettingsManager(params.cwd, {
|
||||
@@ -672,9 +665,8 @@ export class ClaudeAcpAgent implements Agent {
|
||||
// Extract options from _meta if provided
|
||||
const userProvidedOptions = (params._meta as NewSessionMeta | undefined)?.claudeCode?.options;
|
||||
const extraArgs = { ...userProvidedOptions?.extraArgs };
|
||||
if (creationOpts?.resume === undefined) {
|
||||
if (creationOpts?.resume === undefined || creationOpts?.forkSession) {
|
||||
// Set our own session id if not resuming an existing session.
|
||||
// TODO: find a way to make this work for fork
|
||||
extraArgs["session-id"] = sessionId;
|
||||
}
|
||||
|
||||
@@ -998,7 +990,6 @@ export function toAcpNotifications(
|
||||
role: "assistant" | "user",
|
||||
sessionId: string,
|
||||
toolUseCache: ToolUseCache,
|
||||
fileContentCache: { [key: string]: string },
|
||||
client: AgentSideConnection,
|
||||
logger: Logger,
|
||||
): SessionNotification[] {
|
||||
@@ -1109,7 +1100,7 @@ export function toAcpNotifications(
|
||||
sessionUpdate: "tool_call",
|
||||
rawInput,
|
||||
status: "pending",
|
||||
...toolInfoFromToolUse(chunk, fileContentCache, logger),
|
||||
...toolInfoFromToolUse(chunk),
|
||||
};
|
||||
}
|
||||
break;
|
||||
@@ -1172,7 +1163,6 @@ export function streamEventToAcpNotifications(
|
||||
message: SDKPartialAssistantMessage,
|
||||
sessionId: string,
|
||||
toolUseCache: ToolUseCache,
|
||||
fileContentCache: { [key: string]: string },
|
||||
client: AgentSideConnection,
|
||||
logger: Logger,
|
||||
): SessionNotification[] {
|
||||
@@ -1184,7 +1174,6 @@ export function streamEventToAcpNotifications(
|
||||
"assistant",
|
||||
sessionId,
|
||||
toolUseCache,
|
||||
fileContentCache,
|
||||
client,
|
||||
logger,
|
||||
);
|
||||
@@ -1194,7 +1183,6 @@ export function streamEventToAcpNotifications(
|
||||
"assistant",
|
||||
sessionId,
|
||||
toolUseCache,
|
||||
fileContentCache,
|
||||
client,
|
||||
logger,
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
description: Say hello
|
||||
argument-hint: [name]
|
||||
argument-hint: name
|
||||
---
|
||||
|
||||
Respond with "Hello $1" and nothing else.
|
||||
|
||||
@@ -166,7 +166,7 @@ describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration"
|
||||
expect(commands).toContainEqual({
|
||||
name: "say-hello",
|
||||
description: "Say hello (project)",
|
||||
input: { hint: "[name]" },
|
||||
input: { hint: "name" },
|
||||
});
|
||||
|
||||
await connection.prompt({
|
||||
@@ -251,7 +251,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "execute",
|
||||
title: "`rm README.md.rm`",
|
||||
content: [
|
||||
@@ -276,7 +276,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "search",
|
||||
title: "Find `*/**.ts`",
|
||||
content: [],
|
||||
@@ -297,7 +297,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "think",
|
||||
title: "Handle user's work request",
|
||||
content: [
|
||||
@@ -322,7 +322,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "search",
|
||||
title: "List the `/Users/test/github/claude-code-acp` directory's contents",
|
||||
content: [],
|
||||
@@ -340,7 +340,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "search",
|
||||
title: 'grep ".*"',
|
||||
content: [],
|
||||
@@ -358,7 +358,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "edit",
|
||||
title: "Write /Users/test/project/example.txt",
|
||||
content: [
|
||||
@@ -384,7 +384,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "edit",
|
||||
title: "Write /Users/test/project/config.json",
|
||||
content: [
|
||||
@@ -409,7 +409,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "read",
|
||||
title: "Read File",
|
||||
content: [],
|
||||
@@ -427,7 +427,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "read",
|
||||
title: "Read /Users/test/project/data.json",
|
||||
content: [],
|
||||
@@ -446,7 +446,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "read",
|
||||
title: "Read /Users/test/project/large.txt (1 - 100)",
|
||||
content: [],
|
||||
@@ -466,7 +466,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "read",
|
||||
title: "Read /Users/test/project/large.txt (51 - 150)",
|
||||
content: [],
|
||||
@@ -485,7 +485,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "read",
|
||||
title: "Read /Users/test/project/large.txt (from line 201)",
|
||||
content: [],
|
||||
@@ -503,7 +503,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "execute",
|
||||
title: `Kill Process`,
|
||||
content: [],
|
||||
@@ -520,7 +520,7 @@ describe("tool conversions", () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(toolInfoFromToolUse(tool_use, {})).toStrictEqual({
|
||||
expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
|
||||
kind: "execute",
|
||||
title: `Tail Logs`,
|
||||
content: [],
|
||||
@@ -613,7 +613,6 @@ describe("tool conversions", () => {
|
||||
received.message.role,
|
||||
"test",
|
||||
{},
|
||||
{},
|
||||
{} as AgentSideConnection,
|
||||
console,
|
||||
),
|
||||
@@ -847,7 +846,7 @@ describe("permission requests", () => {
|
||||
|
||||
for (const testCase of testCases) {
|
||||
// Get the tool info that would be used in requestPermission
|
||||
const toolInfo = toolInfoFromToolUse(testCase.toolUse, {});
|
||||
const toolInfo = toolInfoFromToolUse(testCase.toolUse);
|
||||
|
||||
// Verify toolInfo has a title
|
||||
expect(toolInfo.title).toBeDefined();
|
||||
|
||||
112
src/tools.ts
112
src/tools.ts
@@ -1,5 +1,6 @@
|
||||
import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk";
|
||||
import { replaceAndCalculateLocation, SYSTEM_REMINDER } from "./mcp-server.js";
|
||||
import { SYSTEM_REMINDER } from "./mcp-server.js";
|
||||
import * as diff from "diff";
|
||||
import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
||||
|
||||
const acpUnqualifiedToolNames = {
|
||||
@@ -49,11 +50,7 @@ interface ToolUpdate {
|
||||
locations?: ToolCallLocation[];
|
||||
}
|
||||
|
||||
export function toolInfoFromToolUse(
|
||||
toolUse: any,
|
||||
cachedFileContent: { [key: string]: string },
|
||||
logger: Logger = console,
|
||||
): ToolInfo {
|
||||
export function toolInfoFromToolUse(toolUse: any): ToolInfo {
|
||||
const name = toolUse.name;
|
||||
const input = toolUse.input;
|
||||
|
||||
@@ -178,27 +175,7 @@ export function toolInfoFromToolUse(
|
||||
case acpToolNames.edit:
|
||||
case "Edit": {
|
||||
const path = input?.file_path ?? input?.file_path;
|
||||
let oldText = input.old_string ?? null;
|
||||
let newText = input.new_string ?? "";
|
||||
let affectedLines: number[] = [];
|
||||
|
||||
if (path && oldText) {
|
||||
try {
|
||||
const oldContent = cachedFileContent[path] || "";
|
||||
const newContent = replaceAndCalculateLocation(oldContent, [
|
||||
{
|
||||
oldText,
|
||||
newText,
|
||||
replaceAll: false,
|
||||
},
|
||||
]);
|
||||
oldText = oldContent;
|
||||
newText = newContent.newContent;
|
||||
affectedLines = newContent.lineNumbers;
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
return {
|
||||
title: path ? `Edit \`${path}\`` : "Edit",
|
||||
kind: "edit",
|
||||
@@ -208,16 +185,12 @@ export function toolInfoFromToolUse(
|
||||
{
|
||||
type: "diff",
|
||||
path,
|
||||
oldText,
|
||||
newText,
|
||||
oldText: input.old_string ?? null,
|
||||
newText: input.new_string ?? "",
|
||||
},
|
||||
]
|
||||
: [],
|
||||
locations: path
|
||||
? affectedLines.length > 0
|
||||
? affectedLines.map((line) => ({ line, path }))
|
||||
: [{ path }]
|
||||
: [],
|
||||
locations: path ? [{ path }] : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,7 +305,9 @@ export function toolInfoFromToolUse(
|
||||
label += " -P";
|
||||
}
|
||||
|
||||
label += ` "${input.pattern}"`;
|
||||
if (input.pattern) {
|
||||
label += ` "${input.pattern}"`;
|
||||
}
|
||||
|
||||
if (input.path) {
|
||||
label += ` ${input.path}`;
|
||||
@@ -441,6 +416,16 @@ export function toolUpdateFromToolResult(
|
||||
| BetaToolSearchToolResultBlockParam,
|
||||
toolUse: any | undefined,
|
||||
): ToolUpdate {
|
||||
if (
|
||||
"is_error" in toolResult &&
|
||||
toolResult.is_error &&
|
||||
toolResult.content &&
|
||||
toolResult.content.length > 0
|
||||
) {
|
||||
// Only return errors
|
||||
return toAcpContentUpdate(toolResult.content, true);
|
||||
}
|
||||
|
||||
switch (toolUse?.name) {
|
||||
case "Read":
|
||||
case acpToolNames.read:
|
||||
@@ -472,21 +457,60 @@ export function toolUpdateFromToolResult(
|
||||
}
|
||||
return {};
|
||||
|
||||
case acpToolNames.edit: {
|
||||
const content: ToolCallContent[] = [];
|
||||
const locations: ToolCallLocation[] = [];
|
||||
|
||||
if (
|
||||
Array.isArray(toolResult.content) &&
|
||||
toolResult.content.length > 0 &&
|
||||
"text" in toolResult.content[0] &&
|
||||
typeof toolResult.content[0].text === "string"
|
||||
) {
|
||||
const patches = diff.parsePatch(toolResult.content[0].text);
|
||||
console.error(JSON.stringify(patches));
|
||||
for (const { oldFileName, newFileName, hunks } of patches) {
|
||||
for (const { lines, newStart } of hunks) {
|
||||
const oldText = [];
|
||||
const newText = [];
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("-")) {
|
||||
oldText.push(line.slice(1));
|
||||
} else if (line.startsWith("+")) {
|
||||
newText.push(line.slice(1));
|
||||
} else {
|
||||
oldText.push(line.slice(1));
|
||||
newText.push(line.slice(1));
|
||||
}
|
||||
}
|
||||
if (oldText.length > 0 || newText.length > 0) {
|
||||
locations.push({ path: newFileName || oldFileName, line: newStart });
|
||||
content.push({
|
||||
type: "diff",
|
||||
path: newFileName || oldFileName,
|
||||
oldText: oldText.join("\n") || null,
|
||||
newText: newText.join("\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result: ToolUpdate = {};
|
||||
if (content.length > 0) {
|
||||
result.content = content;
|
||||
}
|
||||
if (locations.length > 0) {
|
||||
result.locations = locations;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
case acpToolNames.bash:
|
||||
case "edit":
|
||||
case "Edit":
|
||||
case acpToolNames.edit:
|
||||
case acpToolNames.write:
|
||||
case "Write": {
|
||||
if (
|
||||
"is_error" in toolResult &&
|
||||
toolResult.is_error &&
|
||||
toolResult.content &&
|
||||
toolResult.content.length > 0
|
||||
) {
|
||||
// Only return errors
|
||||
return toAcpContentUpdate(toolResult.content, true);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user