Skip to content

Commit 295f69e

Browse files
agu-zbennetbo
andauthored
Add terminal/kill method (#53)
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
1 parent dbae247 commit 295f69e

9 files changed

Lines changed: 124 additions & 3 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ All paths in the protocol should be absolute
2121
- Add constants for the method names
2222
- Add variants to {Agent|Client}{Request|Response} enums
2323
- Add the methods to the Client/Agent impl of {Agent|Client}SideConnection in rust/acp.rs
24-
- Handle the method in the decoders
24+
- Handle the new method in the `Side::decode_request`/`Side::decode_notification` implementation
2525
- Handle the new request in the blanket impl of MessageHandler<{Agent|Client}Side>
2626
- Add the method to markdown_generator.rs SideDocs functions
2727
- Run `npm run generate` and fix any issues that appear

rust/acp.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ impl Side for ClientSide {
254254
.map(AgentRequest::TerminalOutputRequest)
255255
.map_err(Into::into),
256256
#[cfg(feature = "unstable")]
257+
TERMINAL_KILL_METHOD_NAME => serde_json::from_str(params.get())
258+
.map(AgentRequest::KillTerminalRequest)
259+
.map_err(Into::into),
260+
#[cfg(feature = "unstable")]
257261
TERMINAL_RELEASE_METHOD_NAME => serde_json::from_str(params.get())
258262
.map(AgentRequest::ReleaseTerminalRequest)
259263
.map_err(Into::into),
@@ -315,6 +319,11 @@ impl<T: Client> MessageHandler<ClientSide> for T {
315319
let response = self.wait_for_terminal_exit(args).await?;
316320
Ok(ClientResponse::WaitForTerminalExitResponse(response))
317321
}
322+
#[cfg(feature = "unstable")]
323+
AgentRequest::KillTerminalRequest(args) => {
324+
self.kill_terminal(args).await?;
325+
Ok(ClientResponse::KillTerminalResponse)
326+
}
318327
}
319328
}
320329

@@ -468,6 +477,16 @@ impl Client for AgentSideConnection {
468477
.await
469478
}
470479

480+
#[cfg(feature = "unstable")]
481+
async fn kill_terminal(&self, arguments: KillTerminalRequest) -> Result<(), Error> {
482+
self.conn
483+
.request(
484+
TERMINAL_KILL_METHOD_NAME,
485+
Some(AgentRequest::KillTerminalRequest(arguments)),
486+
)
487+
.await
488+
}
489+
471490
async fn session_notification(&self, notification: SessionNotification) -> Result<(), Error> {
472491
self.conn.notify(
473492
SESSION_UPDATE_NOTIFICATION,

rust/client.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ pub trait Client {
111111
&self,
112112
args: WaitForTerminalExitRequest,
113113
) -> impl Future<Output = Result<WaitForTerminalExitResponse, Error>>;
114+
115+
/// **UNSTABLE**
116+
///
117+
/// This method is not part of the spec, and may be removed or changed at any point.
118+
#[doc(hidden)]
119+
#[cfg(feature = "unstable")]
120+
fn kill_terminal(&self, args: KillTerminalRequest) -> impl Future<Output = Result<(), Error>>;
114121
}
115122

116123
// Session updates
@@ -353,6 +360,15 @@ pub struct ReleaseTerminalRequest {
353360
pub terminal_id: TerminalId,
354361
}
355362

363+
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
364+
#[schemars(extend("x-docs-ignore" = true))]
365+
#[serde(rename_all = "camelCase")]
366+
#[cfg(feature = "unstable")]
367+
pub struct KillTerminalRequest {
368+
pub session_id: SessionId,
369+
pub terminal_id: TerminalId,
370+
}
371+
356372
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
357373
#[schemars(extend("x-docs-ignore" = true))]
358374
#[serde(rename_all = "camelCase")]
@@ -445,6 +461,9 @@ pub struct ClientMethodNames {
445461
/// Method for waiting for a terminal to finish.
446462
#[cfg(feature = "unstable")]
447463
pub terminal_wait_for_exit: &'static str,
464+
/// Method for killing a terminal.
465+
#[cfg(feature = "unstable")]
466+
pub terminal_kill: &'static str,
448467
}
449468

450469
/// Constant containing all client method names.
@@ -461,6 +480,8 @@ pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
461480
terminal_release: TERMINAL_RELEASE_METHOD_NAME,
462481
#[cfg(feature = "unstable")]
463482
terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
483+
#[cfg(feature = "unstable")]
484+
terminal_kill: TERMINAL_KILL_METHOD_NAME,
464485
};
465486

466487
/// Notification name for session updates.
@@ -483,6 +504,9 @@ pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
483504
/// Method for waiting for a terminal to finish.
484505
#[cfg(feature = "unstable")]
485506
pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
507+
/// Method for killing a terminal.
508+
#[cfg(feature = "unstable")]
509+
pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
486510

487511
/// All possible requests that an agent can send to a client.
488512
///
@@ -505,6 +529,8 @@ pub enum AgentRequest {
505529
ReleaseTerminalRequest(ReleaseTerminalRequest),
506530
#[cfg(feature = "unstable")]
507531
WaitForTerminalExitRequest(WaitForTerminalExitRequest),
532+
#[cfg(feature = "unstable")]
533+
KillTerminalRequest(KillTerminalRequest),
508534
}
509535

510536
/// All possible responses that a client can send to an agent.
@@ -528,6 +554,8 @@ pub enum ClientResponse {
528554
ReleaseTerminalResponse,
529555
#[cfg(feature = "unstable")]
530556
WaitForTerminalExitResponse(WaitForTerminalExitResponse),
557+
#[cfg(feature = "unstable")]
558+
KillTerminalResponse,
531559
}
532560

533561
/// All possible notifications that an agent can send to a client.

rust/example_client.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ impl acp::Client for ExampleClient {
7272
Err(acp::Error::method_not_found())
7373
}
7474

75+
#[cfg(feature = "unstable")]
76+
async fn kill_terminal(
77+
&self,
78+
_args: acp::KillTerminalRequest,
79+
) -> anyhow::Result<(), acp::Error> {
80+
Err(acp::Error::method_not_found())
81+
}
82+
7583
async fn session_notification(
7684
&self,
7785
args: acp::SessionNotification,

rust/markdown_generator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ impl SideDocs {
648648
"terminal/output" => self.client_methods.get("terminal_output").unwrap(),
649649
"terminal/release" => self.client_methods.get("release_terminal").unwrap(),
650650
"terminal/wait_for_exit" => self.client_methods.get("wait_for_terminal_exit").unwrap(),
651+
"terminal/kill" => self.client_methods.get("kill_terminal").unwrap(),
651652
_ => panic!("Introduced a method? Add it here :)"),
652653
}
653654
}

schema/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"session_request_permission": "session/request_permission",
1414
"session_update": "session/update",
1515
"terminal_create": "terminal/create",
16+
"terminal_kill": "terminal/kill",
1617
"terminal_output": "terminal/output",
1718
"terminal_release": "terminal/release",
1819
"terminal_wait_for_exit": "terminal/wait_for_exit"

schema/schema.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
{
6060
"$ref": "#/$defs/WaitForTerminalExitRequest",
6161
"title": "WaitForTerminalExitRequest"
62+
},
63+
{
64+
"$ref": "#/$defs/KillTerminalRequest",
65+
"title": "KillTerminalRequest"
6266
}
6367
],
6468
"description": "All possible requests that an agent can send to a client.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly - instead, use the methods on the [`Client`] trait.\n\nThis enum encompasses all method calls from agent to client.",
@@ -281,6 +285,10 @@
281285
{
282286
"$ref": "#/$defs/WaitForTerminalExitResponse",
283287
"title": "WaitForTerminalExitResponse"
288+
},
289+
{
290+
"title": "KillTerminalResponse",
291+
"type": "null"
284292
}
285293
],
286294
"description": "All possible responses that a client can send to an agent.\n\nThis enum is used internally for routing RPC responses. You typically won't need\nto use this directly - the responses are handled automatically by the connection.\n\nThese are responses to the corresponding AgentRequest variants.",
@@ -626,6 +634,19 @@
626634
"x-method": "initialize",
627635
"x-side": "agent"
628636
},
637+
"KillTerminalRequest": {
638+
"properties": {
639+
"sessionId": {
640+
"$ref": "#/$defs/SessionId"
641+
},
642+
"terminalId": {
643+
"type": "string"
644+
}
645+
},
646+
"required": ["sessionId", "terminalId"],
647+
"type": "object",
648+
"x-docs-ignore": true
649+
},
629650
"LoadSessionRequest": {
630651
"description": "Request parameters for loading an existing session.\n\nOnly available if the agent supports the `loadSession` capability.\n\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)",
631652
"properties": {

typescript/acp.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,16 @@ export class TerminalHandle {
210210
);
211211
}
212212

213+
async kill(): Promise<void> {
214+
return await this.#connection.sendRequest(
215+
schema.CLIENT_METHODS.terminal_kill,
216+
{
217+
sessionId: this.#sessionId,
218+
terminalId: this.id,
219+
},
220+
);
221+
}
222+
213223
async release(): Promise<void> {
214224
await this.#connection.sendRequest(schema.CLIENT_METHODS.terminal_release, {
215225
sessionId: this.#sessionId,
@@ -315,6 +325,13 @@ export class ClientSideConnection implements Agent {
315325
validatedParams as schema.WaitForTerminalExitRequest,
316326
);
317327
}
328+
case schema.CLIENT_METHODS.terminal_kill: {
329+
const validatedParams =
330+
schema.killTerminalRequestSchema.parse(params);
331+
return client.killTerminal?.(
332+
validatedParams as schema.KillTerminalRequest,
333+
);
334+
}
318335
default:
319336
throw RequestError.methodNotFound(method);
320337
}
@@ -837,6 +854,13 @@ export interface Client {
837854
waitForTerminalExit?(
838855
params: schema.WaitForTerminalExitRequest,
839856
): Promise<schema.WaitForTerminalExitResponse>;
857+
858+
/**
859+
* @internal **UNSTABLE**
860+
*
861+
* This method is not part of the spec, and may be removed or changed at any point.
862+
*/
863+
killTerminal?(params: schema.KillTerminalRequest): Promise<void>;
840864
}
841865

842866
/**

typescript/schema.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const CLIENT_METHODS = {
1313
session_request_permission: "session/request_permission",
1414
session_update: "session/update",
1515
terminal_create: "terminal/create",
16+
terminal_kill: "terminal/kill",
1617
terminal_output: "terminal/output",
1718
terminal_release: "terminal/release",
1819
terminal_wait_for_exit: "terminal/wait_for_exit",
@@ -45,7 +46,8 @@ export type ClientRequest =
4546
| CreateTerminalRequest
4647
| TerminalOutputRequest
4748
| ReleaseTerminalRequest
48-
| WaitForTerminalExitRequest;
49+
| WaitForTerminalExitRequest
50+
| KillTerminalRequest;
4951
/**
5052
* Content produced by a tool call.
5153
*
@@ -197,9 +199,11 @@ export type ClientResponse =
197199
| CreateTerminalResponse
198200
| TerminalOutputResponse
199201
| ReleaseTerminalResponse
200-
| WaitForTerminalExitResponse;
202+
| WaitForTerminalExitResponse
203+
| KillTerminalResponse;
201204
export type WriteTextFileResponse = null;
202205
export type ReleaseTerminalResponse = null;
206+
export type KillTerminalResponse = null;
203207
/**
204208
* All possible notifications that a client can send to an agent.
205209
*
@@ -496,6 +500,10 @@ export interface WaitForTerminalExitRequest {
496500
sessionId: SessionId;
497501
terminalId: string;
498502
}
503+
export interface KillTerminalRequest {
504+
sessionId: SessionId;
505+
terminalId: string;
506+
}
499507
/**
500508
* Response containing the contents of a text file.
501509
*/
@@ -1084,6 +1092,9 @@ export const waitForTerminalExitResponseSchema = z.object({
10841092
signal: z.string().optional().nullable(),
10851093
});
10861094

1095+
/** @internal */
1096+
export const killTerminalResponseSchema = z.null();
1097+
10871098
/** @internal */
10881099
export const cancelNotificationSchema = z.object({
10891100
sessionId: z.string(),
@@ -1223,6 +1234,12 @@ export const waitForTerminalExitRequestSchema = z.object({
12231234
terminalId: z.string(),
12241235
});
12251236

1237+
/** @internal */
1238+
export const killTerminalRequestSchema = z.object({
1239+
sessionId: sessionIdSchema,
1240+
terminalId: z.string(),
1241+
});
1242+
12261243
/** @internal */
12271244
export const terminalExitStatusSchema = z.object({
12281245
exitCode: z.number().optional().nullable(),
@@ -1441,6 +1458,7 @@ export const clientResponseSchema = z.union([
14411458
terminalOutputResponseSchema,
14421459
releaseTerminalResponseSchema,
14431460
waitForTerminalExitResponseSchema,
1461+
killTerminalResponseSchema,
14441462
]);
14451463

14461464
/** @internal */
@@ -1475,6 +1493,7 @@ export const clientRequestSchema = z.union([
14751493
terminalOutputRequestSchema,
14761494
releaseTerminalRequestSchema,
14771495
waitForTerminalExitRequestSchema,
1496+
killTerminalRequestSchema,
14781497
]);
14791498

14801499
/** @internal */

0 commit comments

Comments
 (0)