Class: Legion::CLI::Chat::Tools::GraphExplore
Constant Summary
collapse
- DEFAULT_PORT =
4567
- DEFAULT_HOST =
'127.0.0.1'
Class Method Summary
collapse
Methods inherited from Tools::Base
deferred, deferred?, description, error_response, extension, handle_exception, input_schema, log, mcp_category, mcp_tier, runner, sticky, tags, text_response, tool_name, trigger_words
Class Method Details
.apollo_port ⇒ Object
136
137
138
139
140
141
142
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 136
def self.apollo_port
return DEFAULT_PORT unless defined?(Legion::Settings)
Legion::Settings[:api]&.dig(:port) || DEFAULT_PORT
rescue StandardError
DEFAULT_PORT
end
|
.call(action: 'topology') ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 32
def self.call(action: 'topology')
case action.to_s
when 'expertise' then format_expertise
when 'disputed' then format_disputed
else format_topology
end
rescue Errno::ECONNREFUSED
'Apollo unavailable (daemon not running).'
rescue StandardError => e
Legion::Logging.warn("GraphExplore#execute failed: #{e.message}") if defined?(Legion::Logging)
"Error exploring knowledge graph: #{e.message}"
end
|
.fetch_json(path, method: :get, body: nil) ⇒ Object
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 118
def self.fetch_json(path, method: :get, body: nil)
uri = URI("http://#{DEFAULT_HOST}:#{apollo_port}#{path}")
http = Net::HTTP.new(uri.host, uri.port)
http.open_timeout = 3
http.read_timeout = 10
response = if method == :post
req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
req.body = ::JSON.dump(body) if body
http.request(req)
else
http.get(uri.request_uri)
end
parsed = ::JSON.parse(response.body, symbolize_names: true)
parsed[:data] || parsed
end
|
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 97
def self.format_disputed
data = fetch_json('/api/apollo/query', method: :post,
body: { status: ['disputed'], limit: 20, query: '*',
min_confidence: 0.0 })
return "Apollo error: #{data[:error]}" if data[:error]
entries = data[:entries] || []
return 'No disputed entries in the knowledge graph.' if entries.empty?
lines = ["Disputed Knowledge Entries (#{entries.size}):\n"]
entries.each_with_index do |entry, idx|
conf = entry[:confidence] ? format(' (conf: %.2f)', entry[:confidence]) : ''
tags = entry[:tags]&.any? ? " [#{Array(entry[:tags]).join(', ')}]" : ''
lines << " #{idx + 1}. ##{entry[:id]}#{conf}#{tags}"
lines << " #{truncate(entry[:content], 120)}"
lines << " source: #{entry[:source_agent] || 'unknown'}"
end
lines.join("\n")
end
|
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 76
def self.format_expertise
data = fetch_json('/api/apollo/expertise')
return "Apollo error: #{data[:error]}" if data[:error]
lines = ["Apollo Agent Expertise Map:\n"]
lines << format(' Agents: %<a>d Domains: %<d>d', a: data[:total_agents] || 0, d: data[:total_domains] || 0)
(data[:domains] || {}).each do |domain, agents|
lines << ''
lines << " #{domain}:"
Array(agents).each do |agent|
bar = proficiency_bar(agent[:proficiency] || 0.0)
lines << format(' %<a>-20s %<bar>s %<p>5.1f%% (%<c>d entries)',
a: agent[:agent_id], bar: bar, p: (agent[:proficiency] || 0.0) * 100,
c: agent[:entry_count] || 0)
end
end
lines.join("\n")
end
|
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 45
def self.format_topology
data = fetch_json('/api/apollo/graph')
return "Apollo error: #{data[:error]}" if data[:error]
lines = ["Apollo Knowledge Graph Topology:\n"]
lines << ' Domains:'
(data[:domains] || {}).sort_by { |_, c| -c }.each do |domain, count|
lines << format(' %<d>-25s %<c>d entries', d: domain, c: count)
end
lines << ''
lines << ' Contributing Agents:'
(data[:agents] || {}).sort_by { |_, c| -c }.first(10).each do |agent, count|
lines << format(' %<a>-25s %<c>d entries', a: agent, c: count)
end
lines << ''
lines << ' Relation Types:'
(data[:relation_types] || {}).sort_by { |_, c| -c }.each do |rtype, count|
lines << format(' %<r>-20s %<c>d', r: rtype, c: count)
end
lines << ''
lines << format(' Total Relations: %<v>d', v: data[:total_relations] || 0)
lines << format(' Confirmed: %<v>d Candidates: %<v2>d Disputed: %<v3>d',
v: data[:confirmed] || 0, v2: data[:candidates] || 0, v3: data[:disputed_entries] || 0)
lines.join("\n")
end
|
.proficiency_bar(value) ⇒ Object
144
145
146
147
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 144
def self.proficiency_bar(value)
filled = (value * 10).round.clamp(0, 10)
('#' * filled) + ('-' * (10 - filled))
end
|
.truncate(text, max) ⇒ Object
149
150
151
152
153
|
# File 'lib/legion/cli/chat/tools/graph_explore.rb', line 149
def self.truncate(text, max)
return '' if text.nil?
text.length > max ? "#{text[0...max]}..." : text
end
|