acp-sdk 0.2.0 → 0.3.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.
@@ -16,11 +16,9 @@ class ACP::Transport::Stdio
16
16
  # @rbs @next_id: Integer
17
17
  # @rbs @closed: bool
18
18
 
19
- INTERNAL_ERROR = -32_603 #: Integer
20
- PARSE_ERROR = ACP::Transport::ResponseError.new(code: -32_700, message: 'Parse error') #: ACP::Transport::ResponseError
21
- INVALID_REQUEST = ACP::Transport::ResponseError.new(code: -32_600, message: 'Invalid request') #: ACP::Transport::ResponseError
22
- METHOD_NOT_FOUND = ACP::Transport::ResponseError.new(code: -32_601, message: 'Method not found') #: ACP::Transport::ResponseError
23
- CONNECTION_CLOSED = ACP::Transport::ResponseError.new(code: INTERNAL_ERROR, message: 'Connection closed') #: ACP::Transport::ResponseError
19
+ CONNECTION_CLOSED = ACP::RequestError.new(
20
+ code: ACP::RequestError::INTERNAL_ERROR, message: 'Connection closed'
21
+ ) #: ACP::RequestError
24
22
 
25
23
  # @rbs input: _Reader
26
24
  # @rbs output: _Writer
@@ -52,14 +50,14 @@ class ACP::Transport::Stdio
52
50
 
53
51
  # @rbs method: String
54
52
  # @rbs params: untyped
55
- # @rbs return: ACP::Transport::Result
53
+ # @rbs return: (Hash[String, untyped] | ACP::RequestError)
56
54
  def request(method, params = nil)
57
55
  queue = Thread::Queue.new
58
56
  id = register(queue)
59
- return ACP::Transport::Result.error(CONNECTION_CLOSED) unless id
57
+ return CONNECTION_CLOSED unless id
60
58
 
61
59
  write({ 'jsonrpc' => '2.0', 'id' => id, 'method' => method, 'params' => params }.compact)
62
- queue.pop || ACP::Transport::Result.error(CONNECTION_CLOSED)
60
+ queue.pop || CONNECTION_CLOSED
63
61
  end
64
62
 
65
63
  # @rbs method: String
@@ -78,7 +76,7 @@ class ACP::Transport::Stdio
78
76
  def receive(line, requests, notifications)
79
77
  message = parse(line)
80
78
  case message
81
- when ACP::Transport::ResponseError then reply(nil, ACP::Transport::Result.error(message))
79
+ when ACP::RequestError then reply(nil, message)
82
80
  else route(message, requests, notifications)
83
81
  end
84
82
  end
@@ -98,25 +96,24 @@ class ACP::Transport::Stdio
98
96
  handler = notifications[method]
99
97
  quietly { handler.call(message['params']) } if handler
100
98
  elsif message.key?('result')
101
- settle(message['id'], ACP::Transport::Result.ok(message['result']))
99
+ settle(message['id'], message['result'])
102
100
  elsif error.is_a?(Hash) && error['code'].is_a?(Integer) && error['message'].is_a?(String)
103
101
  code, text, data = error.values_at('code', 'message', 'data')
104
- response_error = ACP::Transport::ResponseError.new(code:, message: text, data:)
105
- settle(message['id'], ACP::Transport::Result.error(response_error))
102
+ settle(message['id'], ACP::RequestError.new(code:, message: text, data:))
106
103
  else
107
- reply(nil, ACP::Transport::Result.error(INVALID_REQUEST))
104
+ reply(nil, ACP::RequestError.invalid_request)
108
105
  end
109
106
  end
110
107
 
111
108
  # @rbs line: String
112
- # @rbs return: Hash[String, untyped] | ACP::Transport::ResponseError
109
+ # @rbs return: Hash[String, untyped] | ACP::RequestError
113
110
  def parse(line)
114
- return PARSE_ERROR unless line.valid_encoding?
111
+ return ACP::RequestError.parse_error unless line.valid_encoding?
115
112
 
116
113
  message = JSON.parse(line)
117
- message.is_a?(Hash) ? message : INVALID_REQUEST
114
+ message.is_a?(Hash) ? message : ACP::RequestError.invalid_request
118
115
  rescue JSON::ParserError
119
- PARSE_ERROR
116
+ ACP::RequestError.parse_error
120
117
  end
121
118
 
122
119
  # @rbs handler: _Handler?
@@ -125,7 +122,7 @@ class ACP::Transport::Stdio
125
122
  # @rbs return: void
126
123
  def serve(handler, id, params)
127
124
  Thread.new do
128
- outcome = handler ? invoke(handler, params) : ACP::Transport::Result.error(METHOD_NOT_FOUND)
125
+ outcome = handler ? invoke(handler, params) : ACP::RequestError.method_not_found
129
126
  case outcome
130
127
  when ACP::Transport::Reply
131
128
  reply(id, outcome.result)
@@ -152,19 +149,25 @@ class ACP::Transport::Stdio
152
149
  #
153
150
  # @rbs handler: _Handler
154
151
  # @rbs params: untyped
155
- # @rbs return: ACP::Transport::Result | ACP::Transport::Reply
152
+ # @rbs return: (_ToH | ACP::RequestError | ACP::Transport::Reply)
156
153
  def invoke(handler, params)
157
154
  handler.call(params)
158
155
  rescue StandardError => e
159
- ACP::Transport::Result.error(ACP::Transport::ResponseError.new(code: INTERNAL_ERROR, message: e.message))
156
+ ACP::RequestError.new(code: ACP::RequestError::INTERNAL_ERROR, message: e.message)
160
157
  end
161
158
 
159
+ # The success arm is whatever the handler returned, which the transport only
160
+ # knows serializes with to_h; RequestError picks the error arm of the reply.
161
+ #
162
162
  # @rbs id: untyped
163
- # @rbs result: ACP::Transport::Result
163
+ # @rbs outcome: (_ToH | ACP::RequestError)
164
164
  # @rbs return: void
165
- def reply(id, result)
166
- error = result.error
167
- write({ 'jsonrpc' => '2.0', 'id' => id }.merge(error ? { 'error' => error.to_h } : { 'result' => result.value }))
165
+ def reply(id, outcome)
166
+ payload = case outcome
167
+ when ACP::RequestError then { 'error' => outcome.to_h }
168
+ else { 'result' => outcome.to_h }
169
+ end
170
+ write({ 'jsonrpc' => '2.0', 'id' => id }.merge(payload))
168
171
  end
169
172
 
170
173
  # @rbs queue: Thread::Queue
@@ -180,7 +183,7 @@ class ACP::Transport::Stdio
180
183
  end
181
184
 
182
185
  # @rbs id: untyped
183
- # @rbs result: ACP::Transport::Result
186
+ # @rbs result: (Hash[String, untyped] | ACP::RequestError)
184
187
  # @rbs return: void
185
188
  def settle(id, result)
186
189
  @lock.synchronize { @pending.delete(id) }&.push(result)
data/lib/acp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ACP
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -24,36 +24,36 @@ class ACP::AgentConnection::Client
24
24
  # closes.
25
25
  #
26
26
  # @rbs request: ACP::Types::RequestPermissionRequest
27
- # @rbs return: ACP::Types::RequestPermissionResponse | ACP::Transport::ResponseError
28
- def request_permission: (ACP::Types::RequestPermissionRequest request) -> (ACP::Types::RequestPermissionResponse | ACP::Transport::ResponseError)
27
+ # @rbs return: ACP::Types::RequestPermissionResponse | ACP::RequestError
28
+ def request_permission: (ACP::Types::RequestPermissionRequest request) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
29
29
 
30
30
  # @rbs request: ACP::Types::ReadTextFileRequest
31
- # @rbs return: ACP::Types::ReadTextFileResponse | ACP::Transport::ResponseError
32
- def read_text_file: (ACP::Types::ReadTextFileRequest request) -> (ACP::Types::ReadTextFileResponse | ACP::Transport::ResponseError)
31
+ # @rbs return: ACP::Types::ReadTextFileResponse | ACP::RequestError
32
+ def read_text_file: (ACP::Types::ReadTextFileRequest request) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError)
33
33
 
34
34
  # @rbs request: ACP::Types::WriteTextFileRequest
35
- # @rbs return: ACP::Types::WriteTextFileResponse | ACP::Transport::ResponseError
36
- def write_text_file: (ACP::Types::WriteTextFileRequest request) -> (ACP::Types::WriteTextFileResponse | ACP::Transport::ResponseError)
35
+ # @rbs return: ACP::Types::WriteTextFileResponse | ACP::RequestError
36
+ def write_text_file: (ACP::Types::WriteTextFileRequest request) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError)
37
37
 
38
38
  # @rbs request: ACP::Types::CreateTerminalRequest
39
- # @rbs return: ACP::Types::CreateTerminalResponse | ACP::Transport::ResponseError
40
- def create_terminal: (ACP::Types::CreateTerminalRequest request) -> (ACP::Types::CreateTerminalResponse | ACP::Transport::ResponseError)
39
+ # @rbs return: ACP::Types::CreateTerminalResponse | ACP::RequestError
40
+ def create_terminal: (ACP::Types::CreateTerminalRequest request) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError)
41
41
 
42
42
  # @rbs request: ACP::Types::TerminalOutputRequest
43
- # @rbs return: ACP::Types::TerminalOutputResponse | ACP::Transport::ResponseError
44
- def terminal_output: (ACP::Types::TerminalOutputRequest request) -> (ACP::Types::TerminalOutputResponse | ACP::Transport::ResponseError)
43
+ # @rbs return: ACP::Types::TerminalOutputResponse | ACP::RequestError
44
+ def terminal_output: (ACP::Types::TerminalOutputRequest request) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError)
45
45
 
46
46
  # @rbs request: ACP::Types::WaitForTerminalExitRequest
47
- # @rbs return: ACP::Types::WaitForTerminalExitResponse | ACP::Transport::ResponseError
48
- def wait_for_terminal_exit: (ACP::Types::WaitForTerminalExitRequest request) -> (ACP::Types::WaitForTerminalExitResponse | ACP::Transport::ResponseError)
47
+ # @rbs return: ACP::Types::WaitForTerminalExitResponse | ACP::RequestError
48
+ def wait_for_terminal_exit: (ACP::Types::WaitForTerminalExitRequest request) -> (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError)
49
49
 
50
50
  # @rbs request: ACP::Types::KillTerminalRequest
51
- # @rbs return: ACP::Types::KillTerminalResponse | ACP::Transport::ResponseError
52
- def kill_terminal: (ACP::Types::KillTerminalRequest request) -> (ACP::Types::KillTerminalResponse | ACP::Transport::ResponseError)
51
+ # @rbs return: ACP::Types::KillTerminalResponse | ACP::RequestError
52
+ def kill_terminal: (ACP::Types::KillTerminalRequest request) -> (ACP::Types::KillTerminalResponse | ACP::RequestError)
53
53
 
54
54
  # @rbs request: ACP::Types::ReleaseTerminalRequest
55
- # @rbs return: ACP::Types::ReleaseTerminalResponse | ACP::Transport::ResponseError
56
- def release_terminal: (ACP::Types::ReleaseTerminalRequest request) -> (ACP::Types::ReleaseTerminalResponse | ACP::Transport::ResponseError)
55
+ # @rbs return: ACP::Types::ReleaseTerminalResponse | ACP::RequestError
56
+ def release_terminal: (ACP::Types::ReleaseTerminalRequest request) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError)
57
57
 
58
58
  private
59
59
 
@@ -68,4 +68,11 @@ class ACP::AgentConnection::Client
68
68
  # @rbs request: ACP::AgentConnection::_Response
69
69
  # @rbs return: untyped
70
70
  def terminal_call: (String rpc_method, ACP::AgentConnection::_Parser type, ACP::AgentConnection::_Response request) -> untyped
71
+
72
+ # Same method-not-found code a peer would send, but with a message that says
73
+ # the refusal was local, so logs can tell the two cases apart.
74
+ #
75
+ # @rbs capability: String
76
+ # @rbs return: ACP::RequestError
77
+ def unadvertised: (String capability) -> ACP::RequestError
71
78
  end
@@ -9,8 +9,6 @@ class ACP::AgentConnection
9
9
 
10
10
  PROTOCOL_VERSION: Integer
11
11
 
12
- INVALID_PARAMS: ACP::Transport::ResponseError
13
-
14
12
  OPTIONAL: Array[ACP::AgentConnection::_OptionalMethod]
15
13
 
16
14
  # The schema has no initialize capability for modes or config options: an
@@ -33,8 +31,8 @@ class ACP::AgentConnection
33
31
 
34
32
  # @rbs agent: ACP::AgentConnection::_Agent
35
33
  # @rbs client: ACP::AgentConnection::Client
36
- # @rbs return: Hash[String, ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)]
37
- def requests: (ACP::AgentConnection::_Agent agent, ACP::AgentConnection::Client client) -> Hash[String, ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)]
34
+ # @rbs return: Hash[String, ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)]
35
+ def requests: (ACP::AgentConnection::_Agent agent, ACP::AgentConnection::Client client) -> Hash[String, ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)]
38
36
 
39
37
  # @rbs agent: ACP::AgentConnection::_Agent
40
38
  # @rbs return: Hash[String, ^(untyped) -> void]
@@ -43,24 +41,20 @@ class ACP::AgentConnection
43
41
  # Generated from_h raises on a missing key or a value of the wrong shape.
44
42
  #
45
43
  # @rbs type: ACP::AgentConnection::_Parser
46
- # @rbs &handle: (untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)
47
- # @rbs return: ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)
48
- def route: (ACP::AgentConnection::_Parser type) { (untyped) -> (ACP::Transport::Result | ACP::Transport::Reply) } -> ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)
49
-
50
- # @rbs response: ACP::AgentConnection::_Response | ACP::Transport::ResponseError
51
- # @rbs return: ACP::Transport::Result
52
- def respond: (ACP::AgentConnection::_Response | ACP::Transport::ResponseError response) -> ACP::Transport::Result
44
+ # @rbs &handle: (untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
45
+ # @rbs return: ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
46
+ def route: (ACP::AgentConnection::_Parser type) { (untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply) } -> ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
53
47
 
54
48
  # @rbs client: ACP::AgentConnection::Client
55
49
  # @rbs request: ACP::Types::InitializeRequest
56
- # @rbs return: ACP::Transport::Result
57
- def connect: (ACP::AgentConnection::Client client, ACP::Types::InitializeRequest request) -> ACP::Transport::Result
50
+ # @rbs return: ACP::Types::InitializeResponse
51
+ def connect: (ACP::AgentConnection::Client client, ACP::Types::InitializeRequest request) -> ACP::Types::InitializeResponse
58
52
 
59
53
  # session_created runs after the reply because the client must know the
60
54
  # session id before updates for it (e.g. available commands) arrive.
61
55
  #
62
56
  # @rbs agent: ACP::AgentConnection::_Agent
63
57
  # @rbs request: ACP::Types::NewSessionRequest
64
- # @rbs return: ACP::Transport::Result | ACP::Transport::Reply
65
- def new_session: (ACP::AgentConnection::_Agent agent, ACP::Types::NewSessionRequest request) -> (ACP::Transport::Result | ACP::Transport::Reply)
58
+ # @rbs return: (ACP::Types::NewSessionResponse | ACP::RequestError | ACP::Transport::Reply)
59
+ def new_session: (ACP::AgentConnection::_Agent agent, ACP::Types::NewSessionRequest request) -> (ACP::Types::NewSessionResponse | ACP::RequestError | ACP::Transport::Reply)
66
60
  end
@@ -0,0 +1,72 @@
1
+ # Generated from lib/acp/agent_process.rb with RBS::Inline
2
+
3
+ # A child agent process and the ACP::ClientConnection wired to its stdio.
4
+ # Spawn one with ACP::AgentProcess.spawn.
5
+ class ACP::AgentProcess
6
+ @stderr: String?
7
+
8
+ @err_reader: Thread?
9
+
10
+ @err_r: IO?
11
+
12
+ @waiter: Process::Waiter
13
+
14
+ @stdout: IO
15
+
16
+ @stdin: IO
17
+
18
+ @pid: Integer
19
+
20
+ @reader: Thread
21
+
22
+ @connection: ACP::ClientConnection
23
+
24
+ # @dynamic pid
25
+ attr_reader pid: Integer
26
+
27
+ # @dynamic connection
28
+ attr_reader connection: ACP::ClientConnection
29
+
30
+ # Child stderr captured when spawn was given stderr: :capture, else nil.
31
+ #
32
+ # @dynamic stderr
33
+ attr_reader stderr: String?
34
+
35
+ # Starts a command with args, env and cwd, wires its stdio to a new
36
+ # ACP::ClientConnection and starts it. With a block, yields the connection
37
+ # and this process, then terminates the child when the block exits; without
38
+ # one, returns the process and terminate is the caller's job.
39
+ #
40
+ # @rbs command: String
41
+ # @rbs *args: String
42
+ # @rbs env: Hash[String, String]?
43
+ # @rbs cwd: String?
44
+ # @rbs stderr: (:inherit | :capture)
45
+ # @rbs permission: ACP::ClientConnection::_PermissionHandler
46
+ # @rbs updates: ACP::ClientConnection::_UpdateHandler
47
+ # @rbs &block: ? (ACP::ClientConnection, ACP::AgentProcess) -> untyped
48
+ # @rbs return: (untyped | ACP::AgentProcess)
49
+ def self.spawn: (String command, *String args, permission: ACP::ClientConnection::_PermissionHandler, ?env: Hash[String, String]?, ?cwd: String?, ?stderr: :inherit | :capture, ?updates: ACP::ClientConnection::_UpdateHandler) ?{ (ACP::ClientConnection, ACP::AgentProcess) -> untyped } -> (untyped | ACP::AgentProcess)
50
+
51
+ # Closes stdin, waits for the child to exit — sending TERM and then KILL if
52
+ # it will not — and joins the transport reader before closing the pipe it
53
+ # reads.
54
+ #
55
+ # @rbs return: void
56
+ def terminate: () -> void
57
+
58
+ private
59
+
60
+ # @rbs connection: ACP::ClientConnection
61
+ # @rbs reader: Thread
62
+ # @rbs stdin: IO
63
+ # @rbs stdout: IO
64
+ # @rbs waiter: Process::Waiter
65
+ # @rbs err_r: IO?
66
+ # @rbs return: void
67
+ def initialize: (connection: ACP::ClientConnection, reader: Thread, stdin: IO, stdout: IO, waiter: Process::Waiter, err_r: IO?) -> void
68
+
69
+ # @rbs sig: String
70
+ # @rbs return: void
71
+ def signal: (String sig) -> void
72
+ end
@@ -26,26 +26,26 @@ class ACP::ClientConnection
26
26
  # sent by connect.
27
27
  #
28
28
  # @rbs request: ACP::Types::InitializeRequest
29
- # @rbs return: ACP::Types::InitializeResponse | ACP::Transport::ResponseError
30
- def connect: (ACP::Types::InitializeRequest request) -> (ACP::Types::InitializeResponse | ACP::Transport::ResponseError)
29
+ # @rbs return: ACP::Types::InitializeResponse | ACP::RequestError
30
+ def connect: (ACP::Types::InitializeRequest request) -> (ACP::Types::InitializeResponse | ACP::RequestError)
31
31
 
32
32
  # @rbs request: ACP::Types::NewSessionRequest
33
- # @rbs return: ACP::Types::NewSessionResponse | ACP::Transport::ResponseError
34
- def session_new: (ACP::Types::NewSessionRequest request) -> (ACP::Types::NewSessionResponse | ACP::Transport::ResponseError)
33
+ # @rbs return: ACP::Types::NewSessionResponse | ACP::RequestError
34
+ def session_new: (ACP::Types::NewSessionRequest request) -> (ACP::Types::NewSessionResponse | ACP::RequestError)
35
35
 
36
36
  # @rbs request: ACP::Types::PromptRequest
37
37
  # @rbs &block: (ACP::Types::SessionUpdate::t) -> void
38
- # @rbs return: ACP::Types::PromptResponse | ACP::Transport::ResponseError
39
- def session_prompt: (ACP::Types::PromptRequest request) { (ACP::Types::SessionUpdate::t) -> void } -> (ACP::Types::PromptResponse | ACP::Transport::ResponseError)
38
+ # @rbs return: ACP::Types::PromptResponse | ACP::RequestError
39
+ def session_prompt: (ACP::Types::PromptRequest request) { (ACP::Types::SessionUpdate::t) -> void } -> (ACP::Types::PromptResponse | ACP::RequestError)
40
40
 
41
41
  # @rbs request: ACP::Types::LoadSessionRequest
42
42
  # @rbs &block: (ACP::Types::SessionUpdate::t) -> void
43
- # @rbs return: ACP::Types::LoadSessionResponse | ACP::Transport::ResponseError
44
- def session_load: (ACP::Types::LoadSessionRequest request) { (ACP::Types::SessionUpdate::t) -> void } -> (ACP::Types::LoadSessionResponse | ACP::Transport::ResponseError)
43
+ # @rbs return: ACP::Types::LoadSessionResponse | ACP::RequestError
44
+ def session_load: (ACP::Types::LoadSessionRequest request) { (ACP::Types::SessionUpdate::t) -> void } -> (ACP::Types::LoadSessionResponse | ACP::RequestError)
45
45
 
46
46
  # @rbs request: ACP::Types::ListSessionsRequest
47
- # @rbs return: ACP::Types::ListSessionsResponse | ACP::Transport::ResponseError
48
- def session_list: (ACP::Types::ListSessionsRequest request) -> (ACP::Types::ListSessionsResponse | ACP::Transport::ResponseError)
47
+ # @rbs return: ACP::Types::ListSessionsResponse | ACP::RequestError
48
+ def session_list: (ACP::Types::ListSessionsRequest request) -> (ACP::Types::ListSessionsResponse | ACP::RequestError)
49
49
 
50
50
  # @rbs notification: ACP::Types::CancelNotification
51
51
  # @rbs return: void
@@ -54,9 +54,9 @@ class ACP::ClientConnection
54
54
  private
55
55
 
56
56
  # @rbs type: ACP::AgentConnection::_Parser
57
- # @rbs result: ACP::Transport::Result
57
+ # @rbs result: (Hash[String, untyped] | ACP::RequestError)
58
58
  # @rbs return: untyped
59
- def parse: (ACP::AgentConnection::_Parser type, ACP::Transport::Result result) -> untyped
59
+ def parse: (ACP::AgentConnection::_Parser type, Hash[String, untyped] | ACP::RequestError result) -> untyped
60
60
 
61
61
  # The request waits on its own thread so the caller's thread can yield each
62
62
  # update as it arrives. The reader thread queues an update before it settles
@@ -66,8 +66,8 @@ class ACP::ClientConnection
66
66
  # @rbs method: String
67
67
  # @rbs params: Hash[String, untyped]
68
68
  # @rbs &block: (ACP::Types::SessionUpdate::t) -> void
69
- # @rbs return: ACP::Transport::Result
70
- def stream: (String session_id, String method, Hash[String, untyped] params) { (ACP::Types::SessionUpdate::t) -> void } -> ACP::Transport::Result
69
+ # @rbs return: (Hash[String, untyped] | ACP::RequestError)
70
+ def stream: (String session_id, String method, Hash[String, untyped] params) { (ACP::Types::SessionUpdate::t) -> void } -> (Hash[String, untyped] | ACP::RequestError)
71
71
 
72
72
  # Pushes under the lock so a stream cannot close its queue between the
73
73
  # lookup and the push.
@@ -77,6 +77,6 @@ class ACP::ClientConnection
77
77
  def dispatch: (untyped params) -> void
78
78
 
79
79
  # @rbs params: untyped
80
- # @rbs return: ACP::Transport::Result
81
- def request_permission: (untyped params) -> ACP::Transport::Result
80
+ # @rbs return: (ACP::Types::RequestPermissionResponse | ACP::RequestError)
81
+ def request_permission: (untyped params) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
82
82
  end
@@ -0,0 +1,65 @@
1
+ # Generated from lib/acp/request_error.rb with RBS::Inline
2
+
3
+ # The schema's JSON-RPC Error object, named after the official SDKs'
4
+ # RequestError: built by handlers and local refusals, and decoded from a
5
+ # peer's error replies by the transport.
6
+ class ACP::RequestError
7
+ PARSE_ERROR: Integer
8
+
9
+ INVALID_REQUEST: Integer
10
+
11
+ METHOD_NOT_FOUND: Integer
12
+
13
+ INVALID_PARAMS: Integer
14
+
15
+ INTERNAL_ERROR: Integer
16
+
17
+ REQUEST_CANCELLED: Integer
18
+
19
+ AUTH_REQUIRED: Integer
20
+
21
+ RESOURCE_NOT_FOUND: Integer
22
+
23
+ # @rbs code: Integer
24
+ # @rbs message: String
25
+ # @rbs data: untyped
26
+ # @rbs return: void
27
+ def initialize: (code: Integer, message: String, ?data: untyped) -> void
28
+
29
+ # @dynamic code
30
+ attr_reader code: Integer
31
+
32
+ # @dynamic message
33
+ attr_reader message: String
34
+
35
+ # @dynamic data
36
+ attr_reader data: untyped
37
+
38
+ # @rbs return: Hash[String, untyped]
39
+ def to_h: () -> Hash[String, untyped]
40
+
41
+ # @rbs return: ACP::RequestError
42
+ def self.parse_error: () -> ACP::RequestError
43
+
44
+ # @rbs return: ACP::RequestError
45
+ def self.invalid_request: () -> ACP::RequestError
46
+
47
+ # @rbs return: ACP::RequestError
48
+ def self.method_not_found: () -> ACP::RequestError
49
+
50
+ # @rbs return: ACP::RequestError
51
+ def self.invalid_params: () -> ACP::RequestError
52
+
53
+ # @rbs return: ACP::RequestError
54
+ def self.internal_error: () -> ACP::RequestError
55
+
56
+ # @rbs return: ACP::RequestError
57
+ def self.request_cancelled: () -> ACP::RequestError
58
+
59
+ # @rbs return: ACP::RequestError
60
+ def self.auth_required: () -> ACP::RequestError
61
+
62
+ # @rbs uri: String?
63
+ # @rbs return: ACP::RequestError
64
+ def self.resource_not_found: (?String? uri) -> ACP::RequestError
65
+ end
@@ -1,16 +1,16 @@
1
1
  # Generated from lib/acp/transport/reply.rb with RBS::Inline
2
2
 
3
- # A request handler's result plus a callback the transport runs once that
4
- # result is on the wire, for messages the peer must only see after the reply.
3
+ # A request handler's outcome plus a callback the transport runs once that
4
+ # outcome is on the wire, for messages the peer must only see after the reply.
5
5
  class ACP::Transport::Reply
6
6
  # @dynamic result
7
- attr_reader result: ACP::Transport::Result
7
+ attr_reader result: ACP::Transport::Stdio::_ToH
8
8
 
9
9
  # @dynamic after
10
10
  attr_reader after: ^() -> void
11
11
 
12
- # @rbs result: ACP::Transport::Result
12
+ # @rbs result: ACP::Transport::Stdio::_ToH
13
13
  # @rbs after: ^() -> void
14
14
  # @rbs return: void
15
- def initialize: (ACP::Transport::Result result, after: ^() -> void) -> void
15
+ def initialize: (ACP::Transport::Stdio::_ToH result, after: ^() -> void) -> void
16
16
  end
@@ -20,15 +20,7 @@ class ACP::Transport::Stdio
20
20
 
21
21
  @input: _Reader
22
22
 
23
- INTERNAL_ERROR: Integer
24
-
25
- PARSE_ERROR: ACP::Transport::ResponseError
26
-
27
- INVALID_REQUEST: ACP::Transport::ResponseError
28
-
29
- METHOD_NOT_FOUND: ACP::Transport::ResponseError
30
-
31
- CONNECTION_CLOSED: ACP::Transport::ResponseError
23
+ CONNECTION_CLOSED: ACP::RequestError
32
24
 
33
25
  # @rbs input: _Reader
34
26
  # @rbs output: _Writer
@@ -45,8 +37,8 @@ class ACP::Transport::Stdio
45
37
 
46
38
  # @rbs method: String
47
39
  # @rbs params: untyped
48
- # @rbs return: ACP::Transport::Result
49
- def request: (String method, ?untyped params) -> ACP::Transport::Result
40
+ # @rbs return: (Hash[String, untyped] | ACP::RequestError)
41
+ def request: (String method, ?untyped params) -> (Hash[String, untyped] | ACP::RequestError)
50
42
 
51
43
  # @rbs method: String
52
44
  # @rbs params: untyped
@@ -68,8 +60,8 @@ class ACP::Transport::Stdio
68
60
  def route: (Hash[String, untyped] message, Hash[String, _Handler] requests, Hash[String, _NotificationHandler] notifications) -> void
69
61
 
70
62
  # @rbs line: String
71
- # @rbs return: Hash[String, untyped] | ACP::Transport::ResponseError
72
- def parse: (String line) -> (Hash[String, untyped] | ACP::Transport::ResponseError)
63
+ # @rbs return: Hash[String, untyped] | ACP::RequestError
64
+ def parse: (String line) -> (Hash[String, untyped] | ACP::RequestError)
73
65
 
74
66
  # @rbs handler: _Handler?
75
67
  # @rbs id: untyped
@@ -90,22 +82,25 @@ class ACP::Transport::Stdio
90
82
  #
91
83
  # @rbs handler: _Handler
92
84
  # @rbs params: untyped
93
- # @rbs return: ACP::Transport::Result | ACP::Transport::Reply
94
- def invoke: (_Handler handler, untyped params) -> (ACP::Transport::Result | ACP::Transport::Reply)
85
+ # @rbs return: (_ToH | ACP::RequestError | ACP::Transport::Reply)
86
+ def invoke: (_Handler handler, untyped params) -> (_ToH | ACP::RequestError | ACP::Transport::Reply)
95
87
 
88
+ # The success arm is whatever the handler returned, which the transport only
89
+ # knows serializes with to_h; RequestError picks the error arm of the reply.
90
+ #
96
91
  # @rbs id: untyped
97
- # @rbs result: ACP::Transport::Result
92
+ # @rbs outcome: (_ToH | ACP::RequestError)
98
93
  # @rbs return: void
99
- def reply: (untyped id, ACP::Transport::Result result) -> void
94
+ def reply: (untyped id, _ToH | ACP::RequestError outcome) -> void
100
95
 
101
96
  # @rbs queue: Thread::Queue
102
97
  # @rbs return: Integer?
103
98
  def register: (Thread::Queue queue) -> Integer?
104
99
 
105
100
  # @rbs id: untyped
106
- # @rbs result: ACP::Transport::Result
101
+ # @rbs result: (Hash[String, untyped] | ACP::RequestError)
107
102
  # @rbs return: void
108
- def settle: (untyped id, ACP::Transport::Result result) -> void
103
+ def settle: (untyped id, Hash[String, untyped] | ACP::RequestError result) -> void
109
104
 
110
105
  # @rbs return: void
111
106
  def close: () -> void
@@ -1,7 +1,7 @@
1
1
  class ACP::AgentConnection
2
2
  interface _Agent
3
- def new_session: (ACP::Types::NewSessionRequest) -> (ACP::Types::NewSessionResponse | ACP::Transport::ResponseError)
4
- def prompt: (ACP::Types::PromptRequest) -> (ACP::Types::PromptResponse | ACP::Transport::ResponseError)
3
+ def new_session: (ACP::Types::NewSessionRequest) -> (ACP::Types::NewSessionResponse | ACP::RequestError)
4
+ def prompt: (ACP::Types::PromptRequest) -> (ACP::Types::PromptResponse | ACP::RequestError)
5
5
  # Runs on the transport's reader thread, so it must return quickly.
6
6
  def cancel: (ACP::Types::CancelNotification) -> void
7
7
  # AgentConnection probes for the optional methods below.
@@ -9,35 +9,35 @@ class ACP::AgentConnection
9
9
  end
10
10
 
11
11
  interface _LoadSession
12
- def load_session: (ACP::Types::LoadSessionRequest) -> (ACP::Types::LoadSessionResponse | ACP::Transport::ResponseError)
12
+ def load_session: (ACP::Types::LoadSessionRequest) -> (ACP::Types::LoadSessionResponse | ACP::RequestError)
13
13
  end
14
14
 
15
15
  interface _ListSessions
16
- def list_sessions: (ACP::Types::ListSessionsRequest) -> (ACP::Types::ListSessionsResponse | ACP::Transport::ResponseError)
16
+ def list_sessions: (ACP::Types::ListSessionsRequest) -> (ACP::Types::ListSessionsResponse | ACP::RequestError)
17
17
  end
18
18
 
19
19
  interface _Authenticate
20
- def authenticate: (ACP::Types::AuthenticateRequest) -> (ACP::Types::AuthenticateResponse | ACP::Transport::ResponseError)
20
+ def authenticate: (ACP::Types::AuthenticateRequest) -> (ACP::Types::AuthenticateResponse | ACP::RequestError)
21
21
  end
22
22
 
23
23
  interface _ResumeSession
24
- def resume_session: (ACP::Types::ResumeSessionRequest) -> (ACP::Types::ResumeSessionResponse | ACP::Transport::ResponseError)
24
+ def resume_session: (ACP::Types::ResumeSessionRequest) -> (ACP::Types::ResumeSessionResponse | ACP::RequestError)
25
25
  end
26
26
 
27
27
  interface _CloseSession
28
- def close_session: (ACP::Types::CloseSessionRequest) -> (ACP::Types::CloseSessionResponse | ACP::Transport::ResponseError)
28
+ def close_session: (ACP::Types::CloseSessionRequest) -> (ACP::Types::CloseSessionResponse | ACP::RequestError)
29
29
  end
30
30
 
31
31
  interface _DeleteSession
32
- def delete_session: (ACP::Types::DeleteSessionRequest) -> (ACP::Types::DeleteSessionResponse | ACP::Transport::ResponseError)
32
+ def delete_session: (ACP::Types::DeleteSessionRequest) -> (ACP::Types::DeleteSessionResponse | ACP::RequestError)
33
33
  end
34
34
 
35
35
  interface _ChangeSessionMode
36
- def change_session_mode: (ACP::Types::SetSessionModeRequest) -> (ACP::Types::SetSessionModeResponse | ACP::Transport::ResponseError)
36
+ def change_session_mode: (ACP::Types::SetSessionModeRequest) -> (ACP::Types::SetSessionModeResponse | ACP::RequestError)
37
37
  end
38
38
 
39
39
  interface _ChangeSessionConfigOption
40
- def change_session_config_option: (ACP::Types::SetSessionConfigOptionRequest) -> (ACP::Types::SetSessionConfigOptionResponse | ACP::Transport::ResponseError)
40
+ def change_session_config_option: (ACP::Types::SetSessionConfigOptionRequest) -> (ACP::Types::SetSessionConfigOptionResponse | ACP::RequestError)
41
41
  end
42
42
 
43
43
  interface _FullAgent
@@ -66,19 +66,19 @@ class ACP::AgentConnection
66
66
  interface _Client
67
67
  def update: (String session_id, ACP::Types::SessionUpdate::t update) -> void
68
68
  def available_commands: (String session_id, Array[ACP::Types::AvailableCommand] commands) -> void
69
- def request_permission: (ACP::Types::RequestPermissionRequest) -> (ACP::Types::RequestPermissionResponse | ACP::Transport::ResponseError)
70
- def read_text_file: (ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::Transport::ResponseError)
71
- def write_text_file: (ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::Transport::ResponseError)
72
- def create_terminal: (ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::Transport::ResponseError)
73
- def terminal_output: (ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::Transport::ResponseError)
74
- def wait_for_terminal_exit: (ACP::Types::WaitForTerminalExitRequest) -> (ACP::Types::WaitForTerminalExitResponse | ACP::Transport::ResponseError)
75
- def kill_terminal: (ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::Transport::ResponseError)
76
- def release_terminal: (ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::Transport::ResponseError)
69
+ def request_permission: (ACP::Types::RequestPermissionRequest) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
70
+ def read_text_file: (ACP::Types::ReadTextFileRequest) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError)
71
+ def write_text_file: (ACP::Types::WriteTextFileRequest) -> (ACP::Types::WriteTextFileResponse | ACP::RequestError)
72
+ def create_terminal: (ACP::Types::CreateTerminalRequest) -> (ACP::Types::CreateTerminalResponse | ACP::RequestError)
73
+ def terminal_output: (ACP::Types::TerminalOutputRequest) -> (ACP::Types::TerminalOutputResponse | ACP::RequestError)
74
+ def wait_for_terminal_exit: (ACP::Types::WaitForTerminalExitRequest) -> (ACP::Types::WaitForTerminalExitResponse | ACP::RequestError)
75
+ def kill_terminal: (ACP::Types::KillTerminalRequest) -> (ACP::Types::KillTerminalResponse | ACP::RequestError)
76
+ def release_terminal: (ACP::Types::ReleaseTerminalRequest) -> (ACP::Types::ReleaseTerminalResponse | ACP::RequestError)
77
77
  def capabilities: () -> ACP::Types::ClientCapabilities?
78
78
  end
79
79
 
80
80
  interface _Peer
81
- def request: (String method, ?untyped params) -> ACP::Transport::Result
81
+ def request: (String method, ?untyped params) -> (Hash[String, untyped] | ACP::RequestError)
82
82
  def notify: (String method, ?untyped params) -> void
83
83
  end
84
84
 
@@ -0,0 +1,7 @@
1
+ class ACP::AgentProcess
2
+ # The stdlib RBS for Open3#popen2 models neither the leading env hash nor
3
+ # the err: option, so spawn calls it through this narrower type.
4
+ interface _Spawner
5
+ def call: (*untyped, **untyped) -> [IO, IO, Process::Waiter]
6
+ end
7
+ end
@@ -1,7 +1,7 @@
1
1
  class ACP::ClientConnection
2
2
  interface _PermissionHandler
3
3
  # Runs on its own thread, so it may block while the user decides.
4
- def call: (ACP::Types::RequestPermissionRequest) -> (ACP::Types::RequestPermissionResponse | ACP::Transport::ResponseError)
4
+ def call: (ACP::Types::RequestPermissionRequest) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
5
5
  end
6
6
 
7
7
  # Receives the session/update notifications that arrive outside a