Module: RubynCode::Agent::DynamicToolSchema
- Defined in:
- lib/rubyn_code/agent/dynamic_tool_schema.rb
Overview
Filters tool schemas sent to the LLM based on detected task context. Instead of sending all 28+ tool schemas on every call, only include tools relevant to the current task. This reduces per-turn system prompt overhead by 30-50%.
Constant Summary collapse
- BASE_TOOLS =
%w[ read_file write_file edit_file glob grep bash ].freeze
- TASK_TOOLS =
{ testing: %w[run_specs].freeze, git: %w[git_status git_diff git_log git_commit].freeze, review: %w[review_pr git_diff].freeze, explore: %w[spawn_agent].freeze, web: %w[web_search web_fetch].freeze, memory: %w[memory_search memory_write].freeze, skills: %w[load_skill].freeze, tasks: %w[task].freeze, teams: %w[spawn_teammate send_message read_inbox].freeze, rails: %w[rails_generate db_migrate bundle_install bundle_add].freeze, background: %w[background_run].freeze, interaction: %w[ask_user compact].freeze }.freeze
Class Method Summary collapse
-
.active_tools(task_context: nil, discovered_tools: Set.new, codebase_index: nil, message: nil) ⇒ Array<String>
Returns tool names relevant to the detected task context.
-
.detect_context(message, codebase_index: nil) ⇒ Symbol?
Detect task context from a user message.
-
.detect_index_contexts(message, codebase_index) ⇒ Array<Symbol>
Detect additional tool contexts based on codebase index content.
-
.filter(all_definitions, active_names:) ⇒ Array<Hash>
Filter full tool definitions to only include active tools.
Class Method Details
.active_tools(task_context: nil, discovered_tools: Set.new, codebase_index: nil, message: nil) ⇒ Array<String>
Returns tool names relevant to the detected task context.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/rubyn_code/agent/dynamic_tool_schema.rb', line 37 def active_tools(task_context: nil, discovered_tools: Set.new, codebase_index: nil, message: nil) tools = BASE_TOOLS.dup # Always include interaction tools tools.concat(TASK_TOOLS[:interaction]) tools.concat(TASK_TOOLS[:memory]) # Add task-specific tools if task_context context_tools = resolve_context_tools(task_context) tools.concat(context_tools) end # Add index-aware tools when a codebase index and message are available if codebase_index && index_contexts = detect_index_contexts(, codebase_index) index_contexts.each { |ctx| tools.concat(resolve_context_tools(ctx)) } end # Always include previously discovered tools tools.concat(discovered_tools.to_a) tools.uniq end |
.detect_context(message, codebase_index: nil) ⇒ Symbol?
Detect task context from a user message.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rubyn_code/agent/dynamic_tool_schema.rb', line 67 def detect_context(, codebase_index: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity -- context detection dispatch msg = .to_s.downcase return :testing if msg.match?(/\b(test|spec|rspec)\b/) return :git if msg.match?(/\b(commit|push|diff|branch|merge|git)\b/) return :review if msg.match?(/\b(review|pr|pull request)\b/) return :rails if msg.match?(/\b(migrate|generate|scaffold|rails)\b/) return :web if msg.match?(/\b(search|fetch|url|http|api)\b/) return :explore if msg.match?(/\b(explore|architecture|structure)\b/) return :teams if msg.match?(/\b(team|spawn|message|inbox)\b/) # Fall back to index-based detection when keyword matching yields nothing return nil unless codebase_index index_contexts = detect_index_contexts(, codebase_index) index_contexts.first end |
.detect_index_contexts(message, codebase_index) ⇒ Array<Symbol>
Detect additional tool contexts based on codebase index content.
89 90 91 92 93 94 95 96 97 98 |
# File 'lib/rubyn_code/agent/dynamic_tool_schema.rb', line 89 def detect_index_contexts(, codebase_index) contexts = [] return contexts unless codebase_index contexts << :rails if (, codebase_index) contexts << :testing if (, codebase_index) contexts.uniq rescue StandardError [] end |
.filter(all_definitions, active_names:) ⇒ Array<Hash>
Filter full tool definitions to only include active tools.
105 106 107 108 109 110 111 |
# File 'lib/rubyn_code/agent/dynamic_tool_schema.rb', line 105 def filter(all_definitions, active_names:) name_set = active_names.to_set all_definitions.select do |defn| name = defn[:name] || defn['name'] name_set.include?(name) end end |