acp-sdk 0.9.0 → 0.11.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 (174) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +20 -8
  4. data/lib/acp/agent_connection/client.rb +31 -13
  5. data/lib/acp/agent_connection/optional_method/spec.rb +42 -0
  6. data/lib/acp/agent_connection/optional_method.rb +36 -0
  7. data/lib/acp/agent_connection.rb +67 -20
  8. data/lib/acp/agent_process.rb +0 -13
  9. data/lib/acp/client_connection/streams.rb +183 -0
  10. data/lib/acp/client_connection.rb +280 -338
  11. data/lib/acp/protocol.rb +33 -0
  12. data/lib/acp/request_error.rb +13 -13
  13. data/lib/acp/transport/cancellation.rb +13 -3
  14. data/lib/acp/transport/reply.rb +0 -2
  15. data/lib/acp/transport/stderr_logger.rb +1 -2
  16. data/lib/acp/transport/stdio.rb +25 -26
  17. data/lib/acp/types/audio_content.rb +3 -46
  18. data/lib/acp/types/auth_method_terminal.rb +3 -59
  19. data/lib/acp/types/available_commands_update.rb +3 -32
  20. data/lib/acp/types/boolean_property_schema.rb +3 -41
  21. data/lib/acp/types/check.rb +210 -0
  22. data/lib/acp/types/config_option_update.rb +3 -32
  23. data/lib/acp/types/content.rb +3 -29
  24. data/lib/acp/types/{elicitation_url_mode → create_elicitation_request/mode/form}/scope.rb +1 -1
  25. data/lib/acp/types/create_elicitation_request/mode/form.rb +3 -3
  26. data/lib/acp/types/{elicitation_form_mode → create_elicitation_request/mode/url}/scope.rb +1 -1
  27. data/lib/acp/types/create_elicitation_request/mode/url.rb +3 -3
  28. data/lib/acp/types/current_mode_update.rb +3 -29
  29. data/lib/acp/types/diff.rb +3 -41
  30. data/lib/acp/types/elicitation_accept_action.rb +3 -26
  31. data/lib/acp/types/elicitation_form_mode.rb +3 -33
  32. data/lib/acp/types/elicitation_url_mode.rb +3 -35
  33. data/lib/acp/types/embedded_resource.rb +3 -44
  34. data/lib/acp/types/image_content.rb +3 -58
  35. data/lib/acp/types/integer_property_schema.rb +3 -60
  36. data/lib/acp/types/mcp_server_http.rb +3 -44
  37. data/lib/acp/types/mcp_server_sse.rb +3 -44
  38. data/lib/acp/types/multi_select_property_schema.rb +3 -70
  39. data/lib/acp/types/number_property_schema.rb +3 -60
  40. data/lib/acp/types/parse_error.rb +37 -0
  41. data/lib/acp/types/plan.rb +3 -29
  42. data/lib/acp/types/resource_link.rb +3 -79
  43. data/lib/acp/types/selected_permission_outcome.rb +3 -26
  44. data/lib/acp/types/session_config_boolean.rb +3 -21
  45. data/lib/acp/types/session_config_select.rb +3 -33
  46. data/lib/acp/types/session_info_update.rb +3 -42
  47. data/lib/acp/types/string_multi_select_items.rb +3 -29
  48. data/lib/acp/types/string_property_schema.rb +3 -105
  49. data/lib/acp/types/terminal.rb +3 -29
  50. data/lib/acp/types/text_content.rb +3 -40
  51. data/lib/acp/types/tool_call.rb +3 -115
  52. data/lib/acp/types/unstable/compaction_summary_chunk.rb +3 -35
  53. data/lib/acp/types/unstable/compaction_update.rb +3 -56
  54. data/lib/acp/types/unstable/idle_state_update.rb +3 -40
  55. data/lib/acp/types/unstable/mcp_server_acp.rb +3 -35
  56. data/lib/acp/types/unstable/message_mcp_response/result.rb +1 -1
  57. data/lib/acp/types/unstable/nes_edit_suggestion.rb +3 -61
  58. data/lib/acp/types/unstable/nes_jump_suggestion.rb +3 -45
  59. data/lib/acp/types/unstable/nes_rename_suggestion.rb +3 -51
  60. data/lib/acp/types/unstable/nes_search_and_replace_suggestion.rb +3 -60
  61. data/lib/acp/types/unstable/notice.rb +3 -41
  62. data/lib/acp/types/unstable/plan_file.rb +3 -35
  63. data/lib/acp/types/unstable/plan_items.rb +3 -38
  64. data/lib/acp/types/unstable/plan_markdown.rb +3 -35
  65. data/lib/acp/types/unstable/plan_removed.rb +3 -26
  66. data/lib/acp/types/unstable/plan_update.rb +3 -33
  67. data/lib/acp/types/unstable/requires_action_state_update.rb +3 -21
  68. data/lib/acp/types/unstable/running_state_update.rb +3 -21
  69. data/lib/acp/types/unstable/session_message.rb +3 -56
  70. data/lib/acp/types/unstable/session_message_chunk.rb +3 -53
  71. data/lib/acp/types/unstable/subagent_update.rb +3 -65
  72. data/lib/acp/types/unstable/unknown_state_update.rb +3 -21
  73. data/lib/acp/types/unstable.rb +20 -20
  74. data/lib/acp/types/usage_update.rb +3 -41
  75. data/lib/acp/types.rb +7 -246
  76. data/lib/acp/version.rb +1 -1
  77. data/sig/generated/acp/agent_connection/client.rbs +25 -15
  78. data/sig/generated/acp/agent_connection/optional_method/spec.rbs +32 -0
  79. data/sig/generated/acp/agent_connection/optional_method.rbs +3 -0
  80. data/sig/generated/acp/agent_connection.rbs +34 -13
  81. data/sig/generated/acp/agent_process.rbs +0 -13
  82. data/sig/generated/acp/client_connection/streams.rbs +94 -0
  83. data/sig/generated/acp/client_connection.rbs +128 -131
  84. data/sig/generated/acp/protocol.rbs +9 -0
  85. data/sig/generated/acp/request_error.rbs +11 -13
  86. data/sig/generated/acp/transport/cancellation.rbs +9 -3
  87. data/sig/generated/acp/transport/reply.rbs +0 -2
  88. data/sig/generated/acp/transport/stderr_logger.rbs +1 -2
  89. data/sig/generated/acp/transport/stdio.rbs +14 -22
  90. data/sig/generated/acp/types/audio_content.rbs +1 -27
  91. data/sig/generated/acp/types/auth_method_terminal.rbs +1 -35
  92. data/sig/generated/acp/types/available_commands_update.rbs +1 -19
  93. data/sig/generated/acp/types/boolean_property_schema.rbs +1 -27
  94. data/sig/generated/acp/types/check.rbs +115 -0
  95. data/sig/generated/acp/types/config_option_update.rbs +1 -19
  96. data/sig/generated/acp/types/content.rbs +1 -19
  97. data/sig/generated/acp/types/{elicitation_url_mode → create_elicitation_request/mode/form}/scope.rbs +2 -2
  98. data/sig/generated/acp/types/create_elicitation_request/mode/form.rbs +3 -3
  99. data/sig/generated/acp/types/{elicitation_form_mode → create_elicitation_request/mode/url}/scope.rbs +2 -2
  100. data/sig/generated/acp/types/create_elicitation_request/mode/url.rbs +3 -3
  101. data/sig/generated/acp/types/current_mode_update.rbs +1 -19
  102. data/sig/generated/acp/types/diff.rbs +1 -27
  103. data/sig/generated/acp/types/elicitation_accept_action.rbs +1 -15
  104. data/sig/generated/acp/types/elicitation_form_mode.rbs +1 -19
  105. data/sig/generated/acp/types/elicitation_url_mode.rbs +1 -23
  106. data/sig/generated/acp/types/embedded_resource.rbs +1 -23
  107. data/sig/generated/acp/types/image_content.rbs +1 -31
  108. data/sig/generated/acp/types/integer_property_schema.rbs +1 -35
  109. data/sig/generated/acp/types/mcp_server_http.rbs +1 -27
  110. data/sig/generated/acp/types/mcp_server_sse.rbs +1 -27
  111. data/sig/generated/acp/types/multi_select_property_schema.rbs +1 -39
  112. data/sig/generated/acp/types/number_property_schema.rbs +1 -35
  113. data/sig/generated/acp/types/parse_error.rbs +22 -0
  114. data/sig/generated/acp/types/plan.rbs +1 -19
  115. data/sig/generated/acp/types/resource_link.rbs +1 -43
  116. data/sig/generated/acp/types/selected_permission_outcome.rbs +1 -19
  117. data/sig/generated/acp/types/session_config_boolean.rbs +1 -15
  118. data/sig/generated/acp/types/session_config_select.rbs +1 -19
  119. data/sig/generated/acp/types/session_info_update.rbs +1 -23
  120. data/sig/generated/acp/types/string_multi_select_items.rbs +1 -19
  121. data/sig/generated/acp/types/string_property_schema.rbs +1 -51
  122. data/sig/generated/acp/types/terminal.rbs +1 -19
  123. data/sig/generated/acp/types/text_content.rbs +1 -23
  124. data/sig/generated/acp/types/tool_call.rbs +1 -51
  125. data/sig/generated/acp/types/unstable/compaction_summary_chunk.rbs +1 -23
  126. data/sig/generated/acp/types/unstable/compaction_update.rbs +1 -31
  127. data/sig/generated/acp/types/unstable/idle_state_update.rbs +1 -23
  128. data/sig/generated/acp/types/unstable/mcp_server_acp.rbs +1 -23
  129. data/sig/generated/acp/types/unstable/nes_edit_suggestion.rbs +1 -31
  130. data/sig/generated/acp/types/unstable/nes_jump_suggestion.rbs +1 -27
  131. data/sig/generated/acp/types/unstable/nes_rename_suggestion.rbs +1 -31
  132. data/sig/generated/acp/types/unstable/nes_search_and_replace_suggestion.rbs +1 -35
  133. data/sig/generated/acp/types/unstable/notice.rbs +1 -27
  134. data/sig/generated/acp/types/unstable/plan_file.rbs +1 -23
  135. data/sig/generated/acp/types/unstable/plan_items.rbs +1 -23
  136. data/sig/generated/acp/types/unstable/plan_markdown.rbs +1 -23
  137. data/sig/generated/acp/types/unstable/plan_removed.rbs +1 -19
  138. data/sig/generated/acp/types/unstable/plan_update.rbs +1 -19
  139. data/sig/generated/acp/types/unstable/requires_action_state_update.rbs +1 -15
  140. data/sig/generated/acp/types/unstable/running_state_update.rbs +1 -15
  141. data/sig/generated/acp/types/unstable/session_message.rbs +1 -31
  142. data/sig/generated/acp/types/unstable/session_message_chunk.rbs +1 -31
  143. data/sig/generated/acp/types/unstable/subagent_update.rbs +1 -35
  144. data/sig/generated/acp/types/unstable/unknown_state_update.rbs +1 -15
  145. data/sig/generated/acp/types/usage_update.rbs +1 -27
  146. data/sig/generated/acp/types.rbs +6 -143
  147. data/sig/manual/acp/agent_connection.rbs +28 -28
  148. data/sig/manual/acp/client_connection.rbs +7 -2
  149. data/sig/manual/acp/{agent_connection/optional_method/logout.rbs → protocol.rbs} +3 -3
  150. data/sig/manual/acp/transport/stdio.rbs +0 -2
  151. data/sig/manual/acp/transport.rbs +25 -2
  152. metadata +17 -29
  153. data/lib/acp/agent_connection/optional_method/authenticate.rb +0 -21
  154. data/lib/acp/agent_connection/optional_method/close_session.rb +0 -21
  155. data/lib/acp/agent_connection/optional_method/delete_session.rb +0 -21
  156. data/lib/acp/agent_connection/optional_method/list_sessions.rb +0 -21
  157. data/lib/acp/agent_connection/optional_method/load_session.rb +0 -21
  158. data/lib/acp/agent_connection/optional_method/logout.rb +0 -21
  159. data/lib/acp/agent_connection/optional_method/resume_session.rb +0 -21
  160. data/lib/acp/types/content_chunk.rb +0 -40
  161. data/sig/generated/acp/agent_connection/optional_method/authenticate.rbs +0 -13
  162. data/sig/generated/acp/agent_connection/optional_method/close_session.rbs +0 -13
  163. data/sig/generated/acp/agent_connection/optional_method/delete_session.rbs +0 -13
  164. data/sig/generated/acp/agent_connection/optional_method/list_sessions.rbs +0 -13
  165. data/sig/generated/acp/agent_connection/optional_method/load_session.rbs +0 -13
  166. data/sig/generated/acp/agent_connection/optional_method/logout.rbs +0 -13
  167. data/sig/generated/acp/agent_connection/optional_method/resume_session.rbs +0 -13
  168. data/sig/generated/acp/types/content_chunk.rbs +0 -25
  169. data/sig/manual/acp/agent_connection/optional_method/authenticate.rbs +0 -6
  170. data/sig/manual/acp/agent_connection/optional_method/close_session.rbs +0 -6
  171. data/sig/manual/acp/agent_connection/optional_method/delete_session.rbs +0 -6
  172. data/sig/manual/acp/agent_connection/optional_method/list_sessions.rbs +0 -6
  173. data/sig/manual/acp/agent_connection/optional_method/load_session.rbs +0 -6
  174. data/sig/manual/acp/agent_connection/optional_method/resume_session.rbs +0 -6
data/lib/acp/types.rb CHANGED
@@ -1,251 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ACP::Types
4
- # Raised by the generated from_h when a param does not match its schema
5
- # type; the connection boundaries rescue it into an invalid-params reply
6
- # that names the failing path.
7
- class ParseError < StandardError
8
- # @rbs @segments: Array[String | Integer]
9
- # @rbs @detail: String
10
-
11
- # @rbs segments: Array[String | Integer]
12
- # @rbs detail: String
13
- # @rbs return: void
14
- def initialize(segments, detail)
15
- @segments = segments.freeze
16
- @detail = detail
17
- super("#{path}: #{detail}")
18
- end
19
-
20
- # @dynamic segments
21
- attr_reader :segments #: Array[String | Integer]
22
-
23
- # @rbs return: String
24
- def path
25
- segments.each_with_index.map do |segment, index|
26
- if segment.is_a?(Integer) then "[#{segment}]"
27
- elsif index.zero? then segment
28
- else ".#{segment}"
29
- end
30
- end.join
31
- end
32
-
33
- # Prepends a container's segments so nested failures report an absolute path.
34
- #
35
- # @rbs *segments: (String | Integer)
36
- # @rbs return: ACP::Types::ParseError
37
- def prefix(*segments)
38
- ParseError.new([*segments, *@segments], @detail)
39
- end
40
- end
41
-
42
- # The guards the generated from_h methods call. Each takes the fetched value
43
- # and the path to it, and raises ParseError naming that path when the value
44
- # does not match the schema type. Nested from_h failures come back with the
45
- # field path prepended, so the reported path is absolute.
46
- module Check
47
- # @rbs hash: Hash[String, untyped]
48
- # @rbs key: String
49
- # @rbs return: untyped
50
- def self.key(hash, key)
51
- hash.fetch(key)
52
- rescue KeyError
53
- raise ParseError.new([key], 'is required')
54
- end
55
-
56
- # @rbs value: untyped
57
- # @rbs path: String | Array[String | Integer]
58
- # @rbs allow_nil: bool
59
- # @rbs allow_unset: bool
60
- # @rbs return: untyped
61
- def self.string(value, path, allow_nil: false, allow_unset: false)
62
- return value if value.is_a?(String) || skipped?(value, allow_nil, allow_unset)
63
-
64
- raise ParseError.new(segments(path), "expected String, got #{describe(value)}")
65
- end
66
-
67
- # @rbs value: untyped
68
- # @rbs path: String | Array[String | Integer]
69
- # @rbs allow_nil: bool
70
- # @rbs allow_unset: bool
71
- # @rbs return: untyped
72
- def self.boolean(value, path, allow_nil: false, allow_unset: false)
73
- return value if value == true || value == false || skipped?(value, allow_nil, allow_unset)
74
-
75
- raise ParseError.new(segments(path), "expected boolean, got #{describe(value)}")
76
- end
77
-
78
- # @rbs value: untyped
79
- # @rbs path: String | Array[String | Integer]
80
- # @rbs min: Integer?
81
- # @rbs max: Integer?
82
- # @rbs allow_nil: bool
83
- # @rbs allow_unset: bool
84
- # @rbs return: untyped
85
- def self.integer(value, path, min: nil, max: nil, allow_nil: false, allow_unset: false)
86
- return value if (value.is_a?(Integer) && within?(value, min, max)) || skipped?(value, allow_nil, allow_unset)
87
-
88
- raise ParseError.new(segments(path), "expected #{bounded('Integer', min, max)}, got #{describe(value)}")
89
- end
90
-
91
- # @rbs value: untyped
92
- # @rbs path: String | Array[String | Integer]
93
- # @rbs min: Integer?
94
- # @rbs max: Integer?
95
- # @rbs allow_nil: bool
96
- # @rbs allow_unset: bool
97
- # @rbs return: untyped
98
- def self.number(value, path, min: nil, max: nil, allow_nil: false, allow_unset: false)
99
- return value if (value.is_a?(Numeric) && within?(value, min, max)) || skipped?(value, allow_nil, allow_unset)
100
-
101
- raise ParseError.new(segments(path), "expected #{bounded('Numeric', min, max)}, got #{describe(value)}")
102
- end
103
-
104
- # @rbs value: untyped
105
- # @rbs path: String | Array[String | Integer]
106
- # @rbs values: Array[untyped]
107
- # @rbs allow_nil: bool
108
- # @rbs allow_unset: bool
109
- # @rbs return: untyped
110
- def self.enum(value, path, values, allow_nil: false, allow_unset: false)
111
- return value if values.include?(value) || skipped?(value, allow_nil, allow_unset)
112
-
113
- expected = values.map(&:inspect).join(', ')
114
- raise ParseError.new(segments(path), "expected one of #{expected}, got #{describe(value)}")
115
- end
116
-
117
- # @rbs value: untyped
118
- # @rbs path: String | Array[String | Integer]
119
- # @rbs classes: Array[untyped]
120
- # @rbs allow_nil: bool
121
- # @rbs allow_unset: bool
122
- # @rbs ?&items: (untyped, Array[String | Integer]) -> void
123
- # @rbs return: untyped
124
- def self.one_of(value, path, classes, allow_nil: false, allow_unset: false, &items)
125
- return value if skipped?(value, allow_nil, allow_unset)
126
-
127
- matched = classes.any? { |klass| value.is_a?(klass) }
128
- unless matched
129
- raise ParseError.new(segments(path), "expected #{classes.map(&:name).join(' | ')}, got #{describe(value)}")
130
- end
131
-
132
- return value unless value.is_a?(Array) && items
133
-
134
- value.each_with_index { |item, index| yield(item, [*segments(path), index]) }
135
- value
136
- end
137
-
138
- # @rbs value: untyped
139
- # @rbs path: String | Array[String | Integer]
140
- # @rbs allow_nil: bool
141
- # @rbs allow_unset: bool
142
- # @rbs &check: (untyped, Array[String | Integer]) -> void
143
- # @rbs return: untyped
144
- def self.hash(value, path, allow_nil: false, allow_unset: false, &check)
145
- return value if skipped?(value, allow_nil, allow_unset)
146
- raise ParseError.new(segments(path), "expected object, got #{describe(value)}") unless value.is_a?(Hash)
147
-
148
- parsed = {} #: Hash[String, untyped]
149
- value.each { |key, item| parsed[key] = yield(item, [*segments(path), key]) }
150
- parsed
151
- end
152
-
153
- # @rbs value: untyped
154
- # @rbs path: String | Array[String | Integer]
155
- # @rbs allow_nil: bool
156
- # @rbs allow_unset: bool
157
- # @rbs &check: (untyped, Array[String | Integer]) -> void
158
- # @rbs return: untyped
159
- def self.array(value, path, allow_nil: false, allow_unset: false, &check)
160
- return value if skipped?(value, allow_nil, allow_unset)
161
- raise ParseError.new(segments(path), "expected array, got #{describe(value)}") unless value.is_a?(Array)
162
-
163
- value.each_with_index.map { |item, index| yield(item, [*segments(path), index]) }
164
- end
165
-
166
- # @rbs value: untyped
167
- # @rbs path: String | Array[String | Integer]
168
- # @rbs klass: untyped
169
- # @rbs allow_nil: bool
170
- # @rbs allow_unset: bool
171
- # @rbs return: untyped
172
- def self.object(value, path, klass, allow_nil: false, allow_unset: false)
173
- return value if skipped?(value, allow_nil, allow_unset)
174
- raise ParseError.new(segments(path), "expected object, got #{describe(value)}") unless value.is_a?(Hash)
175
-
176
- begin
177
- klass.from_h(value)
178
- rescue ParseError => e
179
- raise e.prefix(*segments(path))
180
- end
181
- end
182
-
183
- # @rbs value: untyped
184
- # @rbs path: String | Array[String | Integer]
185
- # @rbs klass: untyped
186
- # @rbs allow_nil: bool
187
- # @rbs allow_unset: bool
188
- # @rbs return: untyped
189
- def self.objects(value, path, klass, allow_nil: false, allow_unset: false)
190
- return value if skipped?(value, allow_nil, allow_unset)
191
- raise ParseError.new(segments(path), "expected array, got #{describe(value)}") unless value.is_a?(Array)
192
-
193
- value.each_with_index do |item, index|
194
- next if item.is_a?(Hash)
195
-
196
- raise ParseError.new([*segments(path), index], "expected object, got #{describe(item)}")
197
- end
198
-
199
- begin
200
- klass.from_a(value)
201
- rescue ParseError => e
202
- raise e.prefix(*segments(path))
203
- end
204
- end
205
-
206
- # @rbs value: untyped
207
- # @rbs allow_nil: bool
208
- # @rbs allow_unset: bool
209
- # @rbs return: bool
210
- def self.skipped?(value, allow_nil, allow_unset)
211
- (value.nil? && allow_nil) || (allow_unset && value.equal?(:unset))
212
- end
213
-
214
- # @rbs path: String | Array[String | Integer]
215
- # @rbs return: Array[String | Integer]
216
- def self.segments(path)
217
- path.is_a?(Array) ? path : [path]
218
- end
219
-
220
- # @rbs value: untyped
221
- # @rbs return: String
222
- def self.describe(value)
223
- case value
224
- when nil then 'null'
225
- when true then 'true'
226
- when false then 'false'
227
- else value.class.name
228
- end
229
- end
230
-
231
- # @rbs value: Numeric
232
- # @rbs min: Integer?
233
- # @rbs max: Integer?
234
- # @rbs return: bool
235
- def self.within?(value, min, max)
236
- (min.nil? || value >= min) && (max.nil? || value <= max)
237
- end
238
-
239
- # @rbs name: String
240
- # @rbs min: Integer?
241
- # @rbs max: Integer?
242
- # @rbs return: String
243
- def self.bounded(name, min, max)
244
- if min && max then "#{name} between #{min} and #{max}"
245
- elsif min then "#{name} >= #{min}"
246
- elsif max then "#{name} <= #{max}"
247
- else name
248
- end
249
- end
4
+ # Lives on ACP::Types rather than ACP::Types::Unstable because the callers
5
+ # run in the stable-only load, where even naming the inner module would raise
6
+ # NameError.
7
+ #
8
+ # @rbs return: bool
9
+ def self.unstable_enabled?
10
+ !defined?(ACP::Types::Unstable).nil?
250
11
  end
251
12
  end
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.9.0'
4
+ VERSION = '0.11.0'
5
5
  end
@@ -1,14 +1,17 @@
1
1
  # Generated from lib/acp/agent_connection/client.rb with RBS::Inline
2
2
 
3
3
  class ACP::AgentConnection::Client
4
- @peer: ACP::AgentConnection::_Peer
4
+ @mcp_advertised: bool
5
+
6
+ @peer: ACP::Transport::_Peer
5
7
 
6
8
  # @dynamic capabilities, capabilities=
7
9
  attr_accessor capabilities: ACP::Types::ClientCapabilities?
8
10
 
9
- # @rbs peer: ACP::AgentConnection::_Peer
11
+ # @rbs peer: ACP::Transport::_Peer
12
+ # @rbs mcp_advertised: bool
10
13
  # @rbs return: void
11
- def initialize: (peer: ACP::AgentConnection::_Peer) -> void
14
+ def initialize: (peer: ACP::Transport::_Peer, ?mcp_advertised: bool) -> void
12
15
 
13
16
  # @rbs session_id: String
14
17
  # @rbs update: ACP::Types::SessionUpdate::t
@@ -20,13 +23,18 @@ class ACP::AgentConnection::Client
20
23
  # @rbs return: void
21
24
  def available_commands: (String session_id, Array[ACP::Types::AvailableCommand] commands) -> void
22
25
 
23
- # Blocks the calling thread until the client answers or the connection
24
- # closes.
25
- #
26
26
  # @rbs request: ACP::Types::RequestPermissionRequest
27
27
  # @rbs return: ACP::Types::RequestPermissionResponse | ACP::RequestError
28
28
  def request_permission: (ACP::Types::RequestPermissionRequest request) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
29
29
 
30
+ # @rbs return: void
31
+ def cancel_requests: () -> void
32
+
33
+ # Always false off a handler thread.
34
+ #
35
+ # @rbs return: bool
36
+ def cancelled?: () -> bool
37
+
30
38
  # @rbs request: ACP::Types::ReadTextFileRequest
31
39
  # @rbs return: ACP::Types::ReadTextFileResponse | ACP::RequestError
32
40
  def read_text_file: (ACP::Types::ReadTextFileRequest request) -> (ACP::Types::ReadTextFileResponse | ACP::RequestError)
@@ -63,9 +71,11 @@ class ACP::AgentConnection::Client
63
71
  # @rbs return: void
64
72
  def complete_elicitation: (ACP::Types::CompleteElicitationNotification notification) -> void
65
73
 
66
- # Sends an extension request, keyed by its raw `_`-prefixed wire name, and
67
- # returns the client's reply as-is: extension methods have no schema to
68
- # parse the result into.
74
+ # @rbs request: ACP::Types::Unstable::MessageMcpRequest
75
+ # @rbs return: (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError)
76
+ def mcp_message: (ACP::Types::Unstable::MessageMcpRequest request) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError)
77
+
78
+ # Extension methods have no schema to parse the result into.
69
79
  #
70
80
  # @rbs method: String
71
81
  # @rbs params: untyped
@@ -80,14 +90,14 @@ class ACP::AgentConnection::Client
80
90
  private
81
91
 
82
92
  # @rbs rpc_method: String
83
- # @rbs type: ACP::AgentConnection::_Parser
84
- # @rbs request: ACP::AgentConnection::_Response
93
+ # @rbs type: ACP::Transport::_Parser
94
+ # @rbs request: ACP::Transport::_Response
85
95
  # @rbs return: untyped
86
- def call: (String rpc_method, ACP::AgentConnection::_Parser type, ACP::AgentConnection::_Response request) -> untyped
96
+ def call: (String rpc_method, ACP::Transport::_Parser type, ACP::Transport::_Response request) -> untyped
87
97
 
88
98
  # @rbs rpc_method: String
89
- # @rbs type: ACP::AgentConnection::_Parser
90
- # @rbs request: ACP::AgentConnection::_Response
99
+ # @rbs type: ACP::Transport::_Parser
100
+ # @rbs request: ACP::Transport::_Response
91
101
  # @rbs return: untyped
92
- def terminal_call: (String rpc_method, ACP::AgentConnection::_Parser type, ACP::AgentConnection::_Response request) -> untyped
102
+ def terminal_call: (String rpc_method, ACP::Transport::_Parser type, ACP::Transport::_Response request) -> untyped
93
103
  end
@@ -0,0 +1,32 @@
1
+ # Generated from lib/acp/agent_connection/optional_method/spec.rb with RBS::Inline
2
+
3
+ class ACP::AgentConnection::OptionalMethod::Spec
4
+ # @dynamic rpc_method
5
+ attr_reader rpc_method: String
6
+
7
+ # @dynamic agent_method
8
+ attr_reader agent_method: Symbol
9
+
10
+ # @dynamic path
11
+ attr_reader path: Array[Symbol]
12
+
13
+ # @rbs rpc_method: String
14
+ # @rbs agent_method: Symbol
15
+ # @rbs path: Array[Symbol]
16
+ # @rbs return: void
17
+ def initialize: (rpc_method: String, agent_method: Symbol, path: Array[Symbol]) -> void
18
+
19
+ # Readers missing along the chain count as unadvertised, so the stable
20
+ # capabilities answer false for the unstable-only paths (fork, providers).
21
+ #
22
+ # @rbs initialize_response: ACP::Types::InitializeResponse
23
+ # @rbs return: bool
24
+ def advertised?: (ACP::Types::InitializeResponse initialize_response) -> bool
25
+
26
+ private
27
+
28
+ # @rbs node: untyped
29
+ # @rbs name: Symbol
30
+ # @rbs return: untyped
31
+ def follow: (untyped node, Symbol name) -> untyped
32
+ end
@@ -1,4 +1,7 @@
1
1
  # Generated from lib/acp/agent_connection/optional_method.rb with RBS::Inline
2
2
 
3
3
  module ACP::AgentConnection::OptionalMethod
4
+ SPECS: Array[Spec]
5
+
6
+ UNSTABLE_SPECS: Array[Spec]
4
7
  end
@@ -15,18 +15,14 @@ class ACP::AgentConnection
15
15
 
16
16
  @capabilities: ACP::Types::AgentCapabilities
17
17
 
18
- @transport: ACP::AgentConnection::_Transport
19
-
20
- PROTOCOL_VERSION: Integer
21
-
22
- OPTIONAL: Array[ACP::AgentConnection::_OptionalMethod]
18
+ @transport: ACP::Transport::_Transport
23
19
 
24
20
  # The schema has no initialize capability for modes or config options: an
25
21
  # agent offers them per session, in its session responses, so they are
26
22
  # routed whenever the agent defines them.
27
23
  PER_SESSION: Hash[String, Symbol]
28
24
 
29
- # @rbs transport: ACP::AgentConnection::_Transport
25
+ # @rbs transport: ACP::Transport::_Transport
30
26
  # @rbs capabilities: ACP::Types::AgentCapabilities
31
27
  # @rbs agent_info: ACP::Types::Implementation?
32
28
  # @rbs auth_methods: Array[ACP::Types::AuthMethod::t]
@@ -35,7 +31,7 @@ class ACP::AgentConnection
35
31
  # @rbs logger: ACP::Transport::_Logger
36
32
  # @rbs &factory: (ACP::AgentConnection::Client) -> ACP::AgentConnection::_Agent
37
33
  # @rbs return: void
38
- def initialize: (transport: ACP::AgentConnection::_Transport, capabilities: ACP::Types::AgentCapabilities, ?agent_info: ACP::Types::Implementation?, ?auth_methods: Array[ACP::Types::AuthMethod::t], ?extension_requests: Hash[String, ^(untyped) -> untyped], ?extension_notifications: Hash[String, ^(untyped) -> void], ?logger: ACP::Transport::_Logger) { (ACP::AgentConnection::Client) -> ACP::AgentConnection::_Agent } -> void
34
+ def initialize: (transport: ACP::Transport::_Transport, capabilities: ACP::Types::AgentCapabilities, ?agent_info: ACP::Types::Implementation?, ?auth_methods: Array[ACP::Types::AuthMethod::t], ?extension_requests: Hash[String, ^(untyped) -> untyped], ?extension_notifications: Hash[String, ^(untyped) -> void], ?logger: ACP::Transport::_Logger) { (ACP::AgentConnection::Client) -> ACP::AgentConnection::_Agent } -> void
39
35
 
40
36
  # @rbs return: Thread
41
37
  def start: () -> Thread
@@ -44,8 +40,23 @@ class ACP::AgentConnection
44
40
 
45
41
  # @rbs agent: ACP::AgentConnection::_Agent
46
42
  # @rbs client: ACP::AgentConnection::Client
47
- # @rbs return: Hash[String, ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)]
48
- def requests: (ACP::AgentConnection::_Agent agent, ACP::AgentConnection::Client client) -> Hash[String, ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)]
43
+ # @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)]
45
+
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]
49
60
 
50
61
  # @rbs agent: ACP::AgentConnection::_Agent
51
62
  # @rbs return: Hash[String, ^(untyped) -> void]
@@ -58,12 +69,22 @@ class ACP::AgentConnection
58
69
  # @rbs return: void
59
70
  def cancel: (ACP::AgentConnection::_Agent agent, untyped params) -> void
60
71
 
72
+ # @rbs return: bool
73
+ def mcp_acp_advertised?: () -> bool
74
+
75
+ # A notification has no reply to carry a parse failure.
76
+ #
77
+ # @rbs agent: ACP::AgentConnection::_Agent
78
+ # @rbs params: untyped
79
+ # @rbs return: void
80
+ def mcp_message_notification: (ACP::AgentConnection::_Agent agent, untyped params) -> void
81
+
61
82
  # Generated from_h raises on a missing key or a value of the wrong shape.
62
83
  #
63
- # @rbs type: ACP::AgentConnection::_Parser
64
- # @rbs &handle: (untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
65
- # @rbs return: ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
66
- def route: (ACP::AgentConnection::_Parser type) { (untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply) } -> ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)
84
+ # @rbs type: ACP::Transport::_Parser
85
+ # @rbs &handle: (untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
86
+ # @rbs return: ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
87
+ def route: (ACP::Transport::_Parser type) { (untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply) } -> ^(untyped) -> (ACP::Transport::_Response | ACP::RequestError | ACP::Transport::Reply)
67
88
 
68
89
  # @rbs client: ACP::AgentConnection::Client
69
90
  # @rbs request: ACP::Types::InitializeRequest
@@ -1,7 +1,5 @@
1
1
  # Generated from lib/acp/agent_process.rb with RBS::Inline
2
2
 
3
- # A child agent process and the ACP::ClientConnection wired to its stdio.
4
- # Spawn one with ACP::AgentProcess.spawn.
5
3
  class ACP::AgentProcess
6
4
  @stderr: String?
7
5
 
@@ -27,16 +25,9 @@ class ACP::AgentProcess
27
25
  # @dynamic connection
28
26
  attr_reader connection: ACP::ClientConnection
29
27
 
30
- # Child stderr captured when spawn was given stderr: :capture, else nil.
31
- #
32
28
  # @dynamic stderr
33
29
  attr_reader stderr: String?
34
30
 
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
31
  # @rbs command: String
41
32
  # @rbs *args: String
42
33
  # @rbs env: Hash[String, String]?
@@ -48,10 +39,6 @@ class ACP::AgentProcess
48
39
  # @rbs return: (untyped | ACP::AgentProcess)
49
40
  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
41
 
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
42
  # @rbs return: void
56
43
  def terminate: () -> void
57
44
 
@@ -0,0 +1,94 @@
1
+ # Generated from lib/acp/client_connection/streams.rb with RBS::Inline
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
+ class ACP::ClientConnection::Streams
7
+ CANCELLED: ACP::Types::RequestPermissionResponse
8
+
9
+ @outstanding_elicitations: Hash[String, bool]
10
+
11
+ @pending_permissions: Hash[String, Array[Thread::Queue]]
12
+
13
+ @streams: Hash[String, Thread::Queue]
14
+
15
+ @lock: Thread::Mutex
16
+
17
+ @logger: ACP::Transport::_Logger
18
+
19
+ @complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
20
+
21
+ @updates: ACP::ClientConnection::_UpdateHandler
22
+
23
+ @permission: ACP::ClientConnection::_PermissionHandler
24
+
25
+ @sender: ACP::ClientConnection::Streams::_Sender
26
+
27
+ # @rbs sender: ACP::ClientConnection::Streams::_Sender
28
+ # @rbs permission: ACP::ClientConnection::_PermissionHandler
29
+ # @rbs updates: ACP::ClientConnection::_UpdateHandler
30
+ # @rbs logger: ACP::Transport::_Logger
31
+ # @rbs complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
32
+ # @rbs return: void
33
+ def initialize: (sender: ACP::ClientConnection::Streams::_Sender, permission: ACP::ClientConnection::_PermissionHandler, updates: ACP::ClientConnection::_UpdateHandler, logger: ACP::Transport::_Logger, ?complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?) -> void
34
+
35
+ # The request waits on its own thread so the caller's thread can yield each
36
+ # update as it arrives. The reader thread queues an update before it settles
37
+ # a reply sent after it, so the queue closes only after the last one.
38
+ #
39
+ # @rbs session_id: String
40
+ # @rbs method: String
41
+ # @rbs params: Hash[String, untyped]
42
+ # @rbs &block: (ACP::Types::SessionUpdate::t) -> void
43
+ # @rbs return: (Hash[String, untyped] | ACP::RequestError)
44
+ def stream: (String session_id, String method, Hash[String, untyped] params) { (ACP::Types::SessionUpdate::t) -> void } -> (Hash[String, untyped] | ACP::RequestError)
45
+
46
+ # Pushes under the lock so a stream cannot close its queue between the
47
+ # lookup and the push. A malformed notification has no reply to carry the
48
+ # failure.
49
+ #
50
+ # @rbs params: untyped
51
+ # @rbs return: void
52
+ def dispatch: (untyped params) -> void
53
+
54
+ # The handler runs on its own thread so a cancelled request is answered
55
+ # without waiting for it, and whatever it returns after that is pushed to a
56
+ # queue nobody reads.
57
+ #
58
+ # @rbs params: untyped
59
+ # @rbs return: (ACP::Types::RequestPermissionResponse | ACP::RequestError)
60
+ def request_permission: (untyped params) -> (ACP::Types::RequestPermissionResponse | ACP::RequestError)
61
+
62
+ # The spec requires a pending session/request_permission to be answered with
63
+ # the cancelled outcome once the turn is cancelled, so every queue registered
64
+ # for the session gets one before this returns.
65
+ #
66
+ # @rbs session_id: String
67
+ # @rbs return: void
68
+ def cancel: (String session_id) -> void
69
+
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
+ private
84
+
85
+ # @rbs session_id: String
86
+ # @rbs replies: Thread::Queue
87
+ # @rbs return: void
88
+ def register_permission: (String session_id, Thread::Queue replies) -> void
89
+
90
+ # @rbs session_id: String
91
+ # @rbs replies: Thread::Queue
92
+ # @rbs return: void
93
+ def unregister_permission: (String session_id, Thread::Queue replies) -> void
94
+ end