hermes-client 0.0.0 → 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.
- checksums.yaml +4 -4
- data/.yardopts +11 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.md +21 -0
- data/README.md +105 -7
- data/lib/hermes-client.rb +3 -8
- data/lib/hermes_agent/client/configuration.rb +98 -0
- data/lib/hermes_agent/client/conversation.rb +134 -0
- data/lib/hermes_agent/client/entities/capabilities.rb +289 -0
- data/lib/hermes_agent/client/entities/chat_completion.rb +370 -0
- data/lib/hermes_agent/client/entities/health.rb +140 -0
- data/lib/hermes_agent/client/entities/job.rb +394 -0
- data/lib/hermes_agent/client/entities/model.rb +68 -0
- data/lib/hermes_agent/client/entities/response.rb +429 -0
- data/lib/hermes_agent/client/entities/run.rb +427 -0
- data/lib/hermes_agent/client/entities/session_headers.rb +78 -0
- data/lib/hermes_agent/client/entity.rb +89 -0
- data/lib/hermes_agent/client/errors.rb +228 -0
- data/lib/hermes_agent/client/resources/capabilities.rb +34 -0
- data/lib/hermes_agent/client/resources/chat.rb +139 -0
- data/lib/hermes_agent/client/resources/health.rb +49 -0
- data/lib/hermes_agent/client/resources/jobs.rb +213 -0
- data/lib/hermes_agent/client/resources/models.rb +38 -0
- data/lib/hermes_agent/client/resources/responses.rb +204 -0
- data/lib/hermes_agent/client/resources/runs.rb +156 -0
- data/lib/hermes_agent/client/stream.rb +166 -0
- data/lib/hermes_agent/client/transport.rb +281 -0
- data/lib/hermes_agent/client/util.rb +56 -0
- data/lib/hermes_agent/client/version.rb +11 -0
- data/lib/hermes_agent/client.rb +137 -0
- metadata +72 -11
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Require "http/cookie" explicitly before requiring "http", to avoid a
|
|
4
|
+
# "circular dependency" warning due to the way the "http" gem uses autoload.
|
|
5
|
+
require "http/cookie"
|
|
6
|
+
require "http"
|
|
7
|
+
require "json"
|
|
8
|
+
|
|
9
|
+
require "hermes_agent/client/util"
|
|
10
|
+
|
|
11
|
+
module HermesAgent
|
|
12
|
+
class Client
|
|
13
|
+
##
|
|
14
|
+
# The single chokepoint for HTTP communication with the server.
|
|
15
|
+
#
|
|
16
|
+
# Transport owns the underlying `http` gem connection, attaches the
|
|
17
|
+
# `Authorization` header, serializes and parses JSON, and maps non-2xx
|
|
18
|
+
# responses to the {Error} hierarchy. Resource objects build paths and
|
|
19
|
+
# delegate here.
|
|
20
|
+
#
|
|
21
|
+
# The connection is **persistent and scoped to the transport instance**: a
|
|
22
|
+
# single keep-alive `HTTP::Session`, built lazily on first use, is reused
|
|
23
|
+
# across every request so the TCP/TLS handshake happens once rather than per
|
|
24
|
+
# call. The `http` gem transparently reopens the connection when it has been
|
|
25
|
+
# closed by the server, has exceeded its keep-alive lifetime, or a prior
|
|
26
|
+
# request failed (timeout or socket error), so callers never manage the
|
|
27
|
+
# connection lifecycle. Because the session is per-instance and holds live
|
|
28
|
+
# connection state, a transport — like the {Client} that owns it — is **not
|
|
29
|
+
# thread-safe**; multithreaded callers should use a separate client per
|
|
30
|
+
# thread.
|
|
31
|
+
#
|
|
32
|
+
# @private
|
|
33
|
+
class Transport
|
|
34
|
+
##
|
|
35
|
+
# The outcome of a request whose response headers matter to the caller:
|
|
36
|
+
# the parsed body — or, for a streaming request, the live chunk
|
|
37
|
+
# enumerator — paired with the response headers as a Hash with downcased
|
|
38
|
+
# string keys. Returned by {#post} and {#stream_post}; the header-agnostic
|
|
39
|
+
# {#get} and {#delete} return the bare parsed body instead.
|
|
40
|
+
#
|
|
41
|
+
# @!attribute [r] body
|
|
42
|
+
# @return [Hash, Enumerator] The parsed JSON body, or the chunk
|
|
43
|
+
# enumerator for a streaming request.
|
|
44
|
+
# @!attribute [r] headers
|
|
45
|
+
# @return [Hash{String=>String}] The response headers, keyed by
|
|
46
|
+
# downcased name.
|
|
47
|
+
#
|
|
48
|
+
Result = ::Data.define(:body, :headers)
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Create a transport.
|
|
52
|
+
#
|
|
53
|
+
# @param config [Configuration] The connection settings to use.
|
|
54
|
+
#
|
|
55
|
+
def initialize(config)
|
|
56
|
+
@config = config
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Issue a GET request and return the parsed JSON body.
|
|
61
|
+
#
|
|
62
|
+
# @param path [String] The request path, including any prefix such as
|
|
63
|
+
# `/v1` or `/health` (resources own their prefixes).
|
|
64
|
+
# @return [Hash] The parsed response body, with string keys.
|
|
65
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
66
|
+
#
|
|
67
|
+
def get(path)
|
|
68
|
+
response = map_request_errors { session.get(url_for(path)) }
|
|
69
|
+
handle(response)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Issue a POST request with a JSON body and return the parsed JSON body.
|
|
74
|
+
#
|
|
75
|
+
# @param path [String] The request path, including any prefix such as
|
|
76
|
+
# `/v1` (resources own their prefixes).
|
|
77
|
+
# @param body [Hash] The request body, serialized to JSON. The
|
|
78
|
+
# `Content-Type: application/json` header is set automatically.
|
|
79
|
+
# @param headers [Hash, nil] Extra request headers to send, merged over
|
|
80
|
+
# the defaults (e.g. the session-continuity headers).
|
|
81
|
+
# @return [Result] The parsed response body and the response headers.
|
|
82
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
83
|
+
#
|
|
84
|
+
def post(path, body, headers: nil)
|
|
85
|
+
response = map_request_errors { session.post(url_for(path), json: body, headers: headers) }
|
|
86
|
+
Result.new(body: handle(response), headers: normalize_headers(response.headers))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Issue a PATCH request with a JSON body and return the parsed JSON body.
|
|
91
|
+
#
|
|
92
|
+
# Like {#get} and {#delete}, this returns the bare parsed body rather than
|
|
93
|
+
# a {Result}: no PATCH endpoint surfaces response headers the caller needs.
|
|
94
|
+
#
|
|
95
|
+
# @param path [String] The request path, including any prefix such as
|
|
96
|
+
# `/v1` or `/api` (resources own their prefixes).
|
|
97
|
+
# @param body [Hash] The request body, serialized to JSON. The
|
|
98
|
+
# `Content-Type: application/json` header is set automatically.
|
|
99
|
+
# @return [Hash] The parsed response body, with string keys.
|
|
100
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
101
|
+
#
|
|
102
|
+
def patch(path, body)
|
|
103
|
+
response = map_request_errors { session.patch(url_for(path), json: body) }
|
|
104
|
+
handle(response)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
##
|
|
108
|
+
# Issue a DELETE request and return the parsed JSON body.
|
|
109
|
+
#
|
|
110
|
+
# @param path [String] The request path, including any prefix such as
|
|
111
|
+
# `/v1` (resources own their prefixes).
|
|
112
|
+
# @return [Hash] The parsed response body, with string keys.
|
|
113
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
114
|
+
#
|
|
115
|
+
def delete(path)
|
|
116
|
+
response = map_request_errors { session.delete(url_for(path)) }
|
|
117
|
+
handle(response)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
##
|
|
121
|
+
# Open a streaming POST and return its live response body for an SSE
|
|
122
|
+
# consumer ({Stream}). The response status is checked up front, so an
|
|
123
|
+
# error response raises before any streaming begins; on success the body
|
|
124
|
+
# is returned unread so it can be consumed incrementally.
|
|
125
|
+
#
|
|
126
|
+
# @param path [String] The request path, including its prefix.
|
|
127
|
+
# @param body [Hash] The request body, serialized to JSON.
|
|
128
|
+
# @param headers [Hash, nil] Extra request headers to send, merged over
|
|
129
|
+
# the defaults (e.g. the session-continuity headers).
|
|
130
|
+
# @return [Result] The live chunk enumerator (as `body`) and the response
|
|
131
|
+
# headers. Iterate `body` with `#each` to read byte chunks as they
|
|
132
|
+
# arrive.
|
|
133
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
134
|
+
#
|
|
135
|
+
def stream_post(path, body, headers: nil)
|
|
136
|
+
response = map_request_errors { session.post(url_for(path), json: body, headers: headers) }
|
|
137
|
+
unless response.status.success?
|
|
138
|
+
raise APIError.from_response(status: response.code, body: response.body.to_s,
|
|
139
|
+
headers: normalize_headers(response.headers))
|
|
140
|
+
end
|
|
141
|
+
Result.new(body: map_stream_errors(response.body), headers: normalize_headers(response.headers))
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
# Open a streaming GET and return its live response body for an SSE
|
|
146
|
+
# consumer ({Stream}). Like {#stream_post}, the status is checked up front
|
|
147
|
+
# so an error response raises before any streaming begins; on success the
|
|
148
|
+
# body is returned unread for incremental consumption. The response
|
|
149
|
+
# headers are not surfaced (this is the streaming counterpart of {#get},
|
|
150
|
+
# which also returns the bare body).
|
|
151
|
+
#
|
|
152
|
+
# @param path [String] The request path, including its prefix.
|
|
153
|
+
# @return [Enumerator] The live chunk enumerator. Iterate it with `#each`
|
|
154
|
+
# to read byte chunks as they arrive.
|
|
155
|
+
# @raise [APIError] If the server returns a non-2xx response.
|
|
156
|
+
#
|
|
157
|
+
def stream_get(path)
|
|
158
|
+
response = map_request_errors { session.get(url_for(path)) }
|
|
159
|
+
unless response.status.success?
|
|
160
|
+
raise APIError.from_response(status: response.code, body: response.body.to_s,
|
|
161
|
+
headers: normalize_headers(response.headers))
|
|
162
|
+
end
|
|
163
|
+
map_stream_errors(response.body)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
##
|
|
169
|
+
# Wrap a streaming response body so transport-level failures hit while
|
|
170
|
+
# reading it are mapped to the {Error} hierarchy.
|
|
171
|
+
#
|
|
172
|
+
# The body is read lazily, chunk by chunk, *after* {#stream_post} has
|
|
173
|
+
# returned — so a socket or read-timeout failure mid-stream happens
|
|
174
|
+
# outside `map_request_errors`'s rescue and would otherwise surface as the raw
|
|
175
|
+
# `http`-gem exception. Iterating the returned enumerator re-reads the
|
|
176
|
+
# body inside `map_request_errors`, so the same {TimeoutError}/{ConnectionError}
|
|
177
|
+
# mapping applies. Chunks delivered before the failure are still yielded;
|
|
178
|
+
# the exception is raised when the failing read is reached. Keeps {Stream}
|
|
179
|
+
# HTTP-agnostic — it only ever sees mapped errors.
|
|
180
|
+
#
|
|
181
|
+
# @param body [#each] The live response body, yielding String chunks.
|
|
182
|
+
# @return [Enumerator] The same chunks, with mid-stream failures mapped.
|
|
183
|
+
#
|
|
184
|
+
def map_stream_errors(body)
|
|
185
|
+
::Enumerator.new do |yielder|
|
|
186
|
+
map_request_errors { body.each { |chunk| yielder << chunk } }
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
##
|
|
191
|
+
# Run an HTTP request, translating the `http` gem's transport-level
|
|
192
|
+
# failures into the client's {Error} hierarchy.
|
|
193
|
+
#
|
|
194
|
+
# @yield The block that issues the request and returns its response.
|
|
195
|
+
# @return [HTTP::Response]
|
|
196
|
+
# @raise [TimeoutError] On an open or read timeout.
|
|
197
|
+
# @raise [ConnectionError] On a socket, DNS, or TLS failure.
|
|
198
|
+
#
|
|
199
|
+
def map_request_errors
|
|
200
|
+
yield
|
|
201
|
+
rescue ::HTTP::TimeoutError => e
|
|
202
|
+
raise TimeoutError, e.message
|
|
203
|
+
rescue ::HTTP::ConnectionError => e
|
|
204
|
+
raise ConnectionError, e.message
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
##
|
|
208
|
+
# The persistent `http` session for this transport, built once and reused
|
|
209
|
+
# across requests so its keep-alive connection is shared. The session
|
|
210
|
+
# carries the default headers (auth, `Accept`) and the configured
|
|
211
|
+
# timeouts, and reuses an idle connection for up to the configured
|
|
212
|
+
# keep-alive timeout before reopening it; per-request headers are merged
|
|
213
|
+
# over the defaults at the call site via the request's `headers:` option.
|
|
214
|
+
# Scoped to (and pinned to the origin of) this transport instance; not
|
|
215
|
+
# thread-safe.
|
|
216
|
+
#
|
|
217
|
+
# @return [HTTP::Session] The persistent, auth- and timeout-configured
|
|
218
|
+
# session.
|
|
219
|
+
#
|
|
220
|
+
def session
|
|
221
|
+
@session ||=
|
|
222
|
+
begin
|
|
223
|
+
result = ::HTTP.persistent(@config.base_url, timeout: @config.keep_alive_timeout)
|
|
224
|
+
.headers(default_headers)
|
|
225
|
+
# Pass only the timeouts that are set: the `http` gem rejects a nil
|
|
226
|
+
# value for any operation rather than treating it as "no limit".
|
|
227
|
+
timeouts = {read: @config.read_timeout, connect: @config.open_timeout,
|
|
228
|
+
write: @config.write_timeout}.compact
|
|
229
|
+
result = result.timeout(timeouts) unless timeouts.empty?
|
|
230
|
+
result
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
##
|
|
235
|
+
# Normalize response headers to a plain Hash keyed by downcased name,
|
|
236
|
+
# keeping the layers above {Transport} free of the `http` gem's header
|
|
237
|
+
# type. Repeated headers collapse to their first value.
|
|
238
|
+
#
|
|
239
|
+
# @param headers [#to_h] The response headers.
|
|
240
|
+
# @return [Hash{String=>String}]
|
|
241
|
+
#
|
|
242
|
+
def normalize_headers(headers)
|
|
243
|
+
headers.to_h.each_with_object({}) do |(name, value), result|
|
|
244
|
+
result[name.to_s.downcase] = value.is_a?(::Array) ? value.first : value
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
##
|
|
249
|
+
# @return [Hash] The headers sent on every request.
|
|
250
|
+
#
|
|
251
|
+
def default_headers
|
|
252
|
+
headers = {"Accept" => "application/json"}
|
|
253
|
+
headers["Authorization"] = "Bearer #{@config.api_key}" if @config.api_key
|
|
254
|
+
headers
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
##
|
|
258
|
+
# @param path [String] A request path.
|
|
259
|
+
# @return [String] The fully-qualified request URL.
|
|
260
|
+
#
|
|
261
|
+
def url_for(path)
|
|
262
|
+
"#{@config.base_url.chomp('/')}#{path}"
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
##
|
|
266
|
+
# Parse a successful response or raise on a non-2xx status.
|
|
267
|
+
#
|
|
268
|
+
# @param response [HTTP::Response]
|
|
269
|
+
# @return [Hash] The parsed JSON body.
|
|
270
|
+
#
|
|
271
|
+
def handle(response)
|
|
272
|
+
body = response.body.to_s
|
|
273
|
+
unless response.status.success?
|
|
274
|
+
raise APIError.from_response(status: response.code, body: body,
|
|
275
|
+
headers: normalize_headers(response.headers))
|
|
276
|
+
end
|
|
277
|
+
body.empty? ? {} : Util.parse_json(body)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
require "hermes_agent/client/errors"
|
|
6
|
+
|
|
7
|
+
module HermesAgent
|
|
8
|
+
class Client
|
|
9
|
+
##
|
|
10
|
+
# Internal helpers shared across the client's layers. Not part of the
|
|
11
|
+
# public API.
|
|
12
|
+
#
|
|
13
|
+
# @private
|
|
14
|
+
module Util
|
|
15
|
+
##
|
|
16
|
+
# The downcased response-header name carrying the session id.
|
|
17
|
+
#
|
|
18
|
+
SESSION_ID_HEADER = "x-hermes-session-id"
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# The downcased response-header name carrying the session key.
|
|
22
|
+
#
|
|
23
|
+
SESSION_KEY_HEADER = "x-hermes-session-key"
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Extract the session-continuity values from a normalized (downcased-key)
|
|
27
|
+
# response-header hash into the keyword form the session-bearing entities
|
|
28
|
+
# ({Entities::ChatCompletion}, {Entities::Response}) accept. Either value
|
|
29
|
+
# is `nil` when the corresponding header is absent.
|
|
30
|
+
#
|
|
31
|
+
# @param headers [Hash{String=>String}] Response headers, keyed by
|
|
32
|
+
# downcased name (as produced by {Transport}).
|
|
33
|
+
# @return [Hash{Symbol=>(String, nil)}] `{session_id:, session_key:}`.
|
|
34
|
+
#
|
|
35
|
+
def self.session_headers(headers)
|
|
36
|
+
{session_id: headers[SESSION_ID_HEADER], session_key: headers[SESSION_KEY_HEADER]}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Parse JSON from a payload the client expected to be JSON, mapping a
|
|
41
|
+
# parse failure to {MalformedResponseError} so a raw `JSON::ParserError`
|
|
42
|
+
# never leaks out. Shared by the non-streaming ({Transport#handle}) and
|
|
43
|
+
# streaming ({Stream#dispatch}) paths so the two behave identically.
|
|
44
|
+
#
|
|
45
|
+
# @param text [String] The raw text to parse.
|
|
46
|
+
# @return [Object] The parsed JSON value.
|
|
47
|
+
# @raise [MalformedResponseError] If the text is not valid JSON.
|
|
48
|
+
#
|
|
49
|
+
def self.parse_json(text)
|
|
50
|
+
::JSON.parse(text)
|
|
51
|
+
rescue ::JSON::ParserError
|
|
52
|
+
raise MalformedResponseError.new("Invalid JSON in response body", body: text)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hermes_agent/client/version"
|
|
4
|
+
require "hermes_agent/client/configuration"
|
|
5
|
+
require "hermes_agent/client/errors"
|
|
6
|
+
require "hermes_agent/client/util"
|
|
7
|
+
require "hermes_agent/client/stream"
|
|
8
|
+
require "hermes_agent/client/transport"
|
|
9
|
+
require "hermes_agent/client/conversation"
|
|
10
|
+
require "hermes_agent/client/resources/capabilities"
|
|
11
|
+
require "hermes_agent/client/resources/chat"
|
|
12
|
+
require "hermes_agent/client/resources/health"
|
|
13
|
+
require "hermes_agent/client/resources/jobs"
|
|
14
|
+
require "hermes_agent/client/resources/models"
|
|
15
|
+
require "hermes_agent/client/resources/responses"
|
|
16
|
+
require "hermes_agent/client/resources/runs"
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Classes related to the Hermes agent
|
|
20
|
+
#
|
|
21
|
+
module HermesAgent
|
|
22
|
+
##
|
|
23
|
+
# A client for the Hermes API server.
|
|
24
|
+
#
|
|
25
|
+
# Construct a client with the server location and credentials, then reach
|
|
26
|
+
# endpoints through resource accessors such as {#health}.
|
|
27
|
+
#
|
|
28
|
+
# client = HermesAgent::Client.new(base_url: "http://127.0.0.1:8642")
|
|
29
|
+
# client.health.check.status # => "ok"
|
|
30
|
+
#
|
|
31
|
+
# Note this class is not thread-safe. When using in a multithreaded
|
|
32
|
+
# application, you should create a separate client object per thread.
|
|
33
|
+
#
|
|
34
|
+
class Client
|
|
35
|
+
# Sentinel distinguishing an omitted `api_key:` (defer to {Configuration}'s
|
|
36
|
+
# `HERMES_API_KEY` default) from an explicit `nil` (send no auth header).
|
|
37
|
+
UNSET = ::Object.new
|
|
38
|
+
private_constant :UNSET
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Create a client.
|
|
42
|
+
#
|
|
43
|
+
# Settings may be supplied as keyword arguments, by yielding the
|
|
44
|
+
# {Configuration} to a block, or both (the block runs after the keyword
|
|
45
|
+
# arguments are applied).
|
|
46
|
+
#
|
|
47
|
+
# @param base_url [String] The server root URL. See {Configuration}.
|
|
48
|
+
# @param api_key [String, nil] The bearer token. When omitted, defaults to
|
|
49
|
+
# the `HERMES_API_KEY` environment variable (see {Configuration}); pass
|
|
50
|
+
# `nil` explicitly to send no `Authorization` header regardless.
|
|
51
|
+
# @param read_timeout [Numeric, nil] The read timeout in seconds.
|
|
52
|
+
# @param open_timeout [Numeric, nil] The connection-open timeout in seconds.
|
|
53
|
+
# @param write_timeout [Numeric, nil] The request-write timeout in seconds.
|
|
54
|
+
# @param keep_alive_timeout [Numeric] How long an idle persistent
|
|
55
|
+
# connection may be reused before being reopened. See {Configuration}.
|
|
56
|
+
# @yieldparam config [Configuration] The configuration, for customization.
|
|
57
|
+
#
|
|
58
|
+
def initialize(base_url: Configuration::DEFAULT_BASE_URL,
|
|
59
|
+
api_key: UNSET,
|
|
60
|
+
read_timeout: nil,
|
|
61
|
+
open_timeout: nil,
|
|
62
|
+
write_timeout: nil,
|
|
63
|
+
keep_alive_timeout: Configuration::DEFAULT_KEEP_ALIVE_TIMEOUT)
|
|
64
|
+
@config = Configuration.new(base_url: base_url, read_timeout: read_timeout,
|
|
65
|
+
open_timeout: open_timeout, write_timeout: write_timeout,
|
|
66
|
+
keep_alive_timeout: keep_alive_timeout)
|
|
67
|
+
@config.api_key = api_key unless api_key.equal?(UNSET)
|
|
68
|
+
yield @config if block_given?
|
|
69
|
+
@transport = Transport.new(@config)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# The configuration this client was built with.
|
|
74
|
+
# @return [Configuration]
|
|
75
|
+
#
|
|
76
|
+
attr_reader :config
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# The capabilities resource (the server's advertised endpoints and
|
|
80
|
+
# feature matrix).
|
|
81
|
+
# @return [Resources::Capabilities]
|
|
82
|
+
#
|
|
83
|
+
def capabilities
|
|
84
|
+
@capabilities ||= Resources::Capabilities.new(@transport)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# The chat resource (OpenAI-compatible chat completions).
|
|
89
|
+
# @return [Resources::Chat]
|
|
90
|
+
#
|
|
91
|
+
def chat
|
|
92
|
+
@chat ||= Resources::Chat.new(@transport)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# The health resource (server health checks).
|
|
97
|
+
# @return [Resources::Health]
|
|
98
|
+
#
|
|
99
|
+
def health
|
|
100
|
+
@health ||= Resources::Health.new(@transport)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
##
|
|
104
|
+
# The jobs resource (the Jobs API, for scheduled background work).
|
|
105
|
+
# @return [Resources::Jobs]
|
|
106
|
+
#
|
|
107
|
+
def jobs
|
|
108
|
+
@jobs ||= Resources::Jobs.new(@transport)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
##
|
|
112
|
+
# The models resource (discovery of advertised models).
|
|
113
|
+
# @return [Resources::Models]
|
|
114
|
+
#
|
|
115
|
+
def models
|
|
116
|
+
@models ||= Resources::Models.new(@transport)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# The responses resource (the Responses API, with server-side
|
|
121
|
+
# conversation state).
|
|
122
|
+
# @return [Resources::Responses]
|
|
123
|
+
#
|
|
124
|
+
def responses
|
|
125
|
+
@responses ||= Resources::Responses.new(@transport)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
##
|
|
129
|
+
# The runs resource (the Runs API, for long-running server-side agent
|
|
130
|
+
# runs).
|
|
131
|
+
# @return [Resources::Runs]
|
|
132
|
+
#
|
|
133
|
+
def runs
|
|
134
|
+
@runs ||= Resources::Runs.new(@transport)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
metadata
CHANGED
|
@@ -1,26 +1,87 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hermes-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Daniel Azuma
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: http
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '6.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '6.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: http-cookie
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.1'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.1'
|
|
40
|
+
description: This is a basic client library for the API Server that ships with the
|
|
41
|
+
Hermes AI Agent.
|
|
42
|
+
email:
|
|
43
|
+
- dazuma@gmail.com
|
|
16
44
|
executables: []
|
|
17
45
|
extensions: []
|
|
18
46
|
extra_rdoc_files: []
|
|
19
47
|
files:
|
|
48
|
+
- ".yardopts"
|
|
49
|
+
- CHANGELOG.md
|
|
50
|
+
- LICENSE.md
|
|
20
51
|
- README.md
|
|
21
52
|
- lib/hermes-client.rb
|
|
22
|
-
|
|
23
|
-
|
|
53
|
+
- lib/hermes_agent/client.rb
|
|
54
|
+
- lib/hermes_agent/client/configuration.rb
|
|
55
|
+
- lib/hermes_agent/client/conversation.rb
|
|
56
|
+
- lib/hermes_agent/client/entities/capabilities.rb
|
|
57
|
+
- lib/hermes_agent/client/entities/chat_completion.rb
|
|
58
|
+
- lib/hermes_agent/client/entities/health.rb
|
|
59
|
+
- lib/hermes_agent/client/entities/job.rb
|
|
60
|
+
- lib/hermes_agent/client/entities/model.rb
|
|
61
|
+
- lib/hermes_agent/client/entities/response.rb
|
|
62
|
+
- lib/hermes_agent/client/entities/run.rb
|
|
63
|
+
- lib/hermes_agent/client/entities/session_headers.rb
|
|
64
|
+
- lib/hermes_agent/client/entity.rb
|
|
65
|
+
- lib/hermes_agent/client/errors.rb
|
|
66
|
+
- lib/hermes_agent/client/resources/capabilities.rb
|
|
67
|
+
- lib/hermes_agent/client/resources/chat.rb
|
|
68
|
+
- lib/hermes_agent/client/resources/health.rb
|
|
69
|
+
- lib/hermes_agent/client/resources/jobs.rb
|
|
70
|
+
- lib/hermes_agent/client/resources/models.rb
|
|
71
|
+
- lib/hermes_agent/client/resources/responses.rb
|
|
72
|
+
- lib/hermes_agent/client/resources/runs.rb
|
|
73
|
+
- lib/hermes_agent/client/stream.rb
|
|
74
|
+
- lib/hermes_agent/client/transport.rb
|
|
75
|
+
- lib/hermes_agent/client/util.rb
|
|
76
|
+
- lib/hermes_agent/client/version.rb
|
|
77
|
+
homepage: https://github.com/dazuma/hermes-client
|
|
78
|
+
licenses:
|
|
79
|
+
- MIT
|
|
80
|
+
metadata:
|
|
81
|
+
bug_tracker_uri: https://github.com/dazuma/hermes-client/issues
|
|
82
|
+
changelog_uri: https://rubydoc.info/gems/hermes-client/0.1.0/file/CHANGELOG.md
|
|
83
|
+
documentation_uri: https://rubydoc.info/gems/hermes-client/0.1.0
|
|
84
|
+
homepage_uri: https://github.com/dazuma/hermes-client
|
|
24
85
|
rdoc_options: []
|
|
25
86
|
require_paths:
|
|
26
87
|
- lib
|
|
@@ -28,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
28
89
|
requirements:
|
|
29
90
|
- - ">="
|
|
30
91
|
- !ruby/object:Gem::Version
|
|
31
|
-
version: '
|
|
92
|
+
version: '3.4'
|
|
32
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
33
94
|
requirements:
|
|
34
95
|
- - ">="
|
|
@@ -37,5 +98,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
37
98
|
requirements: []
|
|
38
99
|
rubygems_version: 4.0.10
|
|
39
100
|
specification_version: 4
|
|
40
|
-
summary:
|
|
101
|
+
summary: A client for the Hermes Agent API Server.
|
|
41
102
|
test_files: []
|