acp-sdk 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/README.md +141 -69
  4. data/lib/acp/agent_connection/client.rb +2 -3
  5. data/lib/acp/agent_connection/optional_route.rb +45 -0
  6. data/lib/acp/agent_connection.rb +120 -76
  7. data/lib/acp/agent_process.rb +4 -4
  8. data/lib/acp/client_connection/elicitations.rb +44 -0
  9. data/lib/acp/client_connection/inbound/route.rb +29 -0
  10. data/lib/acp/client_connection/inbound.rb +232 -0
  11. data/lib/acp/client_connection/streams.rb +20 -52
  12. data/lib/acp/client_connection.rb +34 -309
  13. data/lib/acp/extensions.rb +6 -0
  14. data/lib/acp/protocol.rb +14 -4
  15. data/lib/acp/transport/reply.rb +2 -2
  16. data/lib/acp/transport/stdio.rb +2 -2
  17. data/lib/acp/types/parse_error.rb +1 -1
  18. data/lib/acp/types.rb +13 -0
  19. data/lib/acp/version.rb +1 -1
  20. data/sig/generated/acp/agent_connection/optional_route.rbs +35 -0
  21. data/sig/generated/acp/agent_connection.rbs +5 -21
  22. data/sig/generated/acp/client_connection/elicitations.rbs +29 -0
  23. data/sig/generated/acp/client_connection/inbound/route.rbs +26 -0
  24. data/sig/generated/acp/client_connection/inbound.rbs +90 -0
  25. data/sig/generated/acp/client_connection/streams.rbs +7 -28
  26. data/sig/generated/acp/client_connection.rbs +12 -136
  27. data/sig/generated/acp/extensions.rbs +4 -0
  28. data/sig/generated/acp/protocol.rbs +8 -0
  29. data/sig/generated/acp/transport/reply.rbs +3 -3
  30. data/sig/generated/acp/transport/stdio.rbs +4 -4
  31. data/sig/generated/acp/types.rbs +9 -0
  32. data/sig/manual/acp/agent_connection.rbs +5 -57
  33. data/sig/manual/acp/client_connection.rbs +27 -0
  34. data/sig/manual/acp/transport/stdio.rbs +1 -5
  35. metadata +9 -5
  36. data/lib/acp/agent_connection/optional_method/spec.rb +0 -42
  37. data/lib/acp/agent_connection/optional_method.rb +0 -40
  38. data/sig/generated/acp/agent_connection/optional_method/spec.rbs +0 -32
  39. data/sig/generated/acp/agent_connection/optional_method.rbs +0 -7
@@ -0,0 +1,35 @@
1
+ # Generated from lib/acp/agent_connection/optional_route.rb with RBS::Inline
2
+
3
+ class ACP::AgentConnection::OptionalRoute
4
+ # @dynamic rpc_method
5
+ attr_reader rpc_method: String
6
+
7
+ # @dynamic type
8
+ attr_reader type: ACP::Transport::_Parser
9
+
10
+ # @dynamic agent_method
11
+ attr_reader agent_method: Symbol
12
+
13
+ # @dynamic path
14
+ attr_reader path: Array[Symbol]?
15
+
16
+ # @dynamic handle
17
+ attr_reader handle: ^(ACP::AgentConnection::_FullAgent, untyped) -> (ACP::Transport::_Response | ACP::RequestError)
18
+
19
+ # @rbs rpc_method: String
20
+ # @rbs type: ACP::Transport::_Parser
21
+ # @rbs agent_method: Symbol
22
+ # @rbs path: Array[Symbol]?
23
+ # @rbs &handle: (ACP::AgentConnection::_FullAgent, untyped) -> (ACP::Transport::_Response | ACP::RequestError)
24
+ # @rbs return: void
25
+ def initialize: (rpc_method: String, type: ACP::Transport::_Parser, agent_method: Symbol, path: Array[Symbol]?) { (ACP::AgentConnection::_FullAgent, untyped) -> (ACP::Transport::_Response | ACP::RequestError) } -> void
26
+
27
+ # @rbs initialize_response: ACP::Types::InitializeResponse
28
+ # @rbs return: bool
29
+ def advertised?: (ACP::Types::InitializeResponse initialize_response) -> bool
30
+
31
+ # @rbs initialize_response: ACP::Types::InitializeResponse
32
+ # @rbs agent: ACP::AgentConnection::_Agent
33
+ # @rbs return: bool
34
+ def routed?: (ACP::Types::InitializeResponse initialize_response, ACP::AgentConnection::_Agent agent) -> bool
35
+ end
@@ -17,10 +17,7 @@ class ACP::AgentConnection
17
17
 
18
18
  @transport: ACP::Transport::Stdio
19
19
 
20
- # The schema has no initialize capability for modes or config options: an
21
- # agent offers them per session, in its session responses, so they are
22
- # routed whenever the agent defines them.
23
- PER_SESSION: Hash[String, Symbol]
20
+ OPTIONAL_ROUTES: Array[ACP::AgentConnection::OptionalRoute]
24
21
 
25
22
  # @rbs transport: ACP::Transport::Stdio
26
23
  # @rbs capabilities: ACP::Types::AgentCapabilities
@@ -40,23 +37,12 @@ class ACP::AgentConnection
40
37
 
41
38
  # @rbs agent: ACP::AgentConnection::_Agent
42
39
  # @rbs client: ACP::AgentConnection::Client
40
+ # @rbs optional: Array[ACP::AgentConnection::OptionalRoute]
43
41
  # @rbs return: Hash[String, ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)]
44
- def requests: (ACP::AgentConnection::_Agent agent, ACP::AgentConnection::Client client) -> Hash[String, ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)]
42
+ def requests: (ACP::AgentConnection::_Agent agent, ACP::AgentConnection::Client client, Array[ACP::AgentConnection::OptionalRoute] optional) -> Hash[String, ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)]
45
43
 
46
- # The unstable request types are referenced while the hash is built, so
47
- # without the guard start would raise NameError even for an agent that never
48
- # advertises fork or providers.
49
- #
50
- # @rbs full: ACP::AgentConnection::_FullAgent
51
- # @rbs return: Hash[String, ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)]
52
- def unstable_requests: (ACP::AgentConnection::_FullAgent full) -> Hash[String, ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)]
53
-
54
- # The unstable specs pair with the unstable request routes, which reference
55
- # the unstable request classes, so both are only probed after the caller
56
- # opted in with `require 'acp/types/unstable'`.
57
- #
58
- # @rbs return: Array[ACP::AgentConnection::OptionalMethod::Spec]
59
- def optional_methods: () -> Array[ACP::AgentConnection::OptionalMethod::Spec]
44
+ # @rbs return: Array[ACP::AgentConnection::OptionalRoute]
45
+ def unstable_routes: () -> Array[ACP::AgentConnection::OptionalRoute]
60
46
 
61
47
  # @rbs agent: ACP::AgentConnection::_Agent
62
48
  # @rbs return: Hash[String, ^(untyped) -> void]
@@ -79,8 +65,6 @@ class ACP::AgentConnection
79
65
  # @rbs return: void
80
66
  def mcp_message_notification: (ACP::AgentConnection::_Agent agent, untyped params) -> void
81
67
 
82
- # Generated from_h raises on a missing key or a value of the wrong shape.
83
- #
84
68
  # @rbs type: ACP::Transport::_Parser
85
69
  # @rbs &handle: (untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
86
70
  # @rbs return: ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
@@ -0,0 +1,29 @@
1
+ # Generated from lib/acp/client_connection/elicitations.rb with RBS::Inline
2
+
3
+ class ACP::ClientConnection::Elicitations
4
+ @handler: ACP::ClientConnection::_Elicitation?
5
+
6
+ @logger: ACP::Transport::_Logger
7
+
8
+ @lock: Thread::Mutex
9
+
10
+ @outstanding: Hash[String, bool]
11
+
12
+ # @rbs handler: ACP::ClientConnection::_Elicitation?
13
+ # @rbs logger: ACP::Transport::_Logger
14
+ # @rbs return: void
15
+ def initialize: (handler: ACP::ClientConnection::_Elicitation?, logger: ACP::Transport::_Logger) -> void
16
+
17
+ # @rbs elicitation_id: String
18
+ # @rbs return: void
19
+ def register: (String elicitation_id) -> void
20
+
21
+ # The spec requires a completion for an unknown or already-completed
22
+ # elicitation id to be ignored, so only an id registered by a served
23
+ # url-mode request reaches the handler. It runs on the transport's reader
24
+ # thread, so it must return quickly.
25
+ #
26
+ # @rbs params: untyped
27
+ # @rbs return: void
28
+ def complete: (untyped params) -> void
29
+ end
@@ -0,0 +1,26 @@
1
+ # Generated from lib/acp/client_connection/inbound/route.rb with RBS::Inline
2
+
3
+ class ACP::ClientConnection::Inbound::Route
4
+ # @dynamic rpc_method
5
+ attr_reader rpc_method: String
6
+
7
+ # @dynamic type
8
+ attr_reader type: ACP::Transport::_Parser
9
+
10
+ # @dynamic handler_method
11
+ attr_reader handler_method: Symbol
12
+
13
+ # @dynamic path
14
+ attr_reader path: Array[Symbol]
15
+
16
+ # @dynamic capability
17
+ attr_reader capability: String
18
+
19
+ # @rbs rpc_method: String
20
+ # @rbs type: ACP::Transport::_Parser
21
+ # @rbs handler_method: Symbol
22
+ # @rbs path: Array[Symbol]
23
+ # @rbs capability: String
24
+ # @rbs return: void
25
+ def initialize: (rpc_method: String, type: ACP::Transport::_Parser, handler_method: Symbol, path: Array[Symbol], capability: String) -> void
26
+ end
@@ -0,0 +1,90 @@
1
+ # Generated from lib/acp/client_connection/inbound.rb with RBS::Inline
2
+
3
+ class ACP::ClientConnection::Inbound
4
+ @capabilities: ACP::Types::ClientCapabilities?
5
+
6
+ @extension_notifications: Hash[String, ^(untyped) -> void]
7
+
8
+ @extension_requests: Hash[String, ^(untyped) -> untyped]
9
+
10
+ @mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
11
+
12
+ @elicitations: ACP::ClientConnection::Elicitations
13
+
14
+ @elicitation: ACP::ClientConnection::_Elicitation?
15
+
16
+ @terminal: ACP::ClientConnection::_Terminal?
17
+
18
+ @fs: ACP::ClientConnection::_FileSystem?
19
+
20
+ FS_ROUTES: Array[ACP::ClientConnection::Inbound::Route]
21
+
22
+ # The terminal capability is a single bool, so its five routes share one
23
+ # gate. Their handlers may block for as long as the command runs, so the
24
+ # transport must serve each request on its own thread for this not to hold
25
+ # up others.
26
+ TERMINAL_ROUTES: Array[ACP::ClientConnection::Inbound::Route]
27
+
28
+ # @dynamic mcp_advertised=
29
+ attr_writer mcp_advertised: bool
30
+
31
+ # @rbs elicitations: ACP::ClientConnection::Elicitations
32
+ # @rbs fs: ACP::ClientConnection::_FileSystem?
33
+ # @rbs terminal: ACP::ClientConnection::_Terminal?
34
+ # @rbs elicitation: ACP::ClientConnection::_Elicitation?
35
+ # @rbs mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) ->
36
+ # (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
37
+ # @rbs extension_requests: Hash[String, ^(untyped) -> untyped]
38
+ # @rbs extension_notifications: Hash[String, ^(untyped) -> void]
39
+ # @rbs return: void
40
+ def initialize: (elicitations: ACP::ClientConnection::Elicitations, ?fs: ACP::ClientConnection::_FileSystem?, ?terminal: ACP::ClientConnection::_Terminal?, ?elicitation: ACP::ClientConnection::_Elicitation?, ?mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?, ?extension_requests: Hash[String, ^(untyped) -> untyped], ?extension_notifications: Hash[String, ^(untyped) -> void]) -> void
41
+
42
+ # @rbs return: Hash[String, ACP::Transport::Stdio::_Handler]
43
+ def requests: () -> Hash[String, ACP::Transport::Stdio::_Handler]
44
+
45
+ # @rbs return: Hash[String, ACP::Transport::Stdio::_NotificationHandler]
46
+ def notifications: () -> Hash[String, ACP::Transport::Stdio::_NotificationHandler]
47
+
48
+ # @rbs capabilities: ACP::Types::ClientCapabilities?
49
+ # @rbs return: void
50
+ def advertise: (ACP::Types::ClientCapabilities? capabilities) -> void
51
+
52
+ private
53
+
54
+ # @rbs route: ACP::ClientConnection::Inbound::Route
55
+ # @rbs handler: untyped
56
+ # @rbs return: ^(untyped) -> untyped
57
+ def serve: (ACP::ClientConnection::Inbound::Route route, untyped handler) -> ^(untyped) -> untyped
58
+
59
+ # @rbs type: ACP::Transport::_Parser
60
+ # @rbs params: untyped
61
+ # @rbs &block: (untyped) -> untyped
62
+ # @rbs return: untyped
63
+ def parsed: (ACP::Transport::_Parser type, untyped params) { (untyped) -> untyped } -> untyped
64
+
65
+ # @rbs routes: Array[ACP::ClientConnection::Inbound::Route]
66
+ # @rbs handler: untyped
67
+ # @rbs capabilities: ACP::Types::ClientCapabilities?
68
+ # @rbs return: Array[String]
69
+ def unserved: (Array[ACP::ClientConnection::Inbound::Route] routes, untyped handler, ACP::Types::ClientCapabilities? capabilities) -> Array[String]
70
+
71
+ # @rbs capabilities: ACP::Types::ElicitationCapabilities?
72
+ # @rbs return: Array[String]
73
+ def unserved_elicitation_modes: (ACP::Types::ElicitationCapabilities? capabilities) -> Array[String]
74
+
75
+ # @rbs what: String
76
+ # @rbs unserved: Array[String]
77
+ # @rbs return: void
78
+ def check_served: (String what, Array[String] unserved) -> void
79
+
80
+ # @rbs return: Hash[String, ^(untyped) -> untyped]
81
+ def mcp_requests: () -> Hash[String, ^(untyped) -> untyped]
82
+
83
+ # @rbs params: untyped
84
+ # @rbs return: (ACP::Types::CreateElicitationResponse | ACP::RequestError)
85
+ def create_elicitation: (untyped params) -> (ACP::Types::CreateElicitationResponse | ACP::RequestError)
86
+
87
+ # @rbs request: ACP::Types::CreateElicitationRequest
88
+ # @rbs return: ACP::RequestError?
89
+ def elicitation_refusal: (ACP::Types::CreateElicitationRequest request) -> ACP::RequestError?
90
+ end
@@ -1,36 +1,28 @@
1
1
  # Generated from lib/acp/client_connection/streams.rb with RBS::Inline
2
2
 
3
- # It holds no send facade of its own — requests go through the sender and
4
- # answers to the agent ride the connection's routes — so it is unit-testable
5
- # without a transport.
6
3
  class ACP::ClientConnection::Streams
7
4
  CANCELLED: ACP::Types::RequestPermissionResponse
8
5
 
9
- @outstanding_elicitations: Hash[String, bool]
10
-
11
- @pending_permissions: Hash[String, Array[Thread::Queue]]
6
+ @sender: ACP::Transport::Stdio
12
7
 
13
- @streams: Hash[String, Thread::Queue]
8
+ @permission: ACP::ClientConnection::_PermissionHandler
14
9
 
15
- @lock: Thread::Mutex
10
+ @updates: ACP::ClientConnection::_UpdateHandler
16
11
 
17
12
  @logger: ACP::Transport::_Logger
18
13
 
19
- @complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
20
-
21
- @updates: ACP::ClientConnection::_UpdateHandler
14
+ @lock: Thread::Mutex
22
15
 
23
- @permission: ACP::ClientConnection::_PermissionHandler
16
+ @streams: Hash[String, Thread::Queue]
24
17
 
25
- @sender: ACP::Transport::Stdio
18
+ @pending_permissions: Hash[String, Array[Thread::Queue]]
26
19
 
27
20
  # @rbs sender: ACP::Transport::Stdio
28
21
  # @rbs permission: ACP::ClientConnection::_PermissionHandler
29
22
  # @rbs updates: ACP::ClientConnection::_UpdateHandler
30
23
  # @rbs logger: ACP::Transport::_Logger
31
- # @rbs complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
32
24
  # @rbs return: void
33
- def initialize: (sender: ACP::Transport::Stdio, permission: ACP::ClientConnection::_PermissionHandler, updates: ACP::ClientConnection::_UpdateHandler, logger: ACP::Transport::_Logger, ?complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?) -> void
25
+ def initialize: (sender: ACP::Transport::Stdio, permission: ACP::ClientConnection::_PermissionHandler, updates: ACP::ClientConnection::_UpdateHandler, logger: ACP::Transport::_Logger) -> void
34
26
 
35
27
  # The request waits on its own thread so the caller's thread can yield each
36
28
  # update as it arrives. The reader thread queues an update before it settles
@@ -67,19 +59,6 @@ class ACP::ClientConnection::Streams
67
59
  # @rbs return: void
68
60
  def cancel: (String session_id) -> void
69
61
 
70
- # @rbs elicitation_id: String
71
- # @rbs return: void
72
- def register_elicitation: (String elicitation_id) -> void
73
-
74
- # The spec requires a completion for an unknown or already-completed
75
- # elicitation id to be ignored, so only an id registered by a served
76
- # url-mode request reaches the handler. It runs on the transport's reader
77
- # thread, so it must return quickly.
78
- #
79
- # @rbs params: untyped
80
- # @rbs return: void
81
- def complete_elicitation: (untyped params) -> void
82
-
83
62
  private
84
63
 
85
64
  # @rbs session_id: String
@@ -1,123 +1,33 @@
1
1
  # Generated from lib/acp/client_connection.rb with RBS::Inline
2
2
 
3
3
  class ACP::ClientConnection
4
- @transport: ACP::Transport::Stdio
5
-
6
- @permission: ACP::ClientConnection::_PermissionHandler
7
-
8
- @read_text_file: (^(ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError))?
9
-
10
- @write_text_file: (^(ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError))?
11
-
12
- @create_terminal: (^(ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError))?
13
-
14
- @terminal_output: (^(ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError))?
15
-
16
- @wait_for_terminal_exit: (^(ACP::Types::WaitForTerminalExitRequest) -> (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError))?
17
-
18
- @kill_terminal: (^(ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::RequestError))?
19
-
20
- @release_terminal: (^(ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError))?
21
-
22
- @elicitation: (^(ACP::Types::CreateElicitationRequest) -> (ACP::Types::CreateElicitationResponse | ACP::RequestError))?
23
-
24
- @mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
25
-
26
- @mcp_advertised: bool?
27
-
28
- @fs_capabilities: ACP::Types::FileSystemCapabilities?
29
-
30
- @terminal: bool?
31
-
32
- @elicitation_capabilities: ACP::Types::ElicitationCapabilities?
33
-
34
- @extension_requests: Hash[String, ^(untyped) -> untyped]
35
-
36
- @extension_notifications: Hash[String, ^(untyped) -> void]
4
+ @inbound: ACP::ClientConnection::Inbound
37
5
 
38
6
  @streams: ACP::ClientConnection::Streams
39
7
 
40
- @logger: ACP::Transport::_Logger
8
+ @transport: ACP::Transport::Stdio
41
9
 
42
10
  IGNORE: ^(ACP::Types::SessionNotification) -> void
43
11
 
44
- class Route
45
- @label: String
46
-
47
- @key: String
48
-
49
- @refuse: Symbol
50
-
51
- @advertised: ^(untyped) -> (bool | nil)
52
-
53
- @family: Symbol
54
-
55
- @handler: Symbol
56
-
57
- @type: ACP::Transport::_Parser
58
-
59
- @wire: String
60
-
61
- # @rbs wire: String
62
- # @rbs type: ACP::Transport::_Parser
63
- # @rbs handler: Symbol
64
- # @rbs family: Symbol
65
- # @rbs key: String
66
- # @rbs advertised: ^(untyped) -> (bool | nil)
67
- # @rbs refuse: Symbol
68
- # @rbs label: String?
69
- # @rbs return: void
70
- def initialize: (wire: String, type: ACP::Transport::_Parser, handler: Symbol, family: Symbol, key: String, ?advertised: ^(untyped) -> (bool | nil), ?refuse: Symbol, ?label: String?) -> void
71
-
72
- # @dynamic wire, type, handler, family, advertised, refuse, key, label
73
- attr_reader wire: String
74
-
75
- attr_reader type: ACP::Transport::_Parser
76
-
77
- attr_reader handler: Symbol
78
-
79
- attr_reader family: Symbol
80
-
81
- attr_reader advertised: ^(untyped) -> (bool | nil)
82
-
83
- attr_reader refuse: Symbol
84
-
85
- attr_reader key: String
86
-
87
- attr_reader label: String
88
- end
89
-
90
- # The routes are registered at start, before connect records the
91
- # advertisement, so each one answers its refusal until then. The terminal
92
- # capability is a single bool, so its five routes share one gate.
93
- #
94
- # The terminal handlers may block for as long as the command runs, so the
95
- # transport must serve each request on its own thread for this not to hold
96
- # up others.
97
- SERVE: Array[ACP::ClientConnection::Route]
98
-
99
12
  # @rbs transport: ACP::Transport::Stdio
100
13
  # @rbs permission: ACP::ClientConnection::_PermissionHandler
101
- # @rbs read_text_file: (^(ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError))?
102
- # @rbs write_text_file: (^(ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError))?
103
- # @rbs create_terminal: (^(ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError))?
104
- # @rbs terminal_output: (^(ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError))?
105
- # @rbs wait_for_terminal_exit: (^(ACP::Types::WaitForTerminalExitRequest) ->
106
- # (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError))?
107
- # @rbs kill_terminal: (^(ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::RequestError))?
108
- # @rbs release_terminal: (^(ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError))?
109
- # @rbs elicitation: (^(ACP::Types::CreateElicitationRequest) ->
110
- # (ACP::Types::CreateElicitationResponse | ACP::RequestError))?
111
- # @rbs complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
112
14
  # @rbs updates: ACP::ClientConnection::_UpdateHandler
15
+ # @rbs fs: ACP::ClientConnection::_FileSystem?
16
+ # @rbs terminal: ACP::ClientConnection::_Terminal?
17
+ # @rbs elicitation: ACP::ClientConnection::_Elicitation?
113
18
  # @rbs mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) ->
114
19
  # (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
115
20
  # @rbs extension_requests: Hash[String, ^(untyped) -> untyped]
116
21
  # @rbs extension_notifications: Hash[String, ^(untyped) -> void]
117
- # @rbs streams: ACP::ClientConnection::Streams?
118
22
  # @rbs logger: ACP::Transport::_Logger
23
+ # @rbs return: ACP::ClientConnection
24
+ def self.build: (transport: ACP::Transport::Stdio, permission: ACP::ClientConnection::_PermissionHandler, ?updates: ACP::ClientConnection::_UpdateHandler, ?fs: ACP::ClientConnection::_FileSystem?, ?terminal: ACP::ClientConnection::_Terminal?, ?elicitation: ACP::ClientConnection::_Elicitation?, ?mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?, ?extension_requests: Hash[String, ^(untyped) -> untyped], ?extension_notifications: Hash[String, ^(untyped) -> void], ?logger: ACP::Transport::_Logger) -> ACP::ClientConnection
25
+
26
+ # @rbs transport: ACP::Transport::Stdio
27
+ # @rbs streams: ACP::ClientConnection::Streams
28
+ # @rbs inbound: ACP::ClientConnection::Inbound
119
29
  # @rbs return: void
120
- def initialize: (transport: ACP::Transport::Stdio, permission: ACP::ClientConnection::_PermissionHandler, ?read_text_file: (^(ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError))?, ?write_text_file: (^(ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError))?, ?create_terminal: (^(ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError))?, ?terminal_output: (^(ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError))?, ?wait_for_terminal_exit: (^(ACP::Types::WaitForTerminalExitRequest) -> (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError))?, ?kill_terminal: (^(ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::RequestError))?, ?release_terminal: (^(ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError))?, ?elicitation: (^(ACP::Types::CreateElicitationRequest) -> (ACP::Types::CreateElicitationResponse | ACP::RequestError))?, ?complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?, ?updates: ACP::ClientConnection::_UpdateHandler, ?mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?, ?extension_requests: Hash[String, ^(untyped) -> untyped], ?extension_notifications: Hash[String, ^(untyped) -> void], ?streams: ACP::ClientConnection::Streams?, ?logger: ACP::Transport::_Logger) -> void
30
+ def initialize: (transport: ACP::Transport::Stdio, streams: ACP::ClientConnection::Streams, inbound: ACP::ClientConnection::Inbound) -> void
121
31
 
122
32
  # @rbs return: Thread
123
33
  def start: () -> Thread
@@ -235,42 +145,8 @@ class ACP::ClientConnection
235
145
 
236
146
  private
237
147
 
238
- # @rbs route: ACP::ClientConnection::Route
239
- # @rbs return: ^(untyped) -> (untyped | ACP::RequestError)
240
- def serve: (ACP::ClientConnection::Route route) -> ^(untyped) -> (untyped | ACP::RequestError)
241
-
242
- # @rbs route: ACP::ClientConnection::Route
243
- # @rbs return: ACP::RequestError
244
- def refuse: (ACP::ClientConnection::Route route) -> ACP::RequestError
245
-
246
- # @rbs name: String
247
- # @rbs family: Symbol
248
- # @rbs capabilities: untyped
249
- # @rbs return: void
250
- def check_served: (String name, Symbol family, untyped capabilities) -> void
251
-
252
- # The unstable types are referenced while the row is built, so the route can
253
- # only be served when the caller opted in with `require 'acp/types/unstable'`.
254
- # It is registered only when a handler serves it: unlike the fs and terminal
255
- # gates, the mcp gate reads the agent's advertisement, so nothing forces an
256
- # advertised request to have a handler.
257
- #
258
- # @rbs return: Hash[String, ^(untyped) -> (untyped | ACP::RequestError)]
259
- def mcp_requests: () -> Hash[String, ^(untyped) -> (untyped | ACP::RequestError)]
260
-
261
148
  # @rbs type: ACP::Transport::_Parser
262
149
  # @rbs result: (Hash[String, untyped] | ACP::RequestError)
263
150
  # @rbs return: untyped
264
151
  def parse: (ACP::Transport::_Parser type, Hash[String, untyped] | ACP::RequestError result) -> untyped
265
-
266
- # The route is registered at start, before connect records the advertised
267
- # capabilities, so a request for an unadvertised mode answers -32602.
268
- #
269
- # @rbs params: untyped
270
- # @rbs return: (ACP::Types::CreateElicitationResponse | ACP::RequestError)
271
- def create_elicitation: (untyped params) -> (ACP::Types::CreateElicitationResponse | ACP::RequestError)
272
-
273
- # @rbs capabilities: ACP::Types::ElicitationCapabilities?
274
- # @rbs return: Array[String]
275
- def unserved_elicitation_modes: (ACP::Types::ElicitationCapabilities? capabilities) -> Array[String]
276
152
  end
@@ -6,4 +6,8 @@ module ACP::Extensions
6
6
  # @rbs name: String
7
7
  # @rbs return: void
8
8
  def validate_name: (String name) -> void
9
+
10
+ # @rbs names: Array[String]
11
+ # @rbs return: void
12
+ def validate_names: (Array[String] names) -> void
9
13
  end
@@ -3,6 +3,14 @@
3
3
  module ACP::Protocol
4
4
  PROTOCOL_VERSION: Integer
5
5
 
6
+ # Readers missing along the chain count as unadvertised, so the stable
7
+ # capabilities answer false for the unstable-only paths (fork, providers).
8
+ #
9
+ # @rbs capabilities: untyped
10
+ # @rbs path: Array[Symbol]
11
+ # @rbs return: bool
12
+ def advertised?: (untyped capabilities, Array[Symbol] path) -> bool
13
+
6
14
  # @rbs capabilities: (ACP::Types::AgentCapabilities | ACP::Types::Unstable::AgentCapabilities | Hash[String, untyped])
7
15
  # @rbs return: bool
8
16
  def mcp_acp_advertised?: (ACP::Types::AgentCapabilities | ACP::Types::Unstable::AgentCapabilities | Hash[String, untyped] capabilities) -> bool
@@ -2,13 +2,13 @@
2
2
 
3
3
  class ACP::Transport::Reply
4
4
  # @dynamic result
5
- attr_reader result: ACP::Transport::Stdio::_ToH
5
+ attr_reader result: ACP::Transport::_Response
6
6
 
7
7
  # @dynamic after
8
8
  attr_reader after: ^() -> void
9
9
 
10
- # @rbs result: ACP::Transport::Stdio::_ToH
10
+ # @rbs result: ACP::Transport::_Response
11
11
  # @rbs after: ^() -> void
12
12
  # @rbs return: void
13
- def initialize: (ACP::Transport::Stdio::_ToH result, after: ^() -> void) -> void
13
+ def initialize: (ACP::Transport::_Response result, after: ^() -> void) -> void
14
14
  end
@@ -134,13 +134,13 @@ class ACP::Transport::Stdio
134
134
  #
135
135
  # @rbs handler: _Handler
136
136
  # @rbs params: untyped
137
- # @rbs return: (_ToH | ACP::RequestError | ACP::Transport::Reply)
138
- def invoke: (_Handler handler, untyped params) -> (_ToH | ACP::RequestError | ACP::Transport::Reply)
137
+ # @rbs return: (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
138
+ def invoke: (_Handler handler, untyped params) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
139
139
 
140
140
  # @rbs id: untyped
141
- # @rbs outcome: (_ToH | ACP::RequestError)
141
+ # @rbs outcome: (ACP::Transport::_Response | ACP::RequestError)
142
142
  # @rbs return: void
143
- def reply: (untyped id, _ToH | ACP::RequestError outcome) -> void
143
+ def reply: (untyped id, ACP::Transport::_Response | ACP::RequestError outcome) -> void
144
144
 
145
145
  # @rbs queue: Thread::Queue
146
146
  # @rbs return: Integer?
@@ -7,4 +7,13 @@ module ACP::Types
7
7
  #
8
8
  # @rbs return: bool
9
9
  def self.unstable_enabled?: () -> bool
10
+
11
+ # Generated from_h checks only nested values, so a payload that is not an
12
+ # object is rejected here: a String would answer nil for every key and parse
13
+ # as an empty object.
14
+ #
15
+ # @rbs type: ACP::Transport::_Parser
16
+ # @rbs payload: untyped
17
+ # @rbs return: untyped
18
+ def self.parse: (ACP::Transport::_Parser type, untyped payload) -> untyped
10
19
  end
@@ -8,75 +8,23 @@ class ACP::AgentConnection
8
8
  def respond_to?: (Symbol) -> bool
9
9
  end
10
10
 
11
- interface _LoadSession
11
+ interface _FullAgent
12
+ include _Agent
13
+ def authenticate: (ACP::Types::AuthenticateRequest) -> (ACP::Types::AuthenticateResponse | ACP::RequestError)
12
14
  def load_session: (ACP::Types::LoadSessionRequest) -> (ACP::Types::LoadSessionResponse | ACP::RequestError)
13
- end
14
-
15
- interface _ListSessions
16
15
  def list_sessions: (ACP::Types::ListSessionsRequest) -> (ACP::Types::ListSessionsResponse | ACP::RequestError)
17
- end
18
-
19
- interface _Authenticate
20
- def authenticate: (ACP::Types::AuthenticateRequest) -> (ACP::Types::AuthenticateResponse | ACP::RequestError)
21
- end
22
-
23
- interface _ResumeSession
24
16
  def resume_session: (ACP::Types::ResumeSessionRequest) -> (ACP::Types::ResumeSessionResponse | ACP::RequestError)
25
- end
26
-
27
- interface _CloseSession
28
17
  def close_session: (ACP::Types::CloseSessionRequest) -> (ACP::Types::CloseSessionResponse | ACP::RequestError)
29
- end
30
-
31
- interface _DeleteSession
32
18
  def delete_session: (ACP::Types::DeleteSessionRequest) -> (ACP::Types::DeleteSessionResponse | ACP::RequestError)
33
- end
34
-
35
- interface _Logout
36
19
  def logout: (ACP::Types::LogoutRequest) -> (ACP::Types::LogoutResponse | ACP::RequestError)
37
- end
38
-
39
- interface _ForkSession
20
+ def change_session_mode: (ACP::Types::SetSessionModeRequest) -> (ACP::Types::SetSessionModeResponse | ACP::RequestError)
21
+ def change_session_config_option: (ACP::Types::SetSessionConfigOptionRequest) -> (ACP::Types::SetSessionConfigOptionResponse | ACP::RequestError)
40
22
  def fork_session: (ACP::Types::Unstable::ForkSessionRequest) -> (ACP::Types::Unstable::ForkSessionResponse | ACP::RequestError)
41
- end
42
-
43
- interface _ListProviders
44
23
  def list_providers: (ACP::Types::Unstable::ListProvidersRequest) -> (ACP::Types::Unstable::ListProvidersResponse | ACP::RequestError)
45
- end
46
-
47
- interface _SetProvider
48
24
  def set_provider: (ACP::Types::Unstable::SetProviderRequest) -> (ACP::Types::Unstable::SetProviderResponse | ACP::RequestError)
49
- end
50
-
51
- interface _DisableProvider
52
25
  def disable_provider: (ACP::Types::Unstable::DisableProviderRequest) -> (ACP::Types::Unstable::DisableProviderResponse | ACP::RequestError)
53
26
  end
54
27
 
55
- interface _ChangeSessionMode
56
- def change_session_mode: (ACP::Types::SetSessionModeRequest) -> (ACP::Types::SetSessionModeResponse | ACP::RequestError)
57
- end
58
-
59
- interface _ChangeSessionConfigOption
60
- def change_session_config_option: (ACP::Types::SetSessionConfigOptionRequest) -> (ACP::Types::SetSessionConfigOptionResponse | ACP::RequestError)
61
- end
62
-
63
- interface _FullAgent
64
- include _Agent
65
- include _LoadSession
66
- include _ListSessions
67
- include _Authenticate
68
- include _ResumeSession
69
- include _CloseSession
70
- include _DeleteSession
71
- include _Logout
72
- include _ForkSession
73
- include _ListProviders
74
- include _SetProvider
75
- include _DisableProvider
76
- include _ChangeSessionMode
77
- include _ChangeSessionConfigOption
78
- end
79
-
80
28
  interface _SessionCreated
81
29
  def session_created: (ACP::Types::NewSessionResponse) -> void
82
30
  end
@@ -8,4 +8,31 @@ class ACP::ClientConnection
8
8
  # Runs on the transport's reader thread, so it must return quickly.
9
9
  def call: (ACP::Types::SessionNotification) -> void
10
10
  end
11
+
12
+ # Each handler object needs only the methods of the capabilities initialize
13
+ # advertises; ClientConnection probes for the rest.
14
+ interface _FileSystem
15
+ def read_text_file: (ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError)
16
+ def write_text_file: (ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError)
17
+ def respond_to?: (Symbol) -> bool
18
+ end
19
+
20
+ # Each method runs on its own thread and may block for as long as the
21
+ # command runs.
22
+ interface _Terminal
23
+ def create_terminal: (ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError)
24
+ def terminal_output: (ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError)
25
+ def wait_for_terminal_exit: (ACP::Types::WaitForTerminalExitRequest) -> (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError)
26
+ def kill_terminal: (ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::RequestError)
27
+ def release_terminal: (ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError)
28
+ def respond_to?: (Symbol) -> bool
29
+ end
30
+
31
+ interface _Elicitation
32
+ def create_elicitation: (ACP::Types::CreateElicitationRequest) -> (ACP::Types::CreateElicitationResponse | ACP::RequestError)
33
+ # Optional, for url mode. Runs on the transport's reader thread, so it
34
+ # must return quickly.
35
+ def complete_elicitation: (ACP::Types::CompleteElicitationNotification) -> void
36
+ def respond_to?: (Symbol) -> bool
37
+ end
11
38
  end