datagrout-conduit 0.8.0 → 0.8.2
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/README.md +3 -3
- data/lib/datagrout_conduit/client.rb +15 -1
- data/lib/datagrout_conduit/transport/ws.rb +32 -2
- data/lib/datagrout_conduit/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5f3083e66b890a25b3fe77e4fd86e7e72ba3d86af8a530477ad93334de26f19
|
|
4
|
+
data.tar.gz: 16bb086f9c923bacad3fe8fc228eb5ea024a475a33bba51f320aad00fa032f56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a38b2be0474f517414da7731565fac6a4327664f84b7b95f9e04d478f29183087ac4da84899fbba952bbba11244386735ecd564c1a422038c8baef3b45141d10
|
|
7
|
+
data.tar.gz: 82f0c8a811e8165f1a5c91dcc5c3f93121115cc49d9969774e6b0a2c65d63afb2cf34d646c1042039f52182db2bca2084982d75dee76c56c0ad612405132ec66
|
data/README.md
CHANGED
|
@@ -9,13 +9,13 @@ Connect to remote MCP and JSONRPC servers, invoke tools, discover capabilities w
|
|
|
9
9
|
Add to your Gemfile:
|
|
10
10
|
|
|
11
11
|
```ruby
|
|
12
|
-
gem "datagrout-conduit", "~> 0.8.
|
|
12
|
+
gem "datagrout-conduit", "~> 0.8.1"
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Or install directly:
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
|
-
gem install datagrout-conduit -v 0.8.
|
|
18
|
+
gem install datagrout-conduit -v 0.8.1
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
@@ -310,7 +310,7 @@ Supported topics:
|
|
|
310
310
|
| `flows.<flow_id>.*` | `flow.into` progress and completion |
|
|
311
311
|
| `governor.<server_uuid>` | Governor percept events (file change, schedule, webhook) |
|
|
312
312
|
|
|
313
|
-
**Reconnection**: after a disconnect, `send_request` and `subscribe` raise `DatagroutConduit::NotInitializedError`. Call `client.connect` again and re-subscribe — subscriptions do not survive reconnects in v0.4.
|
|
313
|
+
**Reconnection**: after a disconnect, `send_request` and `subscribe` raise `DatagroutConduit::NotInitializedError`. Call `client.connect` again and re-subscribe — subscriptions do not survive reconnects in v0.4. A connection ends when the server closes it, a read fails, or a keepalive ping goes unanswered for a whole interval; in-flight calls then fail and every subscription's `each` ends.
|
|
314
314
|
|
|
315
315
|
## Standard MCP Methods
|
|
316
316
|
|
|
@@ -173,6 +173,20 @@ module DatagroutConduit
|
|
|
173
173
|
# Standard MCP Methods
|
|
174
174
|
# ================================================================
|
|
175
175
|
|
|
176
|
+
# Whether a tool name is one of DataGrout's own (the semantic discovery
|
|
177
|
+
# and execution tools) rather than a third-party integration tool.
|
|
178
|
+
#
|
|
179
|
+
# Third-party tools are named +integration@version/tool@version+. DataGrout's
|
|
180
|
+
# own tools reach a client in two spellings depending on the transport: the
|
|
181
|
+
# canonical +data-grout@1/discovery.perform@1+ over WebSocket, the short
|
|
182
|
+
# +discovery.perform+ over HTTP MCP. Treating "contains @" as "third party"
|
|
183
|
+
# kept only the short form, so a WebSocket client with the intelligent
|
|
184
|
+
# interface on saw zero tools.
|
|
185
|
+
def self.dg_native_tool?(name)
|
|
186
|
+
name = name.to_s
|
|
187
|
+
!name.include?("@") || name.start_with?("data-grout@", "data-grout/")
|
|
188
|
+
end
|
|
189
|
+
|
|
176
190
|
def list_tools
|
|
177
191
|
ensure_initialized!
|
|
178
192
|
|
|
@@ -194,7 +208,7 @@ module DatagroutConduit
|
|
|
194
208
|
end
|
|
195
209
|
|
|
196
210
|
if @use_intelligent_interface
|
|
197
|
-
all_tools.
|
|
211
|
+
all_tools.select! { |t| self.class.dg_native_tool?(t.name) }
|
|
198
212
|
end
|
|
199
213
|
|
|
200
214
|
all_tools
|
|
@@ -442,6 +442,19 @@ module DatagroutConduit
|
|
|
442
442
|
subs.each_value { |list| list.each(&:_close) }
|
|
443
443
|
end
|
|
444
444
|
|
|
445
|
+
# The peer stopped answering pings: release every waiter as a close
|
|
446
|
+
# does, then close the socket so the read thread stops too.
|
|
447
|
+
def peer_gone
|
|
448
|
+
was_connected = @mutex.synchronize do
|
|
449
|
+
old = @connected
|
|
450
|
+
@connected = false
|
|
451
|
+
old
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
fail_all_pending(:ping_timeout) if was_connected
|
|
455
|
+
@io&.close rescue nil
|
|
456
|
+
end
|
|
457
|
+
|
|
445
458
|
def cleanup_socket
|
|
446
459
|
stop_ping_thread
|
|
447
460
|
@write_mutex.synchronize do
|
|
@@ -458,11 +471,17 @@ module DatagroutConduit
|
|
|
458
471
|
# Start the background ping thread. Sends one WS ping frame every
|
|
459
472
|
# @ping_interval seconds until the connection is torn down. No-op when
|
|
460
473
|
# @ping_interval is non-positive (used by tests to disable pinging).
|
|
474
|
+
#
|
|
475
|
+
# A ping still unanswered when the next is due closes the connection: a
|
|
476
|
+
# peer that vanished without a close frame (a dropped NAT mapping, a
|
|
477
|
+
# host that went away) is otherwise invisible until the OS gives up on
|
|
478
|
+
# the TCP connection.
|
|
461
479
|
def start_ping_thread
|
|
462
480
|
return if @ping_thread
|
|
463
481
|
return if @ping_interval <= 0
|
|
464
482
|
|
|
465
483
|
interval = @ping_interval
|
|
484
|
+
@awaiting_pong = false
|
|
466
485
|
@ping_thread = Thread.new do
|
|
467
486
|
loop do
|
|
468
487
|
sleep interval
|
|
@@ -471,15 +490,26 @@ module DatagroutConduit
|
|
|
471
490
|
driver = @driver
|
|
472
491
|
break unless driver
|
|
473
492
|
|
|
493
|
+
if @awaiting_pong
|
|
494
|
+
peer_gone
|
|
495
|
+
break
|
|
496
|
+
end
|
|
497
|
+
|
|
474
498
|
begin
|
|
475
499
|
# WebSocket::Driver#ping returns false if the connection is
|
|
476
|
-
# already closing; treat that as "stop the loop" too.
|
|
477
|
-
|
|
500
|
+
# already closing; treat that as "stop the loop" too. Its block
|
|
501
|
+
# runs when the matching pong arrives.
|
|
502
|
+
@awaiting_pong = true
|
|
503
|
+
@write_mutex.synchronize { driver.ping { @awaiting_pong = false } } || break
|
|
478
504
|
@pings_sent += 1
|
|
479
505
|
rescue StandardError
|
|
480
506
|
break
|
|
481
507
|
end
|
|
482
508
|
end
|
|
509
|
+
ensure
|
|
510
|
+
# A loop that ended on its own must not stop the next connect from
|
|
511
|
+
# starting a fresh one.
|
|
512
|
+
@ping_thread = nil if @ping_thread == Thread.current
|
|
483
513
|
end
|
|
484
514
|
@ping_thread.abort_on_exception = false
|
|
485
515
|
@ping_thread.name = "conduit-ws-ping"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: datagrout-conduit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DataGrout
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: faraday
|
|
@@ -162,7 +161,6 @@ metadata:
|
|
|
162
161
|
source_code_uri: https://github.com/DataGrout/conduit-sdk/tree/main/ruby
|
|
163
162
|
changelog_uri: https://github.com/DataGrout/conduit-sdk/blob/main/CHANGELOG.md
|
|
164
163
|
bug_tracker_uri: https://github.com/DataGrout/conduit-sdk/issues
|
|
165
|
-
post_install_message:
|
|
166
164
|
rdoc_options: []
|
|
167
165
|
require_paths:
|
|
168
166
|
- lib
|
|
@@ -177,8 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
177
175
|
- !ruby/object:Gem::Version
|
|
178
176
|
version: '0'
|
|
179
177
|
requirements: []
|
|
180
|
-
rubygems_version:
|
|
181
|
-
signing_key:
|
|
178
|
+
rubygems_version: 4.0.16
|
|
182
179
|
specification_version: 4
|
|
183
180
|
summary: Production-ready MCP client with mTLS, OAuth 2.1, and semantic discovery
|
|
184
181
|
test_files: []
|