Skip to content

Commit f952023

Browse files
committed
feat: consolidate terminal methods into main Client interface and add KillTerminalCommand
Change-Id: Ie34241477e4f04a55a57dd04639c68f9b2b6fcc3 Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent 55ce342 commit f952023

9 files changed

Lines changed: 194 additions & 68 deletions

File tree

go/acp_test.go

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ type clientFuncs struct {
1414
ReadTextFileFunc func(context.Context, ReadTextFileRequest) (ReadTextFileResponse, error)
1515
RequestPermissionFunc func(context.Context, RequestPermissionRequest) (RequestPermissionResponse, error)
1616
SessionUpdateFunc func(context.Context, SessionNotification) error
17+
// Terminal-related handlers
18+
CreateTerminalFunc func(context.Context, CreateTerminalRequest) (CreateTerminalResponse, error)
19+
KillTerminalCommandFunc func(context.Context, KillTerminalCommandRequest) error
20+
ReleaseTerminalFunc func(context.Context, ReleaseTerminalRequest) error
21+
TerminalOutputFunc func(context.Context, TerminalOutputRequest) (TerminalOutputResponse, error)
22+
WaitForTerminalExitFunc func(context.Context, WaitForTerminalExitRequest) (WaitForTerminalExitResponse, error)
1723
}
1824

1925
var _ Client = (*clientFuncs)(nil)
@@ -46,6 +52,46 @@ func (c clientFuncs) SessionUpdate(ctx context.Context, n SessionNotification) e
4652
return nil
4753
}
4854

55+
// CreateTerminal implements Client.
56+
func (c *clientFuncs) CreateTerminal(ctx context.Context, params CreateTerminalRequest) (CreateTerminalResponse, error) {
57+
if c.CreateTerminalFunc != nil {
58+
return c.CreateTerminalFunc(ctx, params)
59+
}
60+
return CreateTerminalResponse{TerminalId: "test-terminal"}, nil
61+
}
62+
63+
// KillTerminalCommand implements Client.
64+
func (c *clientFuncs) KillTerminalCommand(ctx context.Context, params KillTerminalCommandRequest) error {
65+
if c.KillTerminalCommandFunc != nil {
66+
return c.KillTerminalCommandFunc(ctx, params)
67+
}
68+
return nil
69+
}
70+
71+
// ReleaseTerminal implements Client.
72+
func (c *clientFuncs) ReleaseTerminal(ctx context.Context, params ReleaseTerminalRequest) error {
73+
if c.ReleaseTerminalFunc != nil {
74+
return c.ReleaseTerminalFunc(ctx, params)
75+
}
76+
return nil
77+
}
78+
79+
// TerminalOutput implements Client.
80+
func (c *clientFuncs) TerminalOutput(ctx context.Context, params TerminalOutputRequest) (TerminalOutputResponse, error) {
81+
if c.TerminalOutputFunc != nil {
82+
return c.TerminalOutputFunc(ctx, params)
83+
}
84+
return TerminalOutputResponse{Output: "ok", Truncated: false}, nil
85+
}
86+
87+
// WaitForTerminalExit implements Client.
88+
func (c *clientFuncs) WaitForTerminalExit(ctx context.Context, params WaitForTerminalExitRequest) (WaitForTerminalExitResponse, error) {
89+
if c.WaitForTerminalExitFunc != nil {
90+
return c.WaitForTerminalExitFunc(ctx, params)
91+
}
92+
return WaitForTerminalExitResponse{}, nil
93+
}
94+
4995
type agentFuncs struct {
5096
InitializeFunc func(context.Context, InitializeRequest) (InitializeResponse, error)
5197
NewSessionFunc func(context.Context, NewSessionRequest) (NewSessionResponse, error)
@@ -108,7 +154,7 @@ func TestConnectionHandlesErrorsBidirectional(t *testing.T) {
108154
c2aR, c2aW := io.Pipe()
109155
a2cR, a2cW := io.Pipe()
110156

111-
c := NewClientSideConnection(clientFuncs{
157+
c := NewClientSideConnection(&clientFuncs{
112158
WriteTextFileFunc: func(context.Context, WriteTextFileRequest) error {
113159
return &RequestError{Code: -32603, Message: "Write failed"}
114160
},
@@ -158,7 +204,7 @@ func TestConnectionHandlesConcurrentRequests(t *testing.T) {
158204
var mu sync.Mutex
159205
requestCount := 0
160206

161-
_ = NewClientSideConnection(clientFuncs{
207+
_ = NewClientSideConnection(&clientFuncs{
162208
WriteTextFileFunc: func(context.Context, WriteTextFileRequest) error {
163209
mu.Lock()
164210
requestCount++
@@ -229,7 +275,7 @@ func TestConnectionHandlesMessageOrdering(t *testing.T) {
229275
var log []string
230276
push := func(s string) { mu.Lock(); defer mu.Unlock(); log = append(log, s) }
231277

232-
cs := NewClientSideConnection(clientFuncs{
278+
cs := NewClientSideConnection(&clientFuncs{
233279
WriteTextFileFunc: func(_ context.Context, req WriteTextFileRequest) error {
234280
push("writeTextFile called: " + req.Path)
235281
return nil
@@ -329,7 +375,7 @@ func TestConnectionHandlesNotifications(t *testing.T) {
329375
var logs []string
330376
push := func(s string) { mu.Lock(); logs = append(logs, s); mu.Unlock() }
331377

332-
clientSide := NewClientSideConnection(clientFuncs{
378+
clientSide := NewClientSideConnection(&clientFuncs{
333379
WriteTextFileFunc: func(context.Context, WriteTextFileRequest) error { return nil },
334380
ReadTextFileFunc: func(context.Context, ReadTextFileRequest) (ReadTextFileResponse, error) {
335381
return ReadTextFileResponse{Content: "test"}, nil
@@ -400,7 +446,7 @@ func TestConnectionHandlesInitialize(t *testing.T) {
400446
c2aR, c2aW := io.Pipe()
401447
a2cR, a2cW := io.Pipe()
402448

403-
agentConn := NewClientSideConnection(clientFuncs{
449+
agentConn := NewClientSideConnection(&clientFuncs{
404450
WriteTextFileFunc: func(context.Context, WriteTextFileRequest) error { return nil },
405451
ReadTextFileFunc: func(context.Context, ReadTextFileRequest) (ReadTextFileResponse, error) {
406452
return ReadTextFileResponse{Content: "test"}, nil
@@ -501,7 +547,7 @@ func TestPromptCancellationSendsCancelAndAllowsNewSession(t *testing.T) {
501547
}, a2cW, c2aR)
502548

503549
// Client side
504-
cs := NewClientSideConnection(clientFuncs{
550+
cs := NewClientSideConnection(&clientFuncs{
505551
WriteTextFileFunc: func(context.Context, WriteTextFileRequest) error { return nil },
506552
ReadTextFileFunc: func(context.Context, ReadTextFileRequest) (ReadTextFileResponse, error) {
507553
return ReadTextFileResponse{Content: ""}, nil

go/agent_gen.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/client_gen.go

Lines changed: 16 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/example/claude-code/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ func (c *replClient) WaitForTerminalExit(ctx context.Context, params acp.WaitFor
154154
return acp.WaitForTerminalExitResponse{}, nil
155155
}
156156

157+
// KillTerminalCommand implements acp.Client.
158+
func (c *replClient) KillTerminalCommand(ctx context.Context, params acp.KillTerminalCommandRequest) error {
159+
fmt.Printf("[Client] KillTerminalCommand: %v\n", params)
160+
return nil
161+
}
162+
157163
func main() {
158164
yolo := flag.Bool("yolo", false, "Auto-approve permission prompts")
159165
flag.Parse()

go/example/client/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ import (
1616

1717
type exampleClient struct{}
1818

19-
var (
20-
_ acp.Client = (*exampleClient)(nil)
21-
_ acp.ClientTerminal = (*exampleClient)(nil)
22-
)
19+
var _ acp.Client = (*exampleClient)(nil)
2320

2421
func (e *exampleClient) RequestPermission(ctx context.Context, params acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error) {
2522
title := ""
@@ -153,6 +150,12 @@ func (e *exampleClient) WaitForTerminalExit(ctx context.Context, params acp.Wait
153150
return acp.WaitForTerminalExitResponse{}, nil
154151
}
155152

153+
// KillTerminalCommand implements acp.Client.
154+
func (c *exampleClient) KillTerminalCommand(ctx context.Context, params acp.KillTerminalCommandRequest) error {
155+
fmt.Printf("[Client] KillTerminalCommand: %v\n", params)
156+
return nil
157+
}
158+
156159
func main() {
157160
// If args provided, treat them as agent program + args. Otherwise run the Go agent example.
158161
ctx, cancel := context.WithCancel(context.Background())

go/example/gemini/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ type replClient struct {
2121
autoApprove bool
2222
}
2323

24-
var (
25-
_ acp.Client = (*replClient)(nil)
26-
_ acp.ClientTerminal = (*replClient)(nil)
27-
)
24+
var _ acp.Client = (*replClient)(nil)
2825

2926
func (c *replClient) RequestPermission(ctx context.Context, params acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error) {
3027
if c.autoApprove {
@@ -157,6 +154,12 @@ func (c *replClient) WaitForTerminalExit(ctx context.Context, params acp.WaitFor
157154
return acp.WaitForTerminalExitResponse{}, nil
158155
}
159156

157+
// KillTerminalCommand implements acp.Client.
158+
func (c *replClient) KillTerminalCommand(ctx context.Context, params acp.KillTerminalCommandRequest) error {
159+
fmt.Printf("[Client] KillTerminalCommand: %v\n", params)
160+
return nil
161+
}
162+
160163
func main() {
161164
binary := flag.String("gemini", "gemini", "Path to the Gemini CLI binary")
162165
model := flag.String("model", "", "Model to pass to Gemini (optional)")

go/example_client_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,29 @@ func (clientExample) ReadTextFile(ctx context.Context, p ReadTextFileRequest) (R
8585
return ReadTextFileResponse{Content: content}, nil
8686
}
8787

88+
// Terminal interface implementations (minimal stubs for examples)
89+
func (clientExample) CreateTerminal(ctx context.Context, p CreateTerminalRequest) (CreateTerminalResponse, error) {
90+
// Return a dummy terminal id
91+
return CreateTerminalResponse{TerminalId: "t-1"}, nil
92+
}
93+
94+
func (clientExample) KillTerminalCommand(ctx context.Context, p KillTerminalCommandRequest) error {
95+
return nil
96+
}
97+
98+
func (clientExample) ReleaseTerminal(ctx context.Context, p ReleaseTerminalRequest) error {
99+
return nil
100+
}
101+
102+
func (clientExample) TerminalOutput(ctx context.Context, p TerminalOutputRequest) (TerminalOutputResponse, error) {
103+
// Provide non-empty output to satisfy validation
104+
return TerminalOutputResponse{Output: "ok", Truncated: false}, nil
105+
}
106+
107+
func (clientExample) WaitForTerminalExit(ctx context.Context, p WaitForTerminalExitRequest) (WaitForTerminalExitResponse, error) {
108+
return WaitForTerminalExitResponse{}, nil
109+
}
110+
88111
// Example_client launches the Go agent example, negotiates protocol,
89112
// opens a session, and sends a simple prompt.
90113
func Example_client() {

go/example_gemini_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ func (geminiClient) ReadTextFile(ctx context.Context, _ ReadTextFileRequest) (Re
3232
}
3333
func (geminiClient) WriteTextFile(ctx context.Context, _ WriteTextFileRequest) error { return nil }
3434

35+
// Terminal interface implementations (minimal stubs for examples)
36+
func (geminiClient) CreateTerminal(ctx context.Context, p CreateTerminalRequest) (CreateTerminalResponse, error) {
37+
return CreateTerminalResponse{TerminalId: "t-1"}, nil
38+
}
39+
40+
func (geminiClient) KillTerminalCommand(ctx context.Context, p KillTerminalCommandRequest) error {
41+
return nil
42+
}
43+
func (geminiClient) ReleaseTerminal(ctx context.Context, p ReleaseTerminalRequest) error { return nil }
44+
func (geminiClient) TerminalOutput(ctx context.Context, p TerminalOutputRequest) (TerminalOutputResponse, error) {
45+
return TerminalOutputResponse{Output: "ok", Truncated: false}, nil
46+
}
47+
48+
func (geminiClient) WaitForTerminalExit(ctx context.Context, p WaitForTerminalExitRequest) (WaitForTerminalExitResponse, error) {
49+
return WaitForTerminalExitResponse{}, nil
50+
}
51+
3552
// Example_gemini connects to a Gemini CLI speaking ACP over stdio,
3653
// then initializes, opens a session, and sends a prompt.
3754
func Example_gemini() {

0 commit comments

Comments
 (0)