Class: PWN::Plugins::REPL::AISwarm::Controller

Inherits:
Object
  • Object
show all
Defined in:
lib/pwn/plugins/repl/ai_swarm.rb

Overview

Session-scoped swarm jobs. Workers never draw the terminal.

Constant Summary collapse

MAX_JOBS =

rubocop:disable Metrics/ClassLength -- one session-scoped swarm command surface

8
ACTIVE =
%w[queued running steering cancelling].freeze

Instance Method Summary collapse

Constructor Details

#initialize(session_id:) ⇒ Controller

Returns a new instance of Controller.



39
40
41
42
43
44
45
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 39

def initialize(session_id:)
  @session_id = session_id.to_s
  @mutex = Mutex.new
  @jobs = {}
  @swarm_id = nil
  @closed = false
end

Instance Method Details

#busy? ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 71

def busy?
  snapshot[:jobs].any? { |job| ACTIVE.include?(job[:state]) }
end

#cancel_all ⇒ Object



81
82
83
84
85
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 81

def cancel_all
  ids = snapshot[:jobs].select { |job| ACTIVE.include?(job[:state]) }.map { |job| job[:id] }
  ids.each { |id| cancel(id) }
  { ok: true, cancelled: ids.length }
end

#close ⇒ Object



87
88
89
90
91
92
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 87

def close
  @closed = true
  cancel_all
  workers.each { |worker| worker.join(30) }
  { ok: true }
end

#completion_context ⇒ Object



66
67
68
69
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 66

def completion_context
  snap = snapshot
  { swarm_id: snap[:swarm_id], jobs: snap[:jobs], agents: agents }
end

#execute(opts = {}) ⇒ Object



47
48
49
50
51
52
53
54
55
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 47

def execute(opts = {})
  line = opts[:line].to_s.strip
  tokens = Shellwords.split(line)
  tokens.shift if tokens.first == '/swarm'
  command = tokens.shift || 'help'
  dispatch(command, tokens, opts)
rescue StandardError => e
  { ok: false, error: "#{e.class}: #{e.message}" }
end

#roster ⇒ Object



75
76
77
78
79
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 75

def roster
  PWN::AI::Agent::Swarm.personas(swarm_id: @swarm_id).map do |name, persona|
    { name: name.to_s, role: persona[:role].to_s, engine: (persona[:engine] || 'inherit').to_s, model: (persona[:model] || 'provider default').to_s }
  end
end

#snapshot ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/pwn/plugins/repl/ai_swarm.rb', line 57

def snapshot
  @mutex.synchronize do
    {
      swarm_id: @swarm_id,
      jobs: @jobs.values.map { |job| job.slice(:id, :agent, :state, :command, :result, :error, :last_tool).transform_values { |value| value.is_a?(String) ? value.dup : value } }
    }
  end
end