Class: SignalWire::Skills::SkillRegistry
- Inherits:
-
Object
- Object
- SignalWire::Skills::SkillRegistry
- Defined in:
- lib/signalwire/skills/skill_registry.rb
Overview
Global registry mapping skill names to factory lambdas.
SkillRegistry.register('datetime') { |params| DateTimeSkill.new(params) }
factory = SkillRegistry.get_factory('datetime')
skill = factory.call({ 'timezone' => 'UTC' })
Instance Attribute Summary collapse
-
#external_paths ⇒ Object
readonly
External skill directories registered via #add_skill_directory.
-
#last_registered ⇒ Object
readonly
The most recently registered skill name (instance form).
-
#logger ⇒ Object
readonly
Python parity: “self.logger = get_logger(“skill_registry”)“.
Class Method Summary collapse
-
._list_skills_full ⇒ Object
private
Full skill metadata (Python instance-method parity for SkillRegistry.list_skills).
-
.get_all_skills_schema ⇒ Hash{String => Hash}
Get complete schema for all registered skills.
-
.get_factory(skill_name) ⇒ Proc?
Get the factory for a skill.
-
.list_skills ⇒ Array<String>
List all registered skill names.
-
.register(skill_name) {|params| ... } ⇒ Object
Register a skill factory.
-
.register_builtins! ⇒ Object
Register all built-in skills.
-
.register_skill(skill_name, factory) ⇒ Object
Register with an explicit lambda / proc instead of a block.
-
.registered?(skill_name) ⇒ Boolean
Check if a skill is registered.
-
.reset! ⇒ Object
Clear all registrations (primarily for testing).
Instance Method Summary collapse
-
#add_skill_directory(path) ⇒ void
Add a directory to search for skills.
-
#get_all_skills_schema ⇒ Hash{String => Hash}
Get complete schema for all registered skills (instance form).
-
#initialize ⇒ SkillRegistry
constructor
Per-instance state for the skill-directory parity surface; the class-method API above is preserved for backwards compatibility, but ‘add_skill_directory` mirrors Python’s instance-method shape exactly (Python’s ‘signalwire.skills.registry.SkillRegistry`).
-
#list_skills ⇒ Array<Hash>
List all registered skill names (instance form).
-
#register_skill(skill_class_or_name, factory = nil) ⇒ Object
Register a skill class or factory (instance form).
Constructor Details
#initialize ⇒ SkillRegistry
Per-instance state for the skill-directory parity surface; the class-method API above is preserved for backwards compatibility, but ‘add_skill_directory` mirrors Python’s instance-method shape exactly (Python’s ‘signalwire.skills.registry.SkillRegistry`).
27 28 29 30 31 |
# File 'lib/signalwire/skills/skill_registry.rb', line 27 def initialize @external_paths = [] @inst_mutex = Mutex.new @logger = ::SignalWire::Logging.logger('skill_registry') end |
Instance Attribute Details
#external_paths ⇒ Object (readonly)
External skill directories registered via #add_skill_directory. Mirrors Python’s ‘_external_paths` accessor surface.
39 40 41 |
# File 'lib/signalwire/skills/skill_registry.rb', line 39 def external_paths @external_paths end |
#last_registered ⇒ Object (readonly)
The most recently registered skill name (instance form).
141 142 143 |
# File 'lib/signalwire/skills/skill_registry.rb', line 141 def last_registered @last_registered end |
#logger ⇒ Object (readonly)
Python parity: “self.logger = get_logger(“skill_registry”)“. Per-instance logger; the class-level API uses the same name.
35 36 37 |
# File 'lib/signalwire/skills/skill_registry.rb', line 35 def logger @logger end |
Class Method Details
._list_skills_full ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Full skill metadata (Python instance-method parity for SkillRegistry.list_skills). Returns one dict per skill with name + description + version when available.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/signalwire/skills/skill_registry.rb', line 179 def _list_skills_full @mutex.synchronize do @factories.keys.sort.map do |skill_name| entry = { 'name' => skill_name } factory = @factories[skill_name] if factory.respond_to?(:call) begin instance = factory.call({}) entry['description'] = instance.description if instance.respond_to?(:description) entry['version'] = instance.version if instance.respond_to?(:version) rescue StandardError # Skill needs constructor args; fall back to name-only. end end entry end end end |
.get_all_skills_schema ⇒ Hash{String => Hash}
Get complete schema for all registered skills.
Mirrors Python’s “SkillRegistry.get_all_skills_schema()“ — returns a hash keyed by skill name, with each value containing parameter metadata. Ruby skills don’t carry rich Python-style parameter introspection in v1, so the value defaults to a minimal shape with the skill name; built-in skills that expose “parameter_schema“ get richer detail.
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/signalwire/skills/skill_registry.rb', line 229 def get_all_skills_schema @mutex.synchronize do @factories.keys.sort.each_with_object({}) do |name, h| entry = { 'name' => name, 'parameters' => {} } factory = @factories[name] if factory.respond_to?(:call) begin instance = factory.call({}) if instance.respond_to?(:parameter_schema) entry['parameters'] = instance.parameter_schema || {} end if instance.class.respond_to?(:skill_description) entry['description'] = instance.class.skill_description end if instance.class.respond_to?(:skill_version) entry['version'] = instance.class.skill_version end rescue StandardError # If we can't instantiate without params, fall back to # the minimal entry. end end h[name] = entry end end end |
.get_factory(skill_name) ⇒ Proc?
Get the factory for a skill.
165 166 167 |
# File 'lib/signalwire/skills/skill_registry.rb', line 165 def get_factory(skill_name) @mutex.synchronize { @factories[skill_name.to_s] } end |
.list_skills ⇒ Array<String>
List all registered skill names.
171 172 173 |
# File 'lib/signalwire/skills/skill_registry.rb', line 171 def list_skills @mutex.synchronize { @factories.keys.dup } end |
.register(skill_name) {|params| ... } ⇒ Object
Register a skill factory.
147 148 149 150 151 |
# File 'lib/signalwire/skills/skill_registry.rb', line 147 def register(skill_name, &block) @mutex.synchronize do @factories[skill_name.to_s] = block end end |
.register_builtins! ⇒ Object
Register all built-in skills. Called at load time.
211 212 213 214 215 216 |
# File 'lib/signalwire/skills/skill_registry.rb', line 211 def register_builtins! # Each builtin file calls SkillRegistry.register on require. # We just need to require them all. builtin_dir = File.join(__dir__, 'builtin') Dir[File.join(builtin_dir, '*.rb')].sort.each { |f| require f } end |
.register_skill(skill_name, factory) ⇒ Object
Register with an explicit lambda / proc instead of a block.
156 157 158 159 160 |
# File 'lib/signalwire/skills/skill_registry.rb', line 156 def register_skill(skill_name, factory) @mutex.synchronize do @factories[skill_name.to_s] = factory end end |
.registered?(skill_name) ⇒ Boolean
Check if a skill is registered.
201 202 203 |
# File 'lib/signalwire/skills/skill_registry.rb', line 201 def registered?(skill_name) @mutex.synchronize { @factories.key?(skill_name.to_s) } end |
.reset! ⇒ Object
Clear all registrations (primarily for testing).
206 207 208 |
# File 'lib/signalwire/skills/skill_registry.rb', line 206 def reset! @mutex.synchronize { @factories.clear } end |
Instance Method Details
#add_skill_directory(path) ⇒ void
This method returns an undefined value.
Add a directory to search for skills.
Mirrors Python’s ‘SkillRegistry.add_skill_directory`: validate that the path exists and is a directory, then append it (de-duplicated) to `@external_paths`. Raises `ArgumentError` (the Ruby analog of Python’s ‘ValueError`) for invalid input.
52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/signalwire/skills/skill_registry.rb', line 52 def add_skill_directory(path) @inst_mutex.synchronize do unless File.exist?(path) raise ArgumentError, "Skill directory does not exist: #{path}" end unless File.directory?(path) raise ArgumentError, "Path is not a directory: #{path}" end @external_paths << path unless @external_paths.include?(path) end end |
#get_all_skills_schema ⇒ Hash{String => Hash}
Get complete schema for all registered skills (instance form).
Mirrors Python’s instance-method “SkillRegistry.get_all_skills_schema()“ — returns a hash keyed by skill name, each value containing parameter metadata. Ruby skills don’t carry rich Python-style parameter introspection in v1, so the value defaults to a minimal shape with the skill name; built-ins that expose “parameter_schema“ get richer detail.
75 76 77 |
# File 'lib/signalwire/skills/skill_registry.rb', line 75 def get_all_skills_schema self.class.get_all_skills_schema end |
#list_skills ⇒ Array<Hash>
List all registered skill names (instance form).
Python parity: “SkillRegistry.list_skills(self)“ returns a list of dictionaries describing each skill. Ruby v1 returns the registered names plus available metadata (description / version) when the factory can be instantiated without arguments.
87 88 89 |
# File 'lib/signalwire/skills/skill_registry.rb', line 87 def list_skills self.class.send(:_list_skills_full) end |
#register_skill(skill_class_or_name, factory = nil) ⇒ Object
Register a skill class or factory (instance form).
Python parity: “SkillRegistry.register_skill(self, skill_class)“ accepts a SkillBase subclass and stores its factory. Ruby accepts either a class with a “new(params)“ constructor, a “Proc“ /“Lambda“, or a 2-arg “(name, factory)“ form for explicit naming. Returns “self“ for chaining.
104 105 106 107 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 |
# File 'lib/signalwire/skills/skill_registry.rb', line 104 def register_skill(skill_class_or_name, factory = nil) if skill_class_or_name.is_a?(String) # Legacy 2-arg form: register_skill(name, factory) self.class.register_skill(skill_class_or_name, factory) return self end skill_class = skill_class_or_name unless skill_class.respond_to?(:new) raise ArgumentError, "register_skill expects a class with .new or a (name, factory) pair" end # Pull the skill name from a class-level method or constant. name = if skill_class.respond_to?(:skill_name) skill_class.skill_name elsif skill_class.const_defined?(:SKILL_NAME) skill_class.const_get(:SKILL_NAME) else # Try instantiating with no args to read .name from the # instance — Ruby idiom for skills that lack a # class-level constant. begin skill_class.new.name rescue StandardError nil end end raise ArgumentError, "Cannot determine skill name for #{skill_class}" if name.nil? self.class.register_skill(name.to_s, ->(params = {}) { skill_class.new(params) }) @inst_mutex.synchronize { @last_registered = name.to_s } self end |