Module: Legion::MCP::ContextCompiler
- Defined in:
- lib/legion/mcp/context_compiler.rb
Constant Summary collapse
- CATEGORIES =
{ tasks: { tools: %w[legion.run_task legion.list_tasks legion.get_task legion.delete_task legion.get_task_logs], summary: 'Create, list, query, and delete tasks. Run functions via dot-notation task identifiers.' }, chains: { tools: %w[legion.list_chains legion.create_chain legion.update_chain legion.delete_chain], summary: 'Manage task chains - ordered sequences of tasks that execute in series.' }, relationships: { tools: %w[legion.list_relationships legion.create_relationship legion.update_relationship legion.delete_relationship], summary: 'Manage trigger-action relationships between functions.' }, extensions: { tools: %w[legion.list_extensions legion.get_extension legion.enable_extension legion.disable_extension], summary: 'Manage LEX extensions - list installed, inspect details, enable/disable.' }, schedules: { tools: %w[legion.list_schedules legion.create_schedule legion.update_schedule legion.delete_schedule], summary: 'Manage scheduled tasks - cron-style recurring task execution.' }, workers: { tools: %w[legion.list_workers legion.show_worker legion.worker_lifecycle legion.worker_costs], summary: 'Manage digital workers - list, inspect, lifecycle transitions, cost tracking.' }, rbac: { tools: %w[legion.rbac_check legion.rbac_assignments legion.rbac_grants], summary: 'Role-based access control - check permissions, view assignments and grants.' }, status: { tools: %w[legion.get_status legion.get_config legion.team_summary legion.routing_stats], summary: 'System status, configuration, team overview, and routing statistics.' }, describe: { tools: %w[legion.describe_runner], summary: 'Inspect a specific runner function - parameters, return type, metadata.' }, knowledge: { tools: %w[legion.query_knowledge legion.knowledge_health legion.knowledge_context legion.absorb], summary: 'Knowledge base operations - query, health, context retrieval, content absorption.' }, mesh: { tools: %w[legion.ask_peer legion.list_peers legion.notify_peer legion.broadcast_peers legion.mesh_status], summary: 'Agent mesh communication - peer queries, notifications, broadcasts, and topology.' }, mind_growth: { tools: %w[legion.mind_growth_status legion.mind_growth_propose legion.mind_growth_approve legion.mind_growth_build_queue legion.mind_growth_cognitive_profile legion.mind_growth_health], summary: 'Cognitive growth - proposals, approvals, build queue, profiling, fitness scores.' }, prompts: { tools: %w[legion.prompt_list legion.prompt_show legion.prompt_run], summary: 'Prompt template management - list, view, and render prompt templates.' }, datasets: { tools: %w[legion.dataset_list legion.dataset_show legion.experiment_results], summary: 'Dataset and experiment browsing - list datasets, view rows, compare results.' }, evals: { tools: %w[legion.eval_list legion.eval_run legion.eval_results], summary: 'Evaluation management - list evaluators, run evaluations, view results.' }, skills: { tools: %w[legion.skill.list legion.skill.describe legion.skill.invoke legion.skill.cancel], summary: 'Skill management - list, describe, invoke, and cancel LLM skills.' }, meta: { tools: %w[legion.do legion.tools legion.plan_action legion.structural_index], summary: 'Meta-tools - natural language routing, tool discovery, planning, structural index.' } }.freeze
Class Method Summary collapse
- .build_tool_index ⇒ Object
-
.category_tools(category_sym) ⇒ Hash?
Returns tools for a specific category, filtered to only those present in Server.tool_registry.
-
.compressed_catalog ⇒ Array<Hash>
Returns a compressed summary of all categories with tool counts and tool name lists.
- .keyword_score_map(keywords) ⇒ Object
-
.match_tool(intent_string) ⇒ Class?
Keyword-match intent against tool names and descriptions.
-
.match_tools(intent_string, limit: 5) ⇒ Array<Hash>
Returns top N keyword-matched tools ranked by score.
-
.merged_categories ⇒ Hash<Symbol, Hash>
Builds a merged category map: CATEGORIES constant as fallback, augmented by tool classes that declare mcp_category: via the definition DSL.
-
.reset! ⇒ Object
Clears the memoized tool_index.
- .scored_tools(intent_string) ⇒ Object
- .semantic_score_map(intent_string) ⇒ Object
-
.tool_index ⇒ Hash<String, Hash>
Returns a hash keyed by tool_name with compressed param info.
Class Method Details
.build_tool_index ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/legion/mcp/context_compiler.rb', line 181 def build_tool_index Server.tool_registry.each_with_object({}) do |klass, idx| raw_schema = klass.input_schema schema = raw_schema.is_a?(Hash) ? raw_schema : raw_schema.to_h properties = schema[:properties] || {} idx[klass.tool_name] = { name: klass.tool_name, description: klass.description, params: properties.keys.map(&:to_s) } end end |
.category_tools(category_sym) ⇒ Hash?
Returns tools for a specific category, filtered to only those present in Server.tool_registry. Checks CATEGORIES (hardcoded fallback) as well as definition-declared mcp_category on tool classes.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/legion/mcp/context_compiler.rb', line 107 def category_tools(category_sym) config = merged_categories[category_sym] return nil unless config index = tool_index tools = config[:tools].filter_map { |name| index[name] } return nil if tools.empty? { category: category_sym, summary: config[:summary], tools: tools } end |
.compressed_catalog ⇒ Array<Hash>
Returns a compressed summary of all categories with tool counts and tool name lists. Merges CATEGORIES (hardcoded fallback) with any categories declared via the definition DSL (mcp_category: on dynamically discovered tool classes).
90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/legion/mcp/context_compiler.rb', line 90 def compressed_catalog merged = merged_categories merged.map do |category, config| tool_names = config[:tools] { category: category, summary: config[:summary], tool_count: tool_names.length, tools: tool_names } end end |
.keyword_score_map(keywords) ⇒ Object
217 218 219 220 221 222 223 224 225 |
# File 'lib/legion/mcp/context_compiler.rb', line 217 def keyword_score_map(keywords) tool_index.values.to_h do |entry| haystack = "#{entry[:name].downcase} #{entry[:description].downcase}" score = keywords.count { |kw| haystack.include?(kw) } name_terms = entry[:name].downcase.tr('._-', ' ').split score += (keywords & name_terms).length * 3 [entry[:name], score] end end |
.match_tool(intent_string) ⇒ Class?
Keyword-match intent against tool names and descriptions.
147 148 149 150 151 152 153 154 155 |
# File 'lib/legion/mcp/context_compiler.rb', line 147 def match_tool(intent_string) scored = scored_tools(intent_string) return nil if scored.empty? best = scored.max_by { |entry| entry[:score] } return nil if best[:score].zero? Server.tool_registry.find { |klass| klass.tool_name == best[:name] } end |
.match_tools(intent_string, limit: 5) ⇒ Array<Hash>
Returns top N keyword-matched tools ranked by score.
161 162 163 164 165 166 |
# File 'lib/legion/mcp/context_compiler.rb', line 161 def match_tools(intent_string, limit: 5) scored = scored_tools(intent_string) .select { |entry| entry[:score].positive? } .sort_by { |entry| -entry[:score] } scored.first(limit) end |
.merged_categories ⇒ Hash<Symbol, Hash>
Builds a merged category map: CATEGORIES constant as fallback, augmented by tool classes that declare mcp_category: via the definition DSL.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/legion/mcp/context_compiler.rb', line 125 def merged_categories result = CATEGORIES.transform_values do |config| { tools: config[:tools].dup, summary: config[:summary] } end Server.tool_registry.each do |klass| next unless klass.respond_to?(:mcp_category) && klass.mcp_category cat = klass.mcp_category.to_sym if result.key?(cat) result[cat][:tools] |= [klass.tool_name] else result[cat] = { tools: [klass.tool_name], summary: cat.to_s.tr('_', ' ').capitalize } end end result end |
.reset! ⇒ Object
Clears the memoized tool_index.
176 177 178 179 |
# File 'lib/legion/mcp/context_compiler.rb', line 176 def reset! @tool_index = nil Legion::MCP::EmbeddingIndex.reset! if defined?(Legion::MCP::EmbeddingIndex) end |
.scored_tools(intent_string) ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/legion/mcp/context_compiler.rb', line 194 def scored_tools(intent_string) keywords = intent_string.downcase.split return [] if keywords.empty? kw_scores = keyword_score_map(keywords) sem_scores = semantic_score_map(intent_string) use_semantic = !sem_scores.empty? tool_index.values.map do |entry| kw_raw = kw_scores[entry[:name]] || 0 if use_semantic max_kw = kw_scores.values.max || 1 normalized_kw = max_kw.positive? ? kw_raw.to_f / max_kw : 0.0 sem = sem_scores[entry[:name]] || 0.0 blended = (normalized_kw * 0.4) + (sem * 0.6) else blended = kw_raw.to_f end { name: entry[:name], description: entry[:description], score: blended } end end |
.semantic_score_map(intent_string) ⇒ Object
227 228 229 230 231 232 233 |
# File 'lib/legion/mcp/context_compiler.rb', line 227 def semantic_score_map(intent_string) return {} unless defined?(Legion::MCP::EmbeddingIndex) && Legion::MCP::EmbeddingIndex.populated? Legion::MCP::EmbeddingIndex.semantic_match(intent_string, limit: tool_index.size).to_h do |result| [result[:name], result[:score]] end end |
.tool_index ⇒ Hash<String, Hash>
Returns a hash keyed by tool_name with compressed param info. Memoized — call reset! to clear.
171 172 173 |
# File 'lib/legion/mcp/context_compiler.rb', line 171 def tool_index @tool_index ||= build_tool_index end |