Class: Aidp::Metadata::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/metadata/query.rb

Overview

Query interface for tool-choosing agent

Provides filtering, ranking, and dependency resolution for tools based on metadata criteria.

Examples:

Querying for tools

query = Query.new(cache: cache)
tools = query.find_by_tags(["ruby", "testing"])
ranked = query.rank_by_priority(tools)

Instance Method Summary collapse

Constructor Details

#initialize(cache:) ⇒ Query

Initialize query interface

Parameters:

  • cache (Cache)

    Metadata cache instance



22
23
24
25
# File 'lib/aidp/metadata/query.rb', line 22

def initialize(cache:)
  @cache = cache
  @directory = nil
end

Instance Method Details

#directoryHash

Load directory (lazy)

Returns:

  • (Hash)

    Tool directory



30
31
32
# File 'lib/aidp/metadata/query.rb', line 30

def directory
  @directory ||= @cache.load
end

#filter(type: nil, tags: nil, work_unit_type: nil, experimental: nil) ⇒ Array<Hash>

Filter tools by multiple criteria

Parameters:

  • type (String, nil) (defaults to: nil)

    Tool type filter

  • tags (Array<String>, nil) (defaults to: nil)

    Tag filter

  • work_unit_type (String, nil) (defaults to: nil)

    Work unit type filter

  • experimental (Boolean, nil) (defaults to: nil)

    Experimental filter (true/false/nil for all)

Returns:

  • (Array<Hash>)

    Filtered tools



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/aidp/metadata/query.rb', line 108

def filter(type: nil, tags: nil, work_unit_type: nil, experimental: nil)
  Aidp.log_debug(
    "metadata",
    "Filtering tools",
    type: type,
    tags: tags,
    work_unit_type: work_unit_type,
    experimental: experimental
  )

  tools = directory["tools"]

  # Filter by type
  tools = tools.select { |t| t["type"] == type } if type

  # Filter by tags
  if tags && !tags.empty?
    tags = Array(tags).map(&:downcase)
    tools = tools.select do |t|
      tool_tags = (t["applies_to"] || []).map(&:downcase)
      (tool_tags & tags).any?
    end
  end

  # Filter by work unit type
  if work_unit_type
    wut_lower = work_unit_type.downcase
    tools = tools.select do |t|
      (t["work_unit_types"] || []).map(&:downcase).include?(wut_lower)
    end
  end

  # Filter by experimental flag
  tools = tools.select { |t| t["experimental"] == experimental } unless experimental.nil?

  Aidp.log_debug("metadata", "Filtered tools", count: tools.size)

  tools
end

#find_by_id(id) ⇒ Hash?

Find tool by ID

Parameters:

  • id (String)

    Tool ID

Returns:

  • (Hash, nil)

    Tool metadata or nil



43
44
45
46
# File 'lib/aidp/metadata/query.rb', line 43

def find_by_id(id)
  tools = directory["tools"]
  tools.find { |tool| tool["id"] == id }
end

#find_by_tags(tags, match_all: false) ⇒ Array<Hash>

Find tools by applies_to tags

Parameters:

  • tags (Array<String>)

    Tags to filter by

  • match_all (Boolean) (defaults to: false)

    Whether to match all tags (AND) or any tag (OR)

Returns:

  • (Array<Hash>)

    Matching tools



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/aidp/metadata/query.rb', line 63

def find_by_tags(tags, match_all: false)
  Aidp.log_debug("metadata", "Finding by tags", tags: tags, match_all: match_all)

  tags = Array(tags).map(&:downcase)
  indexes = directory["indexes"]["by_tag"]

  if match_all
    # Find tools that have ALL specified tags
    tool_ids_sets = tags.map { |tag| indexes[tag] || [] }
    tool_ids = tool_ids_sets.reduce(&:&) || []
  else
    # Find tools that have ANY specified tag
    tool_ids = tags.flat_map { |tag| indexes[tag] || [] }.uniq
  end

  tools = tools_by_ids(tool_ids)

  Aidp.log_debug("metadata", "Found tools by tags", count: tools.size)

  tools
end

#find_by_type(type) ⇒ Array<Hash>

Find tools by type

Parameters:

  • type (String)

    Tool type (“skill”, “persona”, “template”)

Returns:

  • (Array<Hash>)

    Matching tools



52
53
54
55
56
# File 'lib/aidp/metadata/query.rb', line 52

def find_by_type(type)
  indexes = directory["indexes"]["by_type"]
  tool_ids = indexes[type] || []
  tools_by_ids(tool_ids)
end

#find_by_work_unit_type(work_unit_type) ⇒ Array<Hash>

Find tools by work unit type

Parameters:

  • work_unit_type (String)

    Work unit type (e.g., “implementation”, “analysis”)

Returns:

  • (Array<Hash>)

    Matching tools



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/aidp/metadata/query.rb', line 89

def find_by_work_unit_type(work_unit_type)
  Aidp.log_debug("metadata", "Finding by work unit type", type: work_unit_type)

  indexes = directory["indexes"]["by_work_unit_type"]
  tool_ids = indexes[work_unit_type.downcase] || []
  tools = tools_by_ids(tool_ids)

  Aidp.log_debug("metadata", "Found tools by work unit type", count: tools.size)

  tools
end

#find_dependents(tool_id) ⇒ Array<String>

Find dependents of a tool

Returns all tools that depend on this tool (directly or indirectly)

Parameters:

  • tool_id (String)

    Tool ID

Returns:

  • (Array<String>)

    List of dependent tool IDs



183
184
185
186
187
188
# File 'lib/aidp/metadata/query.rb', line 183

def find_dependents(tool_id)
  graph = directory["dependency_graph"]
  return [] unless graph[tool_id]

  graph[tool_id]["dependents"] || []
end

#rank_by_priority(tools) ⇒ Array<Hash>

Rank tools by priority (highest first)

Parameters:

  • tools (Array<Hash>)

    Tools to rank

Returns:

  • (Array<Hash>)

    Ranked tools



152
153
154
# File 'lib/aidp/metadata/query.rb', line 152

def rank_by_priority(tools)
  tools.sort_by { |t| -(t["priority"] || ::DEFAULT_PRIORITY) }
end

#reloadObject

Reload directory



35
36
37
# File 'lib/aidp/metadata/query.rb', line 35

def reload
  @directory = @cache.reload
end

#resolve_dependencies(tool_id) ⇒ Array<String>

Resolve dependencies for a tool

Returns all dependencies recursively in dependency order (topological sort)

Parameters:

  • tool_id (String)

    Tool ID

Returns:

  • (Array<String>)

    Ordered list of dependency IDs

Raises:



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/aidp/metadata/query.rb', line 163

def resolve_dependencies(tool_id)
  Aidp.log_debug("metadata", "Resolving dependencies", tool_id: tool_id)

  graph = directory["dependency_graph"]
  resolved = []
  seen = Set.new

  resolve_recursive(tool_id, graph, resolved, seen)

  Aidp.log_debug("metadata", "Dependencies resolved", tool_id: tool_id, dependencies: resolved)

  resolved
end

#statisticsHash

Get statistics about the tool directory

Returns:

  • (Hash)

    Statistics



193
194
195
# File 'lib/aidp/metadata/query.rb', line 193

def statistics
  directory["statistics"]
end