Skip to content
Source
Sign inSign up

rpc.ts

415 lines12.9 KB

1import * as AcpCompat from "./compat.ts";
2import * as Rpc from "effect/rpc/Rpc";
3import * as RpcGroup from "effect/rpc/RpcGroup";
4import * as Schema from "effect/Schema";
5​
6import * as AcpSchema from "./_generated/schema.gen.ts";
7import * as AcpSchemaV1 from "./_generated/schema-v1.gen.ts";
8import { AGENT_METHODS, CLIENT_METHODS } from "./_generated/meta.gen.ts";
9​
10export const V1_AGENT_METHODS = {
11 authenticate: "authenticate",
12 logout: "logout",
13 session_load: "session/load",
14 session_set_model: "session/set_model",
15 session_set_mode: "session/set_mode",
16} as const;
17​
18export const V1_CLIENT_METHODS = {
19 session_elicitation: "session/elicitation",
20 unstable_session_elicitation: "_session/elicitation",
21 session_elicitation_complete: "session/elicitation/complete",
22 fs_read_text_file: "fs/read_text_file",
23 fs_write_text_file: "fs/write_text_file",
24 terminal_create: "terminal/create",
25 terminal_output: "terminal/output",
26 terminal_release: "terminal/release",
27 terminal_wait_for_exit: "terminal/wait_for_exit",
28 terminal_kill: "terminal/kill",
29} as const;
30​
31const InitializeRpc = Rpc.make(AGENT_METHODS.initialize, {
32 payload: AcpSchema.InitializeRequest,
33 success: AcpSchema.InitializeResponse,
34 error: AcpSchema.Error,
35});
36​
37const LoginRpc = Rpc.make(AGENT_METHODS.auth_login, {
38 payload: AcpSchema.LoginAuthRequest,
39 success: AcpSchema.LoginAuthResponse,
40 error: AcpSchema.Error,
41});
42​
43const LogoutRpc = Rpc.make(AGENT_METHODS.auth_logout, {
44 payload: AcpSchema.LogoutAuthRequest,
45 success: AcpSchema.LogoutAuthResponse,
46 error: AcpSchema.Error,
47});
48​
49const NewSessionRpc = Rpc.make(AGENT_METHODS.session_new, {
50 payload: AcpSchema.NewSessionRequest,
51 success: AcpSchema.NewSessionResponse,
52 error: AcpSchema.Error,
53});
54​
55const ListSessionsRpc = Rpc.make(AGENT_METHODS.session_list, {
56 payload: AcpSchema.ListSessionsRequest,
57 success: AcpSchema.ListSessionsResponse,
58 error: AcpSchema.Error,
59});
60​
61const ForkSessionRpc = Rpc.make(AGENT_METHODS.session_fork, {
62 payload: AcpSchema.ForkSessionRequest,
63 success: AcpSchema.ForkSessionResponse,
64 error: AcpSchema.Error,
65});
66​
67const ResumeSessionRpc = Rpc.make(AGENT_METHODS.session_resume, {
68 payload: AcpSchema.ResumeSessionRequest,
69 success: AcpSchema.ResumeSessionResponse,
70 error: AcpSchema.Error,
71});
72​
73const CloseSessionRpc = Rpc.make(AGENT_METHODS.session_close, {
74 payload: AcpSchema.CloseSessionRequest,
75 success: AcpSchema.CloseSessionResponse,
76 error: AcpSchema.Error,
77});
78​
79const DeleteSessionRpc = Rpc.make(AGENT_METHODS.session_delete, {
80 payload: AcpSchema.DeleteSessionRequest,
81 success: AcpSchema.DeleteSessionResponse,
82 error: AcpSchema.Error,
83});
84​
85const ListProvidersRpc = Rpc.make(AGENT_METHODS.providers_list, {
86 payload: AcpSchema.ListProvidersRequest,
87 success: AcpSchema.ListProvidersResponse,
88 error: AcpSchema.Error,
89});
90​
91const SetProviderRpc = Rpc.make(AGENT_METHODS.providers_set, {
92 payload: AcpSchema.SetProviderRequest,
93 success: AcpSchema.SetProviderResponse,
94 error: AcpSchema.Error,
95});
96​
97const DisableProviderRpc = Rpc.make(AGENT_METHODS.providers_disable, {
98 payload: AcpSchema.DisableProviderRequest,
99 success: AcpSchema.DisableProviderResponse,
100 error: AcpSchema.Error,
101});
102​
103const PromptRpc = Rpc.make(AGENT_METHODS.session_prompt, {
104 payload: AcpSchema.PromptRequest,
105 success: AcpSchema.PromptResponse,
106 error: AcpSchema.Error,
107});
108​
109const SetSessionConfigOptionRpc = Rpc.make(AGENT_METHODS.session_set_config_option, {
110 payload: AcpSchema.SetSessionConfigOptionRequest,
111 success: AcpSchema.SetSessionConfigOptionResponse,
112 error: AcpSchema.Error,
113});
114​
115const RequestPermissionRpc = Rpc.make(CLIENT_METHODS.session_request_permission, {
116 payload: AcpSchema.RequestPermissionRequest,
117 success: AcpSchema.RequestPermissionResponse,
118 error: AcpSchema.Error,
119});
120​
121const ElicitationRpc = Rpc.make(CLIENT_METHODS.elicitation_create, {
122 payload: AcpSchema.CreateElicitationRequest,
123 success: AcpSchema.CreateElicitationResponse,
124 error: AcpSchema.Error,
125});
126​
127export const AgentRpcs = RpcGroup.make(
128 InitializeRpc,
129 LoginRpc,
130 LogoutRpc,
131 NewSessionRpc,
132 ListSessionsRpc,
133 ForkSessionRpc,
134 ResumeSessionRpc,
135 CloseSessionRpc,
136 DeleteSessionRpc,
137 ListProvidersRpc,
138 SetProviderRpc,
139 DisableProviderRpc,
140 PromptRpc,
141 SetSessionConfigOptionRpc,
142);
143​
144const CompatInitializeRpc = Rpc.make(AGENT_METHODS.initialize, {
145 // The negotiation request intentionally carries both v1 and v2 capability
146 // field names. A union encoder would select one branch and discard the
147 // other generation's fields before they reach the agent.
148 payload: Schema.Unknown,
149 success: Schema.Union([AcpSchema.InitializeResponse, AcpSchemaV1.InitializeResponse]),
150 error: AcpSchema.Error,
151});
152​
153const CompatAuthenticateV1Rpc = Rpc.make(V1_AGENT_METHODS.authenticate, {
154 payload: AcpSchemaV1.AuthenticateRequest,
155 success: AcpSchemaV1.AuthenticateResponse,
156 error: AcpSchemaV1.Error,
157});
158​
159const CompatLogoutV1Rpc = Rpc.make(V1_AGENT_METHODS.logout, {
160 payload: AcpSchemaV1.LogoutRequest,
161 success: AcpSchemaV1.LogoutResponse,
162 error: AcpSchemaV1.Error,
163});
164​
165const CompatNewSessionRpc = Rpc.make(AGENT_METHODS.session_new, {
166 payload: Schema.Union([AcpSchema.NewSessionRequest, AcpSchemaV1.NewSessionRequest]),
167 success: Schema.Union([
168 Schema.Struct({
169 ...AcpSchemaV1.NewSessionResponse.fields,
170 models: Schema.optionalKey(Schema.NullOr(AcpCompat.SessionModelState)),
171 }),
172 AcpSchema.NewSessionResponse,
173 ]),
174 error: AcpSchema.Error,
175});
176​
177const CompatLoadSessionV1Rpc = Rpc.make(V1_AGENT_METHODS.session_load, {
178 payload: AcpSchemaV1.LoadSessionRequest,
179 success: Schema.Struct({
180 ...AcpSchemaV1.LoadSessionResponse.fields,
181 models: Schema.optionalKey(Schema.NullOr(AcpCompat.SessionModelState)),
182 }),
183 error: AcpSchemaV1.Error,
184});
185​
186const CompatListSessionsRpc = Rpc.make(AGENT_METHODS.session_list, {
187 payload: Schema.Union([AcpSchema.ListSessionsRequest, AcpSchemaV1.ListSessionsRequest]),
188 success: Schema.Union([AcpSchemaV1.ListSessionsResponse, AcpSchema.ListSessionsResponse]),
189 error: AcpSchema.Error,
190});
191​
192const CompatForkSessionRpc = Rpc.make(AGENT_METHODS.session_fork, {
193 payload: Schema.Union([AcpSchema.ForkSessionRequest, AcpSchemaV1.ForkSessionRequest]),
194 success: Schema.Union([
195 Schema.Struct({
196 ...AcpSchemaV1.ForkSessionResponse.fields,
197 models: Schema.optionalKey(Schema.NullOr(AcpCompat.SessionModelState)),
198 }),
199 AcpSchema.ForkSessionResponse,
200 ]),
201 error: AcpSchema.Error,
202});
203​
204const CompatResumeSessionRpc = Rpc.make(AGENT_METHODS.session_resume, {
205 payload: Schema.Union([AcpSchema.ResumeSessionRequest, AcpSchemaV1.ResumeSessionRequest]),
206 success: Schema.Union([
207 Schema.Struct({
208 ...AcpSchemaV1.ResumeSessionResponse.fields,
209 models: Schema.optionalKey(Schema.NullOr(AcpCompat.SessionModelState)),
210 }),
211 AcpSchema.ResumeSessionResponse,
212 ]),
213 error: AcpSchema.Error,
214});
215​
216const CompatCloseSessionRpc = Rpc.make(AGENT_METHODS.session_close, {
217 payload: Schema.Union([AcpSchema.CloseSessionRequest, AcpSchemaV1.CloseSessionRequest]),
218 success: Schema.Union([AcpSchema.CloseSessionResponse, AcpSchemaV1.CloseSessionResponse]),
219 error: AcpSchema.Error,
220});
221​
222const CompatDeleteSessionRpc = Rpc.make(AGENT_METHODS.session_delete, {
223 payload: AcpSchema.DeleteSessionRequest,
224 success: AcpSchema.DeleteSessionResponse,
225 error: AcpSchema.Error,
226});
227​
228const CompatListProvidersRpc = Rpc.make(AGENT_METHODS.providers_list, {
229 payload: AcpSchema.ListProvidersRequest,
230 success: AcpSchema.ListProvidersResponse,
231 error: AcpSchema.Error,
232});
233​
234const CompatSetProviderRpc = Rpc.make(AGENT_METHODS.providers_set, {
235 payload: AcpSchema.SetProviderRequest,
236 success: AcpSchema.SetProviderResponse,
237 error: AcpSchema.Error,
238});
239​
240const CompatDisableProviderRpc = Rpc.make(AGENT_METHODS.providers_disable, {
241 payload: AcpSchema.DisableProviderRequest,
242 success: AcpSchema.DisableProviderResponse,
243 error: AcpSchema.Error,
244});
245​
246const CompatPromptRpc = Rpc.make(AGENT_METHODS.session_prompt, {
247 payload: Schema.Union([AcpSchema.PromptRequest, AcpSchemaV1.PromptRequest]),
248 success: Schema.Union([
249 AcpSchemaV1.PromptResponse,
250 // fx sends empty usage on cancellation; retain its stop reason when usage is invalid.
251 Schema.Struct({ stopReason: AcpSchemaV1.StopReason }),
252 AcpSchema.PromptResponse,
253 ]),
254 error: AcpSchema.Error,
255});
256​
257const CompatSetSessionConfigOptionRpc = Rpc.make(AGENT_METHODS.session_set_config_option, {
258 payload: Schema.Union([
259 AcpSchema.SetSessionConfigOptionRequest,
260 AcpSchemaV1.SetSessionConfigOptionRequest,
261 ]),
262 success: Schema.Union([
263 AcpSchemaV1.SetSessionConfigOptionResponse,
264 AcpSchema.SetSessionConfigOptionResponse,
265 ]),
266 error: AcpSchema.Error,
267});
268​
269const CompatSetSessionModelRpc = Rpc.make(V1_AGENT_METHODS.session_set_model, {
270 payload: AcpCompat.SetSessionModelRequest,
271 success: AcpCompat.SetSessionModelResponse,
272 error: AcpSchemaV1.Error,
273});
274​
275const CompatSetSessionModeRpc = Rpc.make(V1_AGENT_METHODS.session_set_mode, {
276 payload: AcpSchemaV1.SetSessionModeRequest,
277 success: AcpSchemaV1.SetSessionModeResponse,
278 error: AcpSchemaV1.Error,
279});
280​
281export const CompatAgentRpcs = RpcGroup.make(
282 CompatInitializeRpc,
283 CompatSetSessionModelRpc,
284 CompatSetSessionModeRpc,
285 LoginRpc,
286 CompatAuthenticateV1Rpc,
287 LogoutRpc,
288 CompatLogoutV1Rpc,
289 CompatNewSessionRpc,
290 CompatLoadSessionV1Rpc,
291 CompatListSessionsRpc,
292 CompatForkSessionRpc,
293 CompatResumeSessionRpc,
294 CompatCloseSessionRpc,
295 CompatDeleteSessionRpc,
296 CompatListProvidersRpc,
297 CompatSetProviderRpc,
298 CompatDisableProviderRpc,
299 CompatPromptRpc,
300 CompatSetSessionConfigOptionRpc,
301);
302​
303const CompatRequestPermissionRpc = Rpc.make(CLIENT_METHODS.session_request_permission, {
304 payload: Schema.Union([AcpSchema.RequestPermissionRequest, AcpSchemaV1.RequestPermissionRequest]),
305 success: Schema.Union([
306 AcpSchema.RequestPermissionResponse,
307 AcpSchemaV1.RequestPermissionResponse,
308 ]),
309 error: AcpSchema.Error,
310});
311​
312const CompatElicitationRpc = Rpc.make(CLIENT_METHODS.elicitation_create, {
313 payload: Schema.Unknown,
314 success: Schema.Union([
315 AcpSchema.CreateElicitationResponse,
316 AcpSchemaV1.CreateElicitationResponse,
317 ]),
318 error: AcpSchema.Error,
319});
320​
321// Native ACP agents still use the older nested elicitation response.
322const legacyElicitationRpc = <const Method extends string>(method: Method) =>
323 Rpc.make(method, {
324 payload: AcpSchema.CreateElicitationRequest,
325 success: Schema.Struct({
326 action: AcpSchema.CreateElicitationResponse,
327 _meta: Schema.optionalKey(Schema.NullOr(Schema.Record(Schema.String, Schema.Json))),
328 }),
329 error: AcpSchema.Error,
330 });
331​
332const ConnectMcpRpc = Rpc.make(CLIENT_METHODS.mcp_connect, {
333 payload: AcpSchema.ConnectMcpRequest,
334 success: AcpSchema.ConnectMcpResponse,
335 error: AcpSchema.Error,
336});
337​
338const MessageMcpRpc = Rpc.make(CLIENT_METHODS.mcp_message, {
339 payload: AcpSchema.MessageMcpRequest,
340 success: AcpSchema.MessageMcpResponse,
341 error: AcpSchema.Error,
342});
343​
344const DisconnectMcpRpc = Rpc.make(CLIENT_METHODS.mcp_disconnect, {
345 payload: AcpSchema.DisconnectMcpRequest,
346 success: AcpSchema.DisconnectMcpResponse,
347 error: AcpSchema.Error,
348});
349​
350export const ClientRpcs = RpcGroup.make(
351 RequestPermissionRpc,
352 ElicitationRpc,
353 ConnectMcpRpc,
354 MessageMcpRpc,
355 DisconnectMcpRpc,
356);
357​
358const ReadTextFileV1Rpc = Rpc.make(V1_CLIENT_METHODS.fs_read_text_file, {
359 payload: AcpSchemaV1.ReadTextFileRequest,
360 success: AcpSchemaV1.ReadTextFileResponse,
361 error: AcpSchemaV1.Error,
362});
363​
364const WriteTextFileV1Rpc = Rpc.make(V1_CLIENT_METHODS.fs_write_text_file, {
365 payload: AcpSchemaV1.WriteTextFileRequest,
366 success: AcpSchemaV1.WriteTextFileResponse,
367 error: AcpSchemaV1.Error,
368});
369​
370const CreateTerminalV1Rpc = Rpc.make(V1_CLIENT_METHODS.terminal_create, {
371 payload: AcpSchemaV1.CreateTerminalRequest,
372 success: AcpSchemaV1.CreateTerminalResponse,
373 error: AcpSchemaV1.Error,
374});
375​
376const TerminalOutputV1Rpc = Rpc.make(V1_CLIENT_METHODS.terminal_output, {
377 payload: AcpSchemaV1.TerminalOutputRequest,
378 success: AcpSchemaV1.TerminalOutputResponse,
379 error: AcpSchemaV1.Error,
380});
381​
382const ReleaseTerminalV1Rpc = Rpc.make(V1_CLIENT_METHODS.terminal_release, {
383 payload: AcpSchemaV1.ReleaseTerminalRequest,
384 success: AcpSchemaV1.ReleaseTerminalResponse,
385 error: AcpSchemaV1.Error,
386});
387​
388const WaitForTerminalExitV1Rpc = Rpc.make(V1_CLIENT_METHODS.terminal_wait_for_exit, {
389 payload: AcpSchemaV1.WaitForTerminalExitRequest,
390 success: AcpSchemaV1.WaitForTerminalExitResponse,
391 error: AcpSchemaV1.Error,
392});
393​
394const KillTerminalV1Rpc = Rpc.make(V1_CLIENT_METHODS.terminal_kill, {
395 payload: AcpSchemaV1.KillTerminalRequest,
396 success: AcpSchemaV1.KillTerminalResponse,
397 error: AcpSchemaV1.Error,
398});
399​
400export const CompatClientRpcs = RpcGroup.make(
401 CompatRequestPermissionRpc,
402 CompatElicitationRpc,
403 legacyElicitationRpc(V1_CLIENT_METHODS.session_elicitation),
404 legacyElicitationRpc(V1_CLIENT_METHODS.unstable_session_elicitation),
405 ConnectMcpRpc,
406 MessageMcpRpc,
407 DisconnectMcpRpc,
408 ReadTextFileV1Rpc,
409 WriteTextFileV1Rpc,
410 CreateTerminalV1Rpc,
411 TerminalOutputV1Rpc,
412 ReleaseTerminalV1Rpc,
413 WaitForTerminalExitV1Rpc,
414 KillTerminalV1Rpc,
415);