mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
Plannning
Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
This commit is contained in:
108
src/acp-agent.ts
108
src/acp-agent.ts
@@ -34,7 +34,7 @@ import { ContentBlock } from "@zed-industries/agent-client-protocol";
|
||||
import { SessionNotification } from "@zed-industries/agent-client-protocol";
|
||||
import { createMcpServer } from "./mcp-server.js";
|
||||
import { AddressInfo } from "node:net";
|
||||
import { toolContent, toolLabel, toolKind } from "./tools.js";
|
||||
import { toolContent, toolLabel, toolKind, planEntries } from "./tools.js";
|
||||
|
||||
// Implement the ACP Agent interface
|
||||
export class ClaudeAcpAgent implements Agent {
|
||||
@@ -225,7 +225,7 @@ function promptToClaude(prompt: PromptRequest): SDKUserMessage {
|
||||
* Convert an SDKAssistantMessage (Claude) to a SessionNotification (ACP).
|
||||
* Only handles text, image, and thinking chunks for now.
|
||||
*/
|
||||
function toAcpNotifications(
|
||||
export function toAcpNotifications(
|
||||
message: SDKAssistantMessage | SDKUserMessage,
|
||||
sessionId: string,
|
||||
): SessionNotification[] {
|
||||
@@ -266,16 +266,100 @@ function toAcpNotifications(
|
||||
};
|
||||
break;
|
||||
case "tool_use":
|
||||
update = {
|
||||
toolCallId: chunk.id,
|
||||
title: toolLabel(chunk),
|
||||
sessionUpdate: "tool_call",
|
||||
kind: toolKind(chunk.name), // todo!()
|
||||
rawInput: chunk.input,
|
||||
status: "pending",
|
||||
content: toolContent(chunk),
|
||||
};
|
||||
break;
|
||||
// {
|
||||
// "type": "assistant",
|
||||
// "message": {
|
||||
// "id": "msg_017eNosJgww7F5qD4a8BcAcx",
|
||||
// "type": "message",
|
||||
// "role": "assistant",
|
||||
// "model": "claude-sonnet-4-20250514",
|
||||
// "content": [
|
||||
// {
|
||||
// "type": "tool_use",
|
||||
// "id": "toolu_01HaXZ4LfdchSeSR8ygt4zyq",
|
||||
// "name": "TodoWrite",
|
||||
// "input": {
|
||||
// "todos": [
|
||||
// {
|
||||
// "content": "Analyze existing test coverage and identify gaps",
|
||||
// "status": "in_progress",
|
||||
// "activeForm": "Analyzing existing test coverage"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add comprehensive edge case tests",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding comprehensive edge case tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add performance and timing tests",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding performance and timing tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add error handling and panic behavior tests",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding error handling tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add concurrent access and race condition tests",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding concurrent access tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add tests for Each function with various data types",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding Each function tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Add benchmark tests for performance measurement",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Adding benchmark tests"
|
||||
// },
|
||||
// {
|
||||
// "content": "Improve test organization and helper functions",
|
||||
// "status": "pending",
|
||||
// "activeForm": "Improving test organization"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// "stop_reason": null,
|
||||
// "stop_sequence": null,
|
||||
// "usage": {
|
||||
// "input_tokens": 6,
|
||||
// "cache_creation_input_tokens": 326,
|
||||
// "cache_read_input_tokens": 17265,
|
||||
// "cache_creation": {
|
||||
// "ephemeral_5m_input_tokens": 326,
|
||||
// "ephemeral_1h_input_tokens": 0
|
||||
// },
|
||||
// "output_tokens": 1,
|
||||
// "service_tier": "standard"
|
||||
// }
|
||||
// },
|
||||
// "parent_tool_use_id": null,
|
||||
// "session_id": "d056596f-e328-41e9-badd-b07122ae5227",
|
||||
// "uuid": "b7c3330c-de8f-4bba-ac53-68c7f76ffeb5"
|
||||
// }
|
||||
if (chunk.name == "TodoWrite") {
|
||||
update = {
|
||||
sessionUpdate: "plan",
|
||||
entries: planEntries(chunk.input),
|
||||
};
|
||||
break;
|
||||
} else {
|
||||
update = {
|
||||
toolCallId: chunk.id,
|
||||
title: toolLabel(chunk),
|
||||
sessionUpdate: "tool_call",
|
||||
kind: toolKind(chunk.name), // todo!()
|
||||
rawInput: chunk.input,
|
||||
status: "pending",
|
||||
content: toolContent(chunk),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case "tool_result":
|
||||
update = {
|
||||
|
||||
@@ -15,6 +15,9 @@ import {
|
||||
} from "@zed-industries/agent-client-protocol";
|
||||
import { nodeToWebWritable, nodeToWebReadable } from "../utils.js";
|
||||
import { toolContent, toolKind, toolLabel } from "../tools.js";
|
||||
import { toAcpNotifications } from "../acp-agent.js";
|
||||
import { UUID } from "crypto";
|
||||
import { SDKAssistantMessage } from "@anthropic-ai/claude-code";
|
||||
|
||||
describe("ACP subprocess integration", () => {
|
||||
let child: ReturnType<typeof spawn>;
|
||||
@@ -96,4 +99,134 @@ describe("tool conversions", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("should handle plan entries", () => {
|
||||
const received: SDKAssistantMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "msg_017eNosJgww7F5qD4a8BcAcx",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
model: "claude-sonnet-4-20250514",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "toolu_01HaXZ4LfdchSeSR8ygt4zyq",
|
||||
name: "TodoWrite",
|
||||
input: {
|
||||
todos: [
|
||||
{
|
||||
content: "Analyze existing test coverage and identify gaps",
|
||||
status: "in_progress",
|
||||
activeForm: "Analyzing existing test coverage",
|
||||
},
|
||||
{
|
||||
content: "Add comprehensive edge case tests",
|
||||
status: "pending",
|
||||
activeForm: "Adding comprehensive edge case tests",
|
||||
},
|
||||
{
|
||||
content: "Add performance and timing tests",
|
||||
status: "pending",
|
||||
activeForm: "Adding performance and timing tests",
|
||||
},
|
||||
{
|
||||
content: "Add error handling and panic behavior tests",
|
||||
status: "pending",
|
||||
activeForm: "Adding error handling tests",
|
||||
},
|
||||
{
|
||||
content: "Add concurrent access and race condition tests",
|
||||
status: "pending",
|
||||
activeForm: "Adding concurrent access tests",
|
||||
},
|
||||
{
|
||||
content:
|
||||
"Add tests for Each function with various data types",
|
||||
status: "pending",
|
||||
activeForm: "Adding Each function tests",
|
||||
},
|
||||
{
|
||||
content: "Add benchmark tests for performance measurement",
|
||||
status: "pending",
|
||||
activeForm: "Adding benchmark tests",
|
||||
},
|
||||
{
|
||||
content: "Improve test organization and helper functions",
|
||||
status: "pending",
|
||||
activeForm: "Improving test organization",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
stop_reason: null,
|
||||
stop_sequence: null,
|
||||
usage: {
|
||||
input_tokens: 6,
|
||||
cache_creation_input_tokens: 326,
|
||||
cache_read_input_tokens: 17265,
|
||||
cache_creation: {
|
||||
ephemeral_5m_input_tokens: 326,
|
||||
ephemeral_1h_input_tokens: 0,
|
||||
},
|
||||
output_tokens: 1,
|
||||
service_tier: "standard",
|
||||
},
|
||||
},
|
||||
parent_tool_use_id: null,
|
||||
session_id: "d056596f-e328-41e9-badd-b07122ae5227",
|
||||
uuid: "b7c3330c-de8f-4bba-ac53-68c7f76ffeb5",
|
||||
};
|
||||
expect(toAcpNotifications(received, "test")).toStrictEqual([
|
||||
{
|
||||
sessionId: "test",
|
||||
update: {
|
||||
sessionUpdate: "plan",
|
||||
entries: [
|
||||
{
|
||||
content: "Analyze existing test coverage and identify gaps",
|
||||
priority: "medium",
|
||||
status: "in_progress",
|
||||
},
|
||||
{
|
||||
content: "Add comprehensive edge case tests",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Add performance and timing tests",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Add error handling and panic behavior tests",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Add concurrent access and race condition tests",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Add tests for Each function with various data types",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Add benchmark tests for performance measurement",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
content: "Improve test organization and helper functions",
|
||||
priority: "medium",
|
||||
status: "pending",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
15
src/tools.ts
15
src/tools.ts
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
PlanEntry,
|
||||
ToolCallContent,
|
||||
ToolKind,
|
||||
} from "@zed-industries/agent-client-protocol";
|
||||
@@ -249,3 +250,17 @@ export function toolContent(toolUse: any): ToolCallContent[] {
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
type ClaudePlanEntry = {
|
||||
content: string;
|
||||
status: "pending" | "in_progress" | "completed";
|
||||
activeForm: string;
|
||||
};
|
||||
|
||||
export function planEntries(input: { todos: ClaudePlanEntry[] }): PlanEntry[] {
|
||||
return input.todos.map((input) => ({
|
||||
content: input.content,
|
||||
status: input.status,
|
||||
priority: "medium",
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user