Videos HsxQICTLF84
Building an ACP-Compatible Agent Live — Bennet Fenner, Zed
Scene timeline
48 shot(s).
keyframes kept every frame deduplicated
What was stored
- cues
- 225
- whisperx 225
- chunks
- 32
- from 225 cues
- keyframes
- 24
- kept of 48 captured
- frames with text
- 24
- 1,310 lines read
- chapters
- 0
- from the source metadata
- keyframe bytes
- 6.2 MB
- word timings on 225 cues
Provenance
| stage | state | model | started | took |
|---|---|---|---|---|
fetch |
done | — | 2026-08-11 04:22 | 1m 16s |
stt |
done | — | 2026-08-11 04:23 | 17s |
chunk |
done | — | 2026-08-11 04:24 | 0s |
text_embed |
done | — | 2026-08-11 04:24 | 1s |
keyframe |
done | — | 2026-08-11 04:24 | 1m 35s |
ocr |
done | — | 2026-08-11 04:25 | 19s |
frame_embed |
done | — | 2026-08-11 04:25 | 4s |
Frames, and what the machine read
-
- AlEngineer0.97
- EUROPE1.00
-
- PRESENTINGSPONSOR1.00
- Google DeepMind1.00
-
- PLATINUM SPONSORS0.98
- # Braintrust0.96
- WorkOS OpenAI0.96
-
- Building an ACP1.00
- compatible agent1.00
- Bennet Fenner - April 10, 20260.97
- AlEngineer0.98
- EUROPE1.00
-
- CCS0.67
- Agent/Client1.00
- AIE1.00
- ★1.00
- Protocol1.00
- Engineering the future of Al0.98
-
- 圆0.53
- JETBRAINS1.00
- SIDEQUERY1.00
- In Progcess0.96
- marimo1.00
- ★1.00
- ★1.00
- AIE1.00
- ★1.00
- ★1.00
- ★1.00
- ★1.00
- ★1.00
- Nneovim1.00
- a0.76
- Obsidian1.00
- ALZEN0.79
- DEDPOHAT0.89
- MEB BRONSER0.81
- 40+ Clients1.00
- AlEngineer0.98
- EUROPE1.00
-
- acp-demo main0.96
- acp-demo-agent - Current Worktree (main)0.95
- ACP: acp-demo-agent0.99
- agent.ts0.96
- helpers.ts1.00
- coding-agent.ts1.00
- + .0.73
- src/agent.ts1.00
- QIS0.60
- 11.00
- import * as acp from "@agentclientprotocol/sdk";1.00
- 21.00
- import { Readable, Writable } from "node:stream";1.00
- 31.00
- import { CodingAgent, ToolResult } from "./coding-agent.js";0.99
- 'ToolResult' is declared0.98
- 41.00
- import { extractText } from "./helpers.js";0.99
- 'extractText' is declared but its value is0.99
- 51.00
- 61.00
- class AcpAgent implements acp.Agent {1.00
- 71.00
- connection: acp.AgentSideConnection;1.00
- 81.00
- sessions: Map<acp.SessionId, CodingAgent>;1.00
- ★1.00
- ★1.00
- AIE1.00
- ★1.00
- ★1.00
- 101.00
- 91.00
- constructor(connection: acp.AgentSideConnection) {1.00
- ★1.00
- ★1.00
- 111.00
- this.connection = connection;1.00
- ★1.00
- ★1.00
- ★1.00
- 121.00
- this.sessions = new Map();1.00
- 131.00
- 141.00
- 151.00
- async initialize(1.00
- 161.00
- _params: acp.InitializeRequest,1.00
- 171.00
- ): Promise<acp.InitializeResponse> {1.00
- 181.00
- throw new Error(message: "Not implemented");0.99
- 191.00
- 201.00
- 211.00
- async authenticate(1.00
- 221.00
- _params: acp.AuthenticateRequest,0.99
- Failed to Launch0.96
- Intemal error:0.91
- 231.00
- ): Promise<acp.AuthenticateResponse | void> {0.99
- "details": "Not implemented"0.91
- 241.00
- throw new Error(message: "Not implemented");0.99
- 5:1 Typo5crot 2= E= 8 P0.75
- AlEngineer0.95
- EUROPE1.00
-
- acp-demo main0.95
- acp-demo-agent Current Worktree (main)0.97
- ACP: acp-demo-agent0.98
- agent.ts1.00
- helpers.ts1.00
- coding-agent.ts1.00
- src/coding-agent.ts, const TOOLS, input_schema, properties0.95
- 431.00
- 441.00
- export type StopReason = "end_turn" | "max_tokens" | "cancelled";0.98
- 451.00
- 461.00
- export class CodingAgent {1.00
- 470.97
- private anthropic = new Anthropic();1.00
- 481.00
- private messages: Anthropic.MessageParam[] = [];0.99
- 491.00
- private abort: AbortController | null = null;0.99
- 501.00
- ★1.00
- ★1.00
- 511.00
- constructor(p1.00
- ★1.00
- AIE1.00
- ★1.00
- 521.00
- (parameter) userText: string0.99
- ★1.00
- ★1.00
- 531.00
- async prompt(userText: string): Promise<StopReason> {1.00
- ★1.00
- ★1.00
- ★1.00
- 541.00
- this.abort = new AbortController();0.99
- 551.00
- this.messages.push(...items: { role: "user", content: userText });0.99
- 561.00
- 571.00
- try {1.00
- 581.00
- return await this.agentLoop();0.98
- 591.00
- } catch (err) {0.97
- 601.00
- if (this.abort.signal.aborted) return "cancelled";1.00
- 611.00
- throw err;0.99
- 621.00
- }finally {0.99
- 631.00
- this.abort = null;0.97
- 641.00
- }0.80
- Failed to Launch0.98
- Internal error: {0.94
- 651.00
- "details": "Not implemented"0.92
- 661.00
- 28:11 Type5cript 2+ E 80.81
- Engineering the future of Al1.00
-
- acp-demo main0.94
- acp-demo-agent Current Worktree (main)0.96
- ACP: acp-demo-agent0.98
- agent.ts1.00
- helpers.ts1.00
- coding-agent.ts0.98
- +0.80
- src/coding-agent.ts, class CodingAgent, private async handleToolCcall()0.96
- 0 IS0.58
- 1341.00
- private async handleReadFile(1.00
- 1351.00
- toolCallId: string,1.00
- 'toolCallId' is declared but its value is never read.0.99
- 1361.00
- input: Record<string, unknown>,0.99
- 1371.00
- ): Promise<ToolResult> {0.98
- 1381.00
- const path = input.path as string;1.00
- 1391.00
- 1401.00
- let isError : boolean = false;0.98
- 1411.00
- let content;1.00
- AIE1.00
- ★1.00
- ★0.99
- 1421.00
- 1431.00
- try {1.00
- const fs : { default: typeof import("fs/promises"); access(path: PathLike, mode?:0.99
- ★1.00
- 1441.00
- content = await fs.readFile(path: path, options: "utf-8");1.00
- ★1.00
- ★1.00
- ★1.00
- 1451.00
- } catch (err: unknown0.98
- function readFile(path: PathLike | FileHandle,0.98
- 1461.00
- isError = true;0.99
- options: ({0.98
- 1471.00
- content = err insta1.00
- encoding: BufferEncoding;1.00
- 1481.00
- }0.68
- flag?: OpenMode | undefined;0.98
- 1491.00
- } & EventEmitter<T extends EventMap<T> =0.98
- 1501.00
- return { isError: isE1.00
- DefaultEventMap>.Abortable) | BufferEncoding):0.98
- 1511.00
- }0.50
- Promise<string> (+2 overloads)1.00
- 1521.00
- 1531.00
- private async handleEdi Asynchronously reads the entire contents of a file.0.99
- 1541.00
- toolCallId: string,0.98
- @param path0.98
- read.1.00
- 1551.00
- input: Record<string,0.99
- A path to a file. If a URL is provided, it must use the file:0.99
- Failed to Launch0.96
- Interal error: {0.94
- 1561.00
- ): Promise<ToolResult>1.00
- protocol. If a FileHandle is provided, the underlying file will1.00
- "details": "Not implemented"0.92
- 1571.00
- const path = input.path as string;1.00
- 117:36 Type5crpt 8+8P は0.75
- AlEngineer0.96
- EUROPE1.00
-
- acp-demo main0.95
- Settings0.97
- ACP: acp-demo-agent0.98
- agent.ts0.98
- types,gen.d.ts0.91
- helpers.ts0.97
- coding-agent.ts1.00
- External Agents1.00
- All agents conected through the Agent Clie0.96
- acp-demo-agent0.96
- Extemal Agents0.97
- Claudo Agent0.91
- × Zed Agent0.94
- acp-demo-nt0.96
- pent0.65
- src/agent.ts- class AcpAgent- async cancel()0.96
- 391.00
- async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {0.99
- 0 IS0.58
- claude-dev0.98
- Claude Agent0.97
- Codex CLI0.99
- codex-dev0.95
- claude-dev0.97
- 00.63
- 411.00
- 401.00
- const agent : CodingAgent | undefined = this.sessions.get(key: params.sessionId);0.98
- if (!agent) {0.92
- @ Codex CLI0.93
- @ Factory Droid0.93
- Cursor1.00
- 420.82
- throw new Error(message: 'Session not found: ${params.sessionId}');0.99
- codex-dev0.92
- Kimi CLI0.95
- GitHub Copilot0.99
- 431.00
- AIE1.00
- ★1.00
- ★1.00
- ★1.00
- Kimi CLI0.91
- M Mistral Vibe0.97
- Cursor1.00
- GitHub Copilot0.95
- @ Factory Droid0.95
- M Mistral Vibe0.98
- OpenCode0.99
- + Add More Agents0.97
- 00.96
- 00.96
- 00.95
- 441.00
- 451.00
- 461.00
- 471.00
- 481.00
- const stopReason : StopReason = await agent.prompt(userText: text);1.00
- return {0.99
- };0.80
- const text : string = extractText(prompt: params.prompt);0.99
- stopReason,1.00
- ★1.00
- ★1.00
- ★1.00
- OpenCode0.95
- 00.99
- 491.00
- 501.00
- Model Context Protocol (MCP) Servers1.00
- + Add Server0.93
- 511.00
- async cancel(params: acp.CancelNotification): Promise<void> {1.00
- All MCP servers connected directly or via a Zed extension.0.99
- Postgres0.94
- 521.00
- const agent : CodingAgent | undefined = this.sessions.get(key: params.sessionId);0.99
- C. Context7 3 2 sools0.88
- 531.00
- if (!agent) {0.95
- 541.00
- throw new Error(message: 'Session not found: ${params.sessionId}');0.99
- LLM Providers1.00
- + Add Provider0.93
- 551.00
- Add at least one provider to use Al-powered features with Zed's native agent.1.00
- Zed Prs0.86
- 561.00
- 571.00
- agent.cancel();1.00
- Amazon Bedrock0.97
- 581.00
- A Anthropic0.91
- 591.00
- GitHub Copilot Chat0.96
- 601.00
- const input : WritableStream<any> = Writable.toWeb(streamWritable: process.stdout);0.99
- DeepSeek0.92
- 611.00
- const output = Readable.toWeb(streamReadable: process.stdin) as ReadableStream<Uint8Arra0.99
- 620.92
- conct etrosm : Strosm = scn nd lconStrosmloutnut: innut innut: outnut).0.92
- 00.60
- 56:20 Type5crot 2+ E 8 P0.75
- Engineering the future of Al1.00
-
- acp-demo main0.92
- Hello0.92
- ☐ ACP: acp-demo-agent0.96
- agent.ts1.00
- types.gen.d.ts0.97
- helpers.ts1.00
- coding-agent.ts0.99
- Hello0.96
- ★1.00
- AIE1.00
- ★1.00
- ★1.00
- ★1.00
- ★1.00
- ★1.00
- ↑ session/new0.97
- { "cwd": "/Users/bebo/workspace/acp-demo", "mcpServers": [{ "name": "mcp-server-context7", "command": "/usr/local/bin,0.99
- ↓session/ne0.96
- { "sessionId": "65bb6bf5-739e-4028-9fc3-7774b7b5f8f5"}0.98
- ↑ session/prompt0.97
- Message acp-deno-agent - φ to snctude context0.94
- { "sessionId": "65bb6bf5-739e-4028-9fc3-7774b7b5f8f5", "prompt": [{ "type": "text", "text": "Hello" }] }0.98
- ↓ session/prompt0.97
- { "stopReason": "end_turn"}0.98
- Braintrust1.00
- WorkOS OpenAl0.92
-
- acp-demo main0.96
- Hello0.91
- ACP: acp-demo-agent0.99
- agent.ts0.96
- Definitions for CodingAg...0.96
- types,gen.d.ts0.91
- helpers.ts0.98
- coding-agent.ts0.99
- + .0.71
- Hello0.99
- src/agent.ts- class AcpAgent- async newSession( ), const agent0.96
- 0 IS0.57
- 151.00
- async initialize(0.99
- 161.00
- _params: acp. Init: Cancels ongoing operations for a session.0.99
- 171.00
- 181.00
- ): Promise<acp.Init:1.00
- return {1.00
- This is a notification sent by the client to cancel an ongoing prompt turn.0.99
- 191.00
- protocolVersion1.00
- Upon receiving this notification, the Agent SHOULD:0.99
- 201.00
- }i0.64
- • Stop all language model requests as soon as possible0.99
- 211.00
- • Abort all tool call invocations in progress0.98
- ★1.00
- 221.00
- • Send any pending session/update notifications0.98
- AIE1.00
- ★1.00
- 231.00
- async authenticate(1.00
- • Respond to the original session/prompt request with0.99
- ★1.00
- ★1.00
- ★1.00
- ★1.00
- 241.00
- 251.00
- 261.00
- ): Promise<acp. Auth See protocol docs: Cancellation0.97
- _params: acp.Authe0.98
- cancel1.00
- StopReason::Cancelled1.00
- 271.00
- 281.00
- async newSession(1.00
- params: acp.NewSes0.99
- connection1.00
- authenticate1.00
- 291.00
- ): Promise<acp.NewSe-0.98
- 301.00
- const id : '${str: Z const agent = new CodingAgent(params.cwd, this.connection0.98
- 311.00
- const agent = new CodingAgent(cwd: params.cwd, connection: this.c;0.99
- Expected 3 arg0.97
- 321.00
- this.sessions.set(key: id, value: agent);1.00
- 331.00
- 341.00
- return {1.00
- 351.00
- sessionId: id,1.00
- Message acp-demo~agent - to inctude context0.96
- 361.00
- }i0.65
- 371.00
- 381.00
- 2 Property 'c' does not exist on type AcpAgont0.93
- 31:53 Typešcrpt 24P0.77
- AlEngineer0.97
- EUROPE1.00
Transcript
225 cues· 2,586 words· 13,218 chars
- 0:14 I'm Bennett.
- 0:15 I work at Zed, and we built an AI code editor, all written in Rust.
- 0:19 And last year was kind of, as you probably all know, the rise of the AI coding agent terminal user interfaces with every major model provider, like building Cloud Code, Codex, Gemini, CLI, and so on.
- 0:34 And so at Zed, we asked ourselves, how can we let users bring their agent of choice to our tool and enjoy a nice interface that is unified across all of them?
- 0:47 And so that's why we decided we need some type of protocol called
- 0:52 agent-client protocol, which is similar to MCP or LSP.
- 0:58 It's a JSON RPC-based protocol.
- 1:00 And the idea is basically that agents and clients can talk to each other through a unified interface.
- 1:06 And yeah, online, it's open source.
- 1:12 You can contribute if you want.
- 1:14 At this point, we have a wide variety of agents already supporting this, either by an adapter that translates the agent's native language to the ACP one.
- 1:27 And then we have, for example, OpenCode and Cursor having ACP mode built into their CLI agents.
- 1:36 And we also have a bunch of clients at this point, up to 40, that implement this, including Open Claw, for example.
- 1:43 Open Claw itself is a client and a server, actually, like a client and an agent.
- 1:49 And JetBrains and Obsidian and other people are supporting this.
- 1:54 Great.
- 1:54 So I'm going to do a live coding session.
- 1:59 Let's see how well that goes.
- 2:03 Right.
- 2:05 Basically, we have some pre-existing code.
- 2:07 So this is Zed.
- 2:09 Here I have some TypeScript.
- 2:10 Also, bear with me.
- 2:11 I'm a Rust developer.
- 2:12 I have basically zero clue about TypeScript.
- 2:15 So if you see anything that you don't do in TypeScript, tell me afterwards.
- 2:21 But yeah, here's a very minimal coding agent that just doesn't support ACP, but it's kind of the bare minimum you need to build a coding agent.
- 2:30 All it has is really like two tools, one to read a file and one to edit an existing file.
- 2:37 Yeah, this is like pretty basic.
- 2:38 It provides, the model has to provide a path and it has to provide an old text that is like then just replaced with new text and that's kind of everything.
- 2:47 And then we have, in this case like I'm using Anthropic, there's a way to prompt the agent
- 2:55 Yeah, the user can prompt the agent, which is the function that we were going to call here.
- 3:01 And then we enter the agent loop.
- 3:02 And this is kind of like the way all agents basically work is the model APIs are stateless.
- 3:09 So you just attach some conversation up to this point.
- 3:12 You call the endpoint.
- 3:13 In this case, it's like the anthropic API.
- 3:16 And then we get a message from the model.
- 3:20 And either it can be an end turn.
- 3:21 That means the model decided to just output some text and do nothing.
- 3:27 Or it can call a tool.
- 3:29 And in this case, it would be like a read or a write tool call.
- 3:33 And then in the case of a tool call, we run, for example, the edit file tool call locally, collect the result, and then send it up to the model again.
- 3:42 That's where there's this loop.
- 3:45 And then we call the API again with the conversation up to that point.
- 3:49 And that's kind of everything.
- 3:51 And then we have this handle tool call function here, which handles read and write tool calls, which does what you expect.
- 4:00 We get the path, we read it from the file system, and we return some result.
- 4:08 So now the question is, how do we make this thing ACP compatible?
- 4:11 And hopefully, we can do it in 10 minutes.
loading