pwn 0.5.749 → 0.5.751

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/documentation/Blockchain.md +107 -9
  4. data/documentation/pwn-ai-Agent.md +310 -4
  5. data/documentation/pwn_silent_help_learn_demo.gif +0 -0
  6. data/etc/default_skills/pwn/banner/SKILL.md +7 -3
  7. data/etc/default_skills/pwn/blockchain/btc/SKILL.md +8 -5
  8. data/etc/default_skills/pwn/blockchain/eth/SKILL.md +12 -3
  9. data/etc/default_skills/pwn/blockchain/eth/references/urls.md +1 -1
  10. data/etc/default_skills/pwn/plugins/repl/SKILL.md +5 -0
  11. data/etc/default_skills/pwn/plugins/repl/ai/SKILL.md +4 -0
  12. data/etc/default_skills/pwn/plugins/repl/ai/references/urls.md +5 -0
  13. data/etc/default_skills/pwn/plugins/repl/ai_console/SKILL.md +48 -0
  14. data/etc/default_skills/pwn/plugins/repl/ai_console_commands/SKILL.md +47 -0
  15. data/etc/default_skills/pwn/plugins/repl/ai_console_usage/SKILL.md +48 -0
  16. data/etc/default_skills/pwn/plugins/repl/ai_swarm/SKILL.md +46 -0
  17. data/lib/pwn/ai/agent/loop.rb +287 -18
  18. data/lib/pwn/ai/agent/swarm.rb +28 -4
  19. data/lib/pwn/ai/open_ai.rb +4 -2
  20. data/lib/pwn/banner.rb +743 -2
  21. data/lib/pwn/blockchain/btc.rb +494 -196
  22. data/lib/pwn/blockchain/eth.rb +440 -81
  23. data/lib/pwn/blockchain.rb +6 -0
  24. data/lib/pwn/config.rb +22 -0
  25. data/lib/pwn/migrate.rb +9 -1
  26. data/lib/pwn/plugins/repl/ai.rb +182 -17
  27. data/lib/pwn/plugins/repl/ai_console.rb +1581 -0
  28. data/lib/pwn/plugins/repl/ai_console_commands.rb +282 -0
  29. data/lib/pwn/plugins/repl/ai_console_usage.rb +144 -0
  30. data/lib/pwn/plugins/repl/ai_swarm.rb +375 -0
  31. data/lib/pwn/plugins/repl.rb +25 -3
  32. data/lib/pwn/version.rb +1 -1
  33. data/spec/lib/pwn/ai/agent/loop_spec.rb +258 -1
  34. data/spec/lib/pwn/ai/agent/turn_finalizer_spec.rb +3 -2
  35. data/spec/lib/pwn/ai/open_ai_spec.rb +5 -0
  36. data/spec/lib/pwn/banner_spec.rb +643 -0
  37. data/spec/lib/pwn/blockchain/btc_spec.rb +372 -1
  38. data/spec/lib/pwn/blockchain/eth_spec.rb +205 -0
  39. data/spec/lib/pwn/blockchain_spec.rb +6 -0
  40. data/spec/lib/pwn/config_spec.rb +10 -0
  41. data/spec/lib/pwn/migrate_spec.rb +40 -3
  42. data/spec/lib/pwn/plugins/repl/ai_console_commands_spec.rb +65 -0
  43. data/spec/lib/pwn/plugins/repl/ai_console_spec.rb +1434 -0
  44. data/spec/lib/pwn/plugins/repl/ai_console_usage_spec.rb +29 -0
  45. data/spec/lib/pwn/plugins/repl/ai_swarm_spec.rb +127 -0
  46. data/spec/lib/pwn/plugins/repl_pwn_vault_spec.rb +5 -3
  47. data/spec/lib/pwn/plugins/repl_spec.rb +167 -1
  48. data/third_party/pwn_rdoc.jsonl +229 -10
  49. metadata +18 -6
  50. data/etc/default_skills/pwn/blockchain/btc/references/urls.md +0 -3
@@ -111,14 +111,27 @@ module PWN
111
111
  end
112
112
 
113
113
  # Supported Method Parameters::
114
- # PWN::AI::Agent::Swarm.retire(name: 'required - persona name')
114
+ # PWN::AI::Agent::Swarm.retire(
115
+ # name: 'required - persona name',
116
+ # swarm_id: 'optional - swarm directory when local is true',
117
+ # local: 'optional - true retires only that swarm registry'
118
+ # )
115
119
 
116
120
  public_class_method def self.retire(opts = {})
117
121
  name = opts[:name].to_s
122
+ sid = opts[:swarm_id].to_s
123
+ if opts[:local] == true && !sid.empty?
124
+ path = File.join(SWARM_ROOT, sid, 'agents.yml')
125
+ all = load_personas_file(path: path)
126
+ gone = all.delete(name.to_sym)
127
+ File.write(path, YAML.dump(deep_stringify(hash: all))) if gone
128
+ return { name: name, removed: !gone.nil?, scope: :swarm }
129
+ end
130
+
118
131
  all = personas
119
132
  gone = all.delete(name.to_sym)
120
133
  File.write(AGENTS_FILE, YAML.dump(deep_stringify(hash: all))) if gone
121
- { name: name, removed: !gone.nil? }
134
+ { name: name, removed: !gone.nil?, scope: :global }
122
135
  end
123
136
 
124
137
  # ------------------------------------------------------------------
@@ -212,7 +225,9 @@ module PWN
212
225
  # request: 'required - what to ask/instruct the persona',
213
226
  # swarm_id: 'optional - join an existing swarm (created if omitted)',
214
227
  # to: 'optional - addressee recorded on the bus (default :all)',
215
- # on_tool: 'optional - ->(name, args, result) live-UI callback'
228
+ # on_tool: 'optional - ->(name, args, result) live-UI callback',
229
+ # steering: 'optional - Loop::Steering for this persona turn',
230
+ # usage_observer: 'optional - callable receiving provider usage'
216
231
  # )
217
232
 
218
233
  public_class_method def self.ask(opts = {})
@@ -246,6 +261,8 @@ module PWN
246
261
  Thread.current[:pwn_swarm_depth] = depth + 1
247
262
  Thread.current[:pwn_swarm_id] = sid
248
263
  reply = with_persona_env(persona: persona) do
264
+ prior_observer = Thread.current[:pwn_usage_observer]
265
+ Thread.current[:pwn_usage_observer] = opts[:usage_observer] if opts[:usage_observer]
249
266
  Loop.run(
250
267
  request: opts[:request].to_s,
251
268
  session_id: session_id,
@@ -253,8 +270,11 @@ module PWN
253
270
  core_only: empty_tools ? false : true,
254
271
  system_role_content: sys,
255
272
  on_tool: opts[:on_tool],
273
+ steering: opts[:steering],
256
274
  nested: true
257
275
  )
276
+ ensure
277
+ Thread.current[:pwn_usage_observer] = prior_observer
258
278
  end
259
279
 
260
280
  bus_append(swarm_id: sid, from: name, to: opts[:to] || :all, content: reply)
@@ -698,7 +718,9 @@ module PWN
698
718
 
699
719
  # Run retire and return its result
700
720
  #{self}.retire(
701
- name: 'optional - binary or identifier name'
721
+ name: 'required - persona name',
722
+ swarm_id: 'optional - swarm directory when local is true',
723
+ local: 'optional - true retires only that swarm registry'
702
724
  )
703
725
 
704
726
  # Swarm lifecycle & bus
@@ -730,6 +752,8 @@ module PWN
730
752
  swarm_id: 'optional - join an existing swarm (created if omitted)',
731
753
  to: 'optional - addressee recorded on the bus (default :all)',
732
754
  on_tool: 'optional - ->(name, args, result) live-UI callback',
755
+ steering: 'optional - Loop::Steering for this persona turn',
756
+ usage_observer: 'optional - callable receiving provider usage',
733
757
  from: 'optional - sender account or address to bind as operator (defaults to caller_label)',
734
758
  text_only: 'required - text only value consumed by #ask',
735
759
  unit: 'optional - claim key (host+phase) before the child runs',
@@ -676,6 +676,8 @@ module PWN
676
676
  http_body[:tool_choice] = opts[:tool_choice] if opts[:tool_choice]
677
677
 
678
678
  endpoint = api_endpoint(model: model, tools: opts[:tools])
679
+ effort = opts[:reasoning_effort] || engine[:reasoning_effort]
680
+ http_body[:reasoning_effort] = effort if reasoning && !effort.to_s.empty?
679
681
  if endpoint == 'responses'
680
682
  http_body = responses_http_body(
681
683
  model: model,
@@ -683,7 +685,7 @@ module PWN
683
685
  tools: opts[:tools],
684
686
  tool_choice: opts[:tool_choice],
685
687
  max_tokens: max_tokens,
686
- reasoning_effort: opts[:reasoning_effort] || engine[:reasoning_effort]
688
+ reasoning_effort: effort
687
689
  )
688
690
  end
689
691
 
@@ -791,7 +793,7 @@ module PWN
791
793
  body[:tool_choice] = tc
792
794
  end
793
795
  effort = opts[:reasoning_effort].to_s
794
- body[:reasoning] = { effort: effort, summary: 'auto' } if !effort.empty? && effort != 'none'
796
+ body[:reasoning] = { effort: effort, summary: 'auto' } unless effort.empty? || (effort == 'none' && model.to_s.start_with?('gpt-6-astra'))
795
797
  body
796
798
  end
797
799