Class: Insika::Commands::SetSkillAgents
- Inherits:
-
Object
- Object
- Insika::Commands::SetSkillAgents
- Defined in:
- lib/insika/commands/set_skill_agents.rb
Overview
Control command: enables/disables a skill on N
agents at once, adjusting each one's profile.skills allowlist — and, with
eager_ids, which of them keep the body in the prompt on EVERY turn
(profile.skills_eager). Takes effect on the next dispatch (hot via
ProfileSource). -> { name, enabled_for, eager_for, skipped_all, skipped_eager_all }.
Both are per-agent decisions about the same skill, which is why they are one command: eagerness lives on the agent precisely BECAUSE the skill is shared, so the screen that says "which agents can load this" is the screen that says "and which of them always have it".
Allowlist semantics (AgentProfile): nil = ALL, [] = none, [names] = subset. Important and deliberate consequence:
- enabling on an agent with skills=nil: no-op (already has all).
- DISABLING on an agent with skills=nil: NOT done here — removing one from
"all" would require enumerating the catalog and materializing an explicit
allowlist (destructive/surprising). These agents are left intact and
go into
skipped_all. To restrict, use an explicit :set_agent_tools/allowlist first.
skills_eager is NOT allowlist semantics (nil = NONE, see
SkillCatalog#eager_for), so the two fields are adjusted by different rules: nil
there is an empty set that can simply be added to, and only the BLANKET true
has the same "cannot remove one name from all" problem (-> skipped_eager_all).
Instance Method Summary collapse
- #call(command) ⇒ Object
-
#initialize(profile_source:, event_stream:) ⇒ SetSkillAgents
constructor
A new instance of SetSkillAgents.
Constructor Details
#initialize(profile_source:, event_stream:) ⇒ SetSkillAgents
Returns a new instance of SetSkillAgents.
32 33 34 35 |
# File 'lib/insika/commands/set_skill_agents.rb', line 32 def initialize(profile_source:, event_stream:) @profile_source = profile_source @event_stream = event_stream end |
Instance Method Details
#call(command) ⇒ Object
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/insika/commands/set_skill_agents.rb', line 37 def call(command) p = AgentPayload.symbolize(command.payload) name = AgentPayload.presence(p[:name]) raise Insika::ValidationError, "name is required" if name.nil? raise Insika::ValidationError, "agent_ids must be a list" unless p[:agent_ids].nil? || p[:agent_ids].is_a?(Array) raise Insika::ValidationError, "eager_ids must be a list" unless p[:eager_ids].nil? || p[:eager_ids].is_a?(Array) wanted = Array(p[:agent_ids]).map(&:to_s) # eager_ids ABSENT means "this form does not manage eagerness" — leave every # profile's setting alone. An empty ARRAY means "none of them", which is a real # instruction and must be applied. `nil` and `[]` are not the same request. eager_wanted = p[:eager_ids].nil? ? nil : Array(p[:eager_ids]).map(&:to_s) result = { enabled_for: [], eager_for: [], skipped_all: [], skipped_eager_all: [] } @profile_source.all.each { |profile| apply(profile, name, wanted, eager_wanted, result) } @event_stream.emit(Insika::Event.new( type: :skill_agents_set, data: { name: name, agent_ids: wanted, eager_ids: eager_wanted, skipped_all: result[:skipped_all] }.compact, meta: { at: Time.now.utc.iso8601 } )) { name: name }.merge(result) end |