ruby-utcp 1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/LICENSE +22 -0
- data/Makefile +226 -0
- data/README.md +331 -0
- data/examples/basic.rb +33 -0
- data/examples/cli.rb +32 -0
- data/examples/generated/__init__.py +1 -0
- data/examples/generated/utcp_pb2.py +46 -0
- data/examples/generated/utcp_pb2_grpc.py +183 -0
- data/examples/graphql.rb +15 -0
- data/examples/grpc.rb +42 -0
- data/examples/grpc_python.py +52 -0
- data/examples/http.rb +17 -0
- data/examples/mcp.rb +28 -0
- data/examples/servers/graphql_server.rb +39 -0
- data/examples/servers/grpc_server.py +97 -0
- data/examples/servers/grpc_server.rb +62 -0
- data/examples/servers/http_helpers.rb +34 -0
- data/examples/servers/http_server.rb +28 -0
- data/examples/servers/mcp_stdio_server.rb +43 -0
- data/examples/servers/requirements-grpc.txt +2 -0
- data/examples/servers/sse_server.rb +36 -0
- data/examples/servers/streamable_http_server.rb +39 -0
- data/examples/servers/tcp_server.rb +58 -0
- data/examples/servers/udp_server.rb +33 -0
- data/examples/servers/webrtc_server.rb +78 -0
- data/examples/servers/websocket_server.rb +92 -0
- data/examples/sse.rb +16 -0
- data/examples/streamable_http.rb +17 -0
- data/examples/tcp.rb +20 -0
- data/examples/text.rb +23 -0
- data/examples/udp.rb +18 -0
- data/examples/webrtc.rb +19 -0
- data/examples/websocket.rb +17 -0
- data/lib/ruby-utcp.rb +4 -0
- data/lib/utcp/client.rb +217 -0
- data/lib/utcp/config.rb +79 -0
- data/lib/utcp/errors.rb +48 -0
- data/lib/utcp/migration.rb +88 -0
- data/lib/utcp/models.rb +794 -0
- data/lib/utcp/openapi_converter.rb +179 -0
- data/lib/utcp/protocols/base.rb +97 -0
- data/lib/utcp/protocols/cli.rb +186 -0
- data/lib/utcp/protocols/file.rb +52 -0
- data/lib/utcp/protocols/graphql.rb +277 -0
- data/lib/utcp/protocols/grpc.rb +207 -0
- data/lib/utcp/protocols/http.rb +340 -0
- data/lib/utcp/protocols/http_stream_support.rb +122 -0
- data/lib/utcp/protocols/mcp.rb +339 -0
- data/lib/utcp/protocols/socket_support.rb +51 -0
- data/lib/utcp/protocols/sse.rb +107 -0
- data/lib/utcp/protocols/streamable_http.rb +78 -0
- data/lib/utcp/protocols/tcp.rb +143 -0
- data/lib/utcp/protocols/text.rb +44 -0
- data/lib/utcp/protocols/udp.rb +61 -0
- data/lib/utcp/protocols/webrtc.rb +217 -0
- data/lib/utcp/protocols/websocket.rb +350 -0
- data/lib/utcp/registry.rb +67 -0
- data/lib/utcp/repository.rb +137 -0
- data/lib/utcp/serializer.rb +71 -0
- data/lib/utcp/utils.rb +118 -0
- data/lib/utcp/variables.rb +170 -0
- data/lib/utcp/version.rb +6 -0
- data/lib/utcp.rb +70 -0
- data/proto/utcp.proto +31 -0
- metadata +148 -0
data/lib/utcp/utils.rb
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "yaml"
|
|
5
|
+
|
|
6
|
+
module UTCP
|
|
7
|
+
module ModelSerialization
|
|
8
|
+
def to_json(*arguments)
|
|
9
|
+
to_h.to_json(*arguments)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ==(other)
|
|
13
|
+
other.instance_of?(self.class) && other.to_h == to_h
|
|
14
|
+
end
|
|
15
|
+
alias eql? ==
|
|
16
|
+
|
|
17
|
+
def hash
|
|
18
|
+
[self.class, to_h].hash
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Utils
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
def stringify_keys(value)
|
|
26
|
+
case value
|
|
27
|
+
when Hash
|
|
28
|
+
value.each_with_object({}) { |(key, item), copy| copy[key.to_s] = stringify_keys(item) }
|
|
29
|
+
when Array
|
|
30
|
+
value.map { |item| stringify_keys(item) }
|
|
31
|
+
else
|
|
32
|
+
value
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def symbolize_keys(value)
|
|
37
|
+
value.each_with_object({}) { |(key, item), copy| copy[key.to_sym] = item }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def deep_copy(value)
|
|
41
|
+
case value
|
|
42
|
+
when Hash
|
|
43
|
+
value.each_with_object({}) { |(key, item), copy| copy[key] = deep_copy(item) }
|
|
44
|
+
when Array
|
|
45
|
+
value.map { |item| deep_copy(item) }
|
|
46
|
+
when String
|
|
47
|
+
value.dup
|
|
48
|
+
else
|
|
49
|
+
value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def compact_hash(hash)
|
|
54
|
+
hash.each_with_object({}) do |(key, value), result|
|
|
55
|
+
result[key] = value unless value.nil?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def required_string!(value, field)
|
|
60
|
+
return value if value.is_a?(String) && !value.empty?
|
|
61
|
+
|
|
62
|
+
raise ValidationError.new("must be a non-empty String", path: field)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def optional_string!(value, field)
|
|
66
|
+
return nil if value.nil?
|
|
67
|
+
return value if value.is_a?(String)
|
|
68
|
+
|
|
69
|
+
raise ValidationError.new("must be a String", path: field)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def hash!(value, field)
|
|
73
|
+
return value if value.is_a?(Hash)
|
|
74
|
+
|
|
75
|
+
raise ValidationError.new("must be an object", path: field)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def array!(value, field)
|
|
79
|
+
return value if value.is_a?(Array)
|
|
80
|
+
|
|
81
|
+
raise ValidationError.new("must be an array", path: field)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def parse_document(content, source: nil)
|
|
85
|
+
JSON.parse(content)
|
|
86
|
+
rescue JSON::ParserError => json_error
|
|
87
|
+
begin
|
|
88
|
+
parsed = YAML.safe_load(content, permitted_classes: [], permitted_symbols: [], aliases: false)
|
|
89
|
+
raise ValidationError, "document is empty" if parsed.nil?
|
|
90
|
+
|
|
91
|
+
parsed
|
|
92
|
+
rescue Psych::Exception, ValidationError => yaml_error
|
|
93
|
+
label = source ? " #{source}" : ""
|
|
94
|
+
raise SerializerValidationError,
|
|
95
|
+
"Could not parse#{label} as JSON or safe YAML: #{json_error.message}; #{yaml_error.message}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def load_document(path)
|
|
100
|
+
parse_document(File.read(path, mode: "r:bom|utf-8"), source: path)
|
|
101
|
+
rescue Errno::ENOENT => error
|
|
102
|
+
raise ValidationError, "File not found: #{path} (#{error.message})"
|
|
103
|
+
rescue Errno::EACCES => error
|
|
104
|
+
raise ValidationError, "Cannot read file: #{path} (#{error.message})"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def json_value(value)
|
|
108
|
+
case value
|
|
109
|
+
when String, Numeric, TrueClass, FalseClass, NilClass
|
|
110
|
+
value
|
|
111
|
+
when Hash, Array
|
|
112
|
+
value
|
|
113
|
+
else
|
|
114
|
+
value.to_s
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UTCP
|
|
4
|
+
class VariableLoader
|
|
5
|
+
attr_reader :variable_loader_type
|
|
6
|
+
|
|
7
|
+
def self.from_h(value, root_dir: Dir.pwd)
|
|
8
|
+
return value if value.respond_to?(:get)
|
|
9
|
+
|
|
10
|
+
data = Utils.stringify_keys(Utils.hash!(value, "variable loader"))
|
|
11
|
+
case data["variable_loader_type"]
|
|
12
|
+
when "dotenv"
|
|
13
|
+
DotenvVariableLoader.new(
|
|
14
|
+
env_file_path: data["env_file_path"] || ".env",
|
|
15
|
+
root_dir: root_dir
|
|
16
|
+
)
|
|
17
|
+
else
|
|
18
|
+
raise ValidationError.new(
|
|
19
|
+
"unsupported variable loader type #{data['variable_loader_type'].inspect}",
|
|
20
|
+
path: "variable_loader_type"
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def initialize(variable_loader_type)
|
|
26
|
+
@variable_loader_type = variable_loader_type
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get(_key)
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class DotenvVariableLoader < VariableLoader
|
|
35
|
+
attr_reader :env_file_path
|
|
36
|
+
|
|
37
|
+
def initialize(env_file_path: ".env", root_dir: Dir.pwd)
|
|
38
|
+
super("dotenv")
|
|
39
|
+
@env_file_path = File.expand_path(env_file_path, root_dir)
|
|
40
|
+
@variables = nil
|
|
41
|
+
@mutex = Mutex.new
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def get(key)
|
|
45
|
+
load_variables.fetch(key.to_s, nil)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reload!
|
|
49
|
+
@mutex.synchronize { @variables = nil }
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_h
|
|
54
|
+
{ "variable_loader_type" => variable_loader_type, "env_file_path" => env_file_path }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def load_variables
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
@variables ||= parse_file
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def parse_file
|
|
66
|
+
return {} unless File.file?(env_file_path)
|
|
67
|
+
|
|
68
|
+
File.readlines(env_file_path, chomp: true).each_with_object({}) do |line, values|
|
|
69
|
+
stripped = line.strip
|
|
70
|
+
next if stripped.empty? || stripped.start_with?("#")
|
|
71
|
+
|
|
72
|
+
stripped = stripped.sub(/\Aexport\s+/, "")
|
|
73
|
+
key, raw = stripped.split("=", 2)
|
|
74
|
+
next unless raw && key.match?(/\A[A-Za-z_][A-Za-z0-9_]*\z/)
|
|
75
|
+
|
|
76
|
+
values[key] = parse_value(raw.strip)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def parse_value(raw)
|
|
81
|
+
if raw.length >= 2 && raw.start_with?("'") && raw.end_with?("'")
|
|
82
|
+
raw[1..-2]
|
|
83
|
+
elsif raw.length >= 2 && raw.start_with?("\"") && raw.end_with?("\"")
|
|
84
|
+
raw[1..-2].gsub(/\\n/, "\n").gsub(/\\r/, "\r").gsub(/\\t/, "\t").gsub(/\\\"/, "\"")
|
|
85
|
+
else
|
|
86
|
+
raw.sub(/\s+#.*\z/, "")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class VariableSubstitutor
|
|
92
|
+
VARIABLE_PATTERN = /\$\{([A-Za-z0-9_]+)\}|\$([A-Za-z0-9_]+)/.freeze
|
|
93
|
+
JSON_REF_PATTERN = /\$ref(?![A-Za-z0-9_])/.freeze
|
|
94
|
+
|
|
95
|
+
def substitute(value, config, namespace = nil)
|
|
96
|
+
validate_namespace!(namespace)
|
|
97
|
+
case value
|
|
98
|
+
when String
|
|
99
|
+
return value if value.match?(JSON_REF_PATTERN)
|
|
100
|
+
|
|
101
|
+
value.gsub(VARIABLE_PATTERN) do
|
|
102
|
+
key = Regexp.last_match(1) || Regexp.last_match(2)
|
|
103
|
+
next Regexp.last_match(0) if key.match?(/\ACMD_\d+_OUTPUT\z/)
|
|
104
|
+
|
|
105
|
+
resolve(key, config, namespace)
|
|
106
|
+
end
|
|
107
|
+
when Hash
|
|
108
|
+
value.each_with_object({}) do |(key, item), result|
|
|
109
|
+
result[key] = substitute(item, config, namespace)
|
|
110
|
+
end
|
|
111
|
+
when Array
|
|
112
|
+
value.map { |item| substitute(item, config, namespace) }
|
|
113
|
+
else
|
|
114
|
+
value
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def find_required_variables(value, namespace = nil)
|
|
119
|
+
validate_namespace!(namespace)
|
|
120
|
+
names = collect_required_variables(value)
|
|
121
|
+
names.map { |name| namespace ? "#{encoded_namespace(namespace)}_#{name}" : name }.uniq
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def resolve(key, config, namespace)
|
|
127
|
+
candidates = namespace ? ["#{encoded_namespace(namespace)}_#{key}", key] : [key]
|
|
128
|
+
candidates.each do |candidate|
|
|
129
|
+
direct = config.variables[candidate]
|
|
130
|
+
return direct.to_s unless direct.nil?
|
|
131
|
+
|
|
132
|
+
config.load_variables_from.each do |loader|
|
|
133
|
+
loaded = loader.get(candidate)
|
|
134
|
+
return loaded.to_s unless loaded.nil?
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
environment = ENV[candidate]
|
|
138
|
+
return environment unless environment.nil?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
raise VariableNotFoundError, candidates.first
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def collect_required_variables(value)
|
|
145
|
+
case value
|
|
146
|
+
when String
|
|
147
|
+
return [] if value.match?(JSON_REF_PATTERN)
|
|
148
|
+
|
|
149
|
+
value.scan(VARIABLE_PATTERN).map { |groups| groups.compact.first }
|
|
150
|
+
.reject { |name| name.match?(/\ACMD_\d+_OUTPUT\z/) }
|
|
151
|
+
when Hash
|
|
152
|
+
value.values.flat_map { |item| collect_required_variables(item) }
|
|
153
|
+
when Array
|
|
154
|
+
value.flat_map { |item| collect_required_variables(item) }
|
|
155
|
+
else
|
|
156
|
+
[]
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def encoded_namespace(namespace)
|
|
161
|
+
namespace.to_s.gsub("_", "__")
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def validate_namespace!(namespace)
|
|
165
|
+
return if namespace.nil? || namespace.to_s.match?(/\A[[:alnum:]_]+\z/)
|
|
166
|
+
|
|
167
|
+
raise ArgumentError, "variable namespace may only contain letters, numbers, and underscores"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
data/lib/utcp/version.rb
ADDED
data/lib/utcp.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "utcp/version"
|
|
4
|
+
require_relative "utcp/errors"
|
|
5
|
+
require_relative "utcp/utils"
|
|
6
|
+
require_relative "utcp/registry"
|
|
7
|
+
require_relative "utcp/models"
|
|
8
|
+
require_relative "utcp/repository"
|
|
9
|
+
require_relative "utcp/variables"
|
|
10
|
+
require_relative "utcp/config"
|
|
11
|
+
require_relative "utcp/serializer"
|
|
12
|
+
require_relative "utcp/protocols/base"
|
|
13
|
+
require_relative "utcp/openapi_converter"
|
|
14
|
+
require_relative "utcp/migration"
|
|
15
|
+
require_relative "utcp/protocols/http"
|
|
16
|
+
require_relative "utcp/protocols/http_stream_support"
|
|
17
|
+
require_relative "utcp/protocols/sse"
|
|
18
|
+
require_relative "utcp/protocols/streamable_http"
|
|
19
|
+
require_relative "utcp/protocols/cli"
|
|
20
|
+
require_relative "utcp/protocols/text"
|
|
21
|
+
require_relative "utcp/protocols/file"
|
|
22
|
+
require_relative "utcp/protocols/websocket"
|
|
23
|
+
require_relative "utcp/protocols/graphql"
|
|
24
|
+
require_relative "utcp/protocols/grpc"
|
|
25
|
+
require_relative "utcp/protocols/socket_support"
|
|
26
|
+
require_relative "utcp/protocols/tcp"
|
|
27
|
+
require_relative "utcp/protocols/udp"
|
|
28
|
+
require_relative "utcp/protocols/mcp"
|
|
29
|
+
require_relative "utcp/protocols/webrtc"
|
|
30
|
+
require_relative "utcp/client"
|
|
31
|
+
|
|
32
|
+
module UTCP
|
|
33
|
+
register_auth("api_key", ApiKeyAuth)
|
|
34
|
+
register_auth("basic", BasicAuth)
|
|
35
|
+
register_auth("oauth2", OAuth2Auth)
|
|
36
|
+
|
|
37
|
+
register_call_template("http", HttpCallTemplate)
|
|
38
|
+
register_call_template("sse", SseCallTemplate)
|
|
39
|
+
register_call_template("streamable_http", StreamableHttpCallTemplate)
|
|
40
|
+
register_call_template("http_stream", StreamableHttpCallTemplate)
|
|
41
|
+
register_call_template("cli", CliCallTemplate)
|
|
42
|
+
register_call_template("websocket", WebSocketCallTemplate)
|
|
43
|
+
register_call_template("grpc", GrpcCallTemplate)
|
|
44
|
+
register_call_template("graphql", GraphQLCallTemplate)
|
|
45
|
+
register_call_template("tcp", TcpCallTemplate)
|
|
46
|
+
register_call_template("udp", UdpCallTemplate)
|
|
47
|
+
register_call_template("webrtc", WebRtcCallTemplate)
|
|
48
|
+
register_call_template("mcp", McpCallTemplate)
|
|
49
|
+
register_call_template("text", TextCallTemplate)
|
|
50
|
+
register_call_template("file", FileCallTemplate)
|
|
51
|
+
|
|
52
|
+
register_protocol("http", HTTPProtocol.new)
|
|
53
|
+
register_protocol("sse", SSEProtocol.new)
|
|
54
|
+
streamable_http_protocol = StreamableHTTPProtocol.new
|
|
55
|
+
register_protocol("streamable_http", streamable_http_protocol)
|
|
56
|
+
register_protocol("http_stream", streamable_http_protocol)
|
|
57
|
+
register_protocol("cli", CLIProtocol.new)
|
|
58
|
+
register_protocol("websocket", WebSocketProtocol.new)
|
|
59
|
+
register_protocol("grpc", GRPCProtocol.new)
|
|
60
|
+
register_protocol("graphql", GraphQLProtocol.new)
|
|
61
|
+
register_protocol("tcp", TCPProtocol.new)
|
|
62
|
+
register_protocol("udp", UDPProtocol.new)
|
|
63
|
+
register_protocol("webrtc", WebRTCProtocol.new)
|
|
64
|
+
register_protocol("mcp", MCPProtocol.new)
|
|
65
|
+
register_protocol("text", TextProtocol.new)
|
|
66
|
+
register_protocol("file", FileProtocol.new)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Conventional Ruby casing alias for applications that do not preserve acronyms.
|
|
70
|
+
Utcp = UTCP unless defined?(Utcp)
|
data/proto/utcp.proto
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package grpcpb;
|
|
4
|
+
|
|
5
|
+
// Minimal UTCP gRPC contract used by the Ruby client and example servers.
|
|
6
|
+
message Empty {}
|
|
7
|
+
|
|
8
|
+
message Tool {
|
|
9
|
+
string name = 1;
|
|
10
|
+
string description = 2;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
message Manual {
|
|
14
|
+
string version = 1;
|
|
15
|
+
repeated Tool tools = 2;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
message ToolCallRequest {
|
|
19
|
+
string tool = 1;
|
|
20
|
+
string args_json = 2;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
message ToolCallResponse {
|
|
24
|
+
string result_json = 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
service UTCPService {
|
|
28
|
+
rpc GetManual(Empty) returns (Manual);
|
|
29
|
+
rpc CallTool(ToolCallRequest) returns (ToolCallResponse);
|
|
30
|
+
rpc CallToolStream(ToolCallRequest) returns (stream ToolCallResponse);
|
|
31
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby-utcp
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- ruby-utcp contributors
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: minitest
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '5.0'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '7.0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '5.0'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '7.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: rake
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '12.0'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '14.0'
|
|
42
|
+
type: :development
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '12.0'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '14.0'
|
|
52
|
+
description: Discover, search, and call UTCP 1.1 tools over pluggable native protocols.
|
|
53
|
+
email:
|
|
54
|
+
- maintainers@utcp.io
|
|
55
|
+
executables: []
|
|
56
|
+
extensions: []
|
|
57
|
+
extra_rdoc_files: []
|
|
58
|
+
files:
|
|
59
|
+
- CHANGELOG.md
|
|
60
|
+
- LICENSE
|
|
61
|
+
- Makefile
|
|
62
|
+
- README.md
|
|
63
|
+
- examples/basic.rb
|
|
64
|
+
- examples/cli.rb
|
|
65
|
+
- examples/generated/__init__.py
|
|
66
|
+
- examples/generated/utcp_pb2.py
|
|
67
|
+
- examples/generated/utcp_pb2_grpc.py
|
|
68
|
+
- examples/graphql.rb
|
|
69
|
+
- examples/grpc.rb
|
|
70
|
+
- examples/grpc_python.py
|
|
71
|
+
- examples/http.rb
|
|
72
|
+
- examples/mcp.rb
|
|
73
|
+
- examples/servers/graphql_server.rb
|
|
74
|
+
- examples/servers/grpc_server.py
|
|
75
|
+
- examples/servers/grpc_server.rb
|
|
76
|
+
- examples/servers/http_helpers.rb
|
|
77
|
+
- examples/servers/http_server.rb
|
|
78
|
+
- examples/servers/mcp_stdio_server.rb
|
|
79
|
+
- examples/servers/requirements-grpc.txt
|
|
80
|
+
- examples/servers/sse_server.rb
|
|
81
|
+
- examples/servers/streamable_http_server.rb
|
|
82
|
+
- examples/servers/tcp_server.rb
|
|
83
|
+
- examples/servers/udp_server.rb
|
|
84
|
+
- examples/servers/webrtc_server.rb
|
|
85
|
+
- examples/servers/websocket_server.rb
|
|
86
|
+
- examples/sse.rb
|
|
87
|
+
- examples/streamable_http.rb
|
|
88
|
+
- examples/tcp.rb
|
|
89
|
+
- examples/text.rb
|
|
90
|
+
- examples/udp.rb
|
|
91
|
+
- examples/webrtc.rb
|
|
92
|
+
- examples/websocket.rb
|
|
93
|
+
- lib/ruby-utcp.rb
|
|
94
|
+
- lib/utcp.rb
|
|
95
|
+
- lib/utcp/client.rb
|
|
96
|
+
- lib/utcp/config.rb
|
|
97
|
+
- lib/utcp/errors.rb
|
|
98
|
+
- lib/utcp/migration.rb
|
|
99
|
+
- lib/utcp/models.rb
|
|
100
|
+
- lib/utcp/openapi_converter.rb
|
|
101
|
+
- lib/utcp/protocols/base.rb
|
|
102
|
+
- lib/utcp/protocols/cli.rb
|
|
103
|
+
- lib/utcp/protocols/file.rb
|
|
104
|
+
- lib/utcp/protocols/graphql.rb
|
|
105
|
+
- lib/utcp/protocols/grpc.rb
|
|
106
|
+
- lib/utcp/protocols/http.rb
|
|
107
|
+
- lib/utcp/protocols/http_stream_support.rb
|
|
108
|
+
- lib/utcp/protocols/mcp.rb
|
|
109
|
+
- lib/utcp/protocols/socket_support.rb
|
|
110
|
+
- lib/utcp/protocols/sse.rb
|
|
111
|
+
- lib/utcp/protocols/streamable_http.rb
|
|
112
|
+
- lib/utcp/protocols/tcp.rb
|
|
113
|
+
- lib/utcp/protocols/text.rb
|
|
114
|
+
- lib/utcp/protocols/udp.rb
|
|
115
|
+
- lib/utcp/protocols/webrtc.rb
|
|
116
|
+
- lib/utcp/protocols/websocket.rb
|
|
117
|
+
- lib/utcp/registry.rb
|
|
118
|
+
- lib/utcp/repository.rb
|
|
119
|
+
- lib/utcp/serializer.rb
|
|
120
|
+
- lib/utcp/utils.rb
|
|
121
|
+
- lib/utcp/variables.rb
|
|
122
|
+
- lib/utcp/version.rb
|
|
123
|
+
- proto/utcp.proto
|
|
124
|
+
homepage: https://www.utcp.io
|
|
125
|
+
licenses:
|
|
126
|
+
- MIT
|
|
127
|
+
metadata:
|
|
128
|
+
homepage_uri: https://www.utcp.io
|
|
129
|
+
source_code_uri: https://github.com/universal-tool-calling-protocol/ruby-utcp
|
|
130
|
+
documentation_uri: https://www.utcp.io/implementation
|
|
131
|
+
rdoc_options: []
|
|
132
|
+
require_paths:
|
|
133
|
+
- lib
|
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 2.6.0
|
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '0'
|
|
144
|
+
requirements: []
|
|
145
|
+
rubygems_version: 4.0.20
|
|
146
|
+
specification_version: 4
|
|
147
|
+
summary: A Ruby implementation of the Universal Tool Calling Protocol
|
|
148
|
+
test_files: []
|