acp_ruby 0.1.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.
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # AUTO-GENERATED from meta.json — DO NOT EDIT
4
+
5
+ module AgentClientProtocol
6
+ PROTOCOL_VERSION = 1
7
+
8
+ AGENT_METHODS = {
9
+ authenticate: "authenticate",
10
+ initialize: "initialize",
11
+ session_cancel: "session/cancel",
12
+ session_load: "session/load",
13
+ session_new: "session/new",
14
+ session_prompt: "session/prompt",
15
+ session_set_config_option: "session/set_config_option",
16
+ session_set_mode: "session/set_mode",
17
+ }.freeze
18
+
19
+ CLIENT_METHODS = {
20
+ fs_read_text_file: "fs/read_text_file",
21
+ fs_write_text_file: "fs/write_text_file",
22
+ session_request_permission: "session/request_permission",
23
+ session_update: "session/update",
24
+ terminal_create: "terminal/create",
25
+ terminal_kill: "terminal/kill",
26
+ terminal_output: "terminal/output",
27
+ terminal_release: "terminal/release",
28
+ terminal_wait_for_exit: "terminal/wait_for_exit",
29
+ }.freeze
30
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentClientProtocol
4
+ class Router
5
+ def initialize
6
+ @request_handlers = {}
7
+ @notification_handlers = {}
8
+ @ext_method_handler = nil
9
+ @ext_notification_handler = nil
10
+ end
11
+
12
+ def on_request(method, request_class: nil, response_class: nil, optional: false, &handler)
13
+ @request_handlers[method] = {
14
+ handler: handler,
15
+ request_class: request_class,
16
+ response_class: response_class,
17
+ optional: optional
18
+ }
19
+ end
20
+
21
+ def on_notification(method, request_class: nil, &handler)
22
+ @notification_handlers[method] = {
23
+ handler: handler,
24
+ request_class: request_class
25
+ }
26
+ end
27
+
28
+ def on_ext_method(&handler)
29
+ @ext_method_handler = handler
30
+ end
31
+
32
+ def on_ext_notification(&handler)
33
+ @ext_notification_handler = handler
34
+ end
35
+
36
+ def call(method, params, is_notification)
37
+ if is_notification
38
+ dispatch_notification(method, params)
39
+ else
40
+ dispatch_request(method, params)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def dispatch_request(method, params)
47
+ # Extension methods start with _
48
+ if method.start_with?("_")
49
+ if @ext_method_handler
50
+ return @ext_method_handler.call(method, params)
51
+ else
52
+ raise RequestError.method_not_found(method)
53
+ end
54
+ end
55
+
56
+ entry = @request_handlers[method]
57
+ unless entry
58
+ raise RequestError.method_not_found(method)
59
+ end
60
+
61
+ begin
62
+ deserialized = deserialize_params(params, entry[:request_class])
63
+ result = entry[:handler].call(deserialized)
64
+
65
+ if result.nil? && entry[:optional]
66
+ return nil
67
+ end
68
+
69
+ serialize_result(result)
70
+ rescue NotImplementedError
71
+ if entry[:optional]
72
+ nil
73
+ else
74
+ raise RequestError.method_not_found(method)
75
+ end
76
+ end
77
+ end
78
+
79
+ def dispatch_notification(method, params)
80
+ if method.start_with?("_")
81
+ @ext_notification_handler&.call(method, params)
82
+ return nil
83
+ end
84
+
85
+ entry = @notification_handlers[method]
86
+ return nil unless entry
87
+
88
+ deserialized = deserialize_params(params, entry[:request_class])
89
+ entry[:handler].call(deserialized)
90
+ nil
91
+ end
92
+
93
+ def deserialize_params(params, klass)
94
+ return params unless klass && params.is_a?(Hash)
95
+
96
+ klass.from_hash(params)
97
+ end
98
+
99
+ def serialize_result(result)
100
+ case result
101
+ when Schema::BaseModel then result.to_h
102
+ when Hash then result
103
+ when nil then nil
104
+ else result
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentClientProtocol
4
+ module Schema
5
+ class BaseModel
6
+ class << self
7
+ def properties
8
+ @properties ||= {}
9
+ end
10
+
11
+ def required_properties
12
+ @required_properties ||= Set.new
13
+ end
14
+
15
+ # Register a discriminator field + value for this class.
16
+ # E.g., `discriminator "type", "text"` means to_h includes {"type" => "text"}
17
+ def discriminator(field = nil, value = nil)
18
+ if field
19
+ @discriminator_field = field
20
+ @discriminator_value = value
21
+ end
22
+ @discriminator_field ? [@discriminator_field, @discriminator_value] : nil
23
+ end
24
+
25
+ def property(ruby_name, json_name: nil, type: nil, default: :_no_default, required: false)
26
+ json_name ||= to_camel_case(ruby_name.to_s)
27
+ properties[ruby_name] = {json_name: json_name, type: type, default: default}
28
+ required_properties << ruby_name if required
29
+ attr_reader ruby_name
30
+ end
31
+
32
+ def from_hash(hash)
33
+ return nil if hash.nil?
34
+
35
+ kwargs = {}
36
+ properties.each do |ruby_name, meta|
37
+ json_name = meta[:json_name]
38
+ if hash.key?(json_name)
39
+ kwargs[ruby_name] = deserialize_value(hash[json_name], meta[:type])
40
+ elsif hash.key?(ruby_name.to_s)
41
+ kwargs[ruby_name] = deserialize_value(hash[ruby_name.to_s], meta[:type])
42
+ end
43
+ end
44
+ new(**kwargs)
45
+ end
46
+
47
+ def inherited(subclass)
48
+ super
49
+ subclass.instance_variable_set(:@properties, properties.dup)
50
+ subclass.instance_variable_set(:@required_properties, required_properties.dup)
51
+ end
52
+
53
+ private
54
+
55
+ def to_camel_case(str)
56
+ return str if str == "_meta"
57
+
58
+ parts = str.split("_")
59
+ parts[0] + parts[1..].map(&:capitalize).join
60
+ end
61
+
62
+ def deserialize_value(value, type)
63
+ return nil if value.nil?
64
+
65
+ case type
66
+ when Class
67
+ if type < BaseModel
68
+ type.from_hash(value)
69
+ else
70
+ value
71
+ end
72
+ when :content_block
73
+ ContentBlock.parse(value)
74
+ when :session_update
75
+ SessionUpdate.parse(value)
76
+ when :tool_call_content
77
+ ToolCallContent.parse(value)
78
+ when :permission_outcome
79
+ RequestPermissionOutcome.parse(value)
80
+ when Array
81
+ if type[0] == :array && value.is_a?(::Array)
82
+ value.map { |v| deserialize_value(v, type[1]) }
83
+ else
84
+ value
85
+ end
86
+ when :hash
87
+ value
88
+ else
89
+ value
90
+ end
91
+ end
92
+ end
93
+
94
+ def initialize(**kwargs)
95
+ self.class.properties.each do |ruby_name, meta|
96
+ if kwargs.key?(ruby_name)
97
+ instance_variable_set(:"@#{ruby_name}", kwargs[ruby_name])
98
+ elsif meta[:default] != :_no_default
99
+ default = meta[:default]
100
+ default = default.dup if default.is_a?(::Hash) || default.is_a?(::Array)
101
+ instance_variable_set(:"@#{ruby_name}", default)
102
+ end
103
+ end
104
+ end
105
+
106
+ def to_h
107
+ result = {}
108
+
109
+ # Include discriminator if set on this class
110
+ disc = self.class.discriminator
111
+ if disc
112
+ result[disc[0]] = disc[1]
113
+ end
114
+
115
+ self.class.properties.each do |ruby_name, meta|
116
+ value = instance_variable_get(:"@#{ruby_name}")
117
+ next if value.nil? && !self.class.required_properties.include?(ruby_name)
118
+
119
+ result[meta[:json_name]] = serialize_value(value)
120
+ end
121
+ result
122
+ end
123
+
124
+ def to_json(*)
125
+ JSON.generate(to_h, *)
126
+ end
127
+
128
+ def ==(other)
129
+ other.is_a?(self.class) && to_h == other.to_h
130
+ end
131
+
132
+ def hash
133
+ [self.class, to_h].hash
134
+ end
135
+
136
+ def eql?(other)
137
+ self == other
138
+ end
139
+
140
+ def inspect
141
+ pairs = self.class.properties.keys.map { |k| "#{k}: #{instance_variable_get(:"@#{k}").inspect}" }
142
+ "#<#{self.class.name} #{pairs.join(", ")}>"
143
+ end
144
+
145
+ private
146
+
147
+ def serialize_value(value)
148
+ case value
149
+ when BaseModel then value.to_h
150
+ when ::Array then value.map { |v| serialize_value(v) }
151
+ when ::Hash then value.transform_values { |v| serialize_value(v) }
152
+ else
153
+ value.respond_to?(:to_h) && !value.is_a?(Numeric) ? value.to_h : value
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end