pwn 0.5.658 → 0.5.660

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84155e448029c5d41ebd8dda5e4c00147a3283ebf8258c42f2fdf7cb3f159616
4
- data.tar.gz: ceecb743a07ddf4d0a2f45434f1b7816e859754762d60f8932f9dd1f4a83d80a
3
+ metadata.gz: '06678f228c6acc69d9fb173f01f3825af6a7a8dcffcb8ed24c865bf281e0c65c'
4
+ data.tar.gz: 9967223f974d122e30cbb4be7aea369108e28b951ace091a1ed90d54825a4720
5
5
  SHA512:
6
- metadata.gz: 5cb1bf7948fa027253fa5e2aeb2204d917bf51ab4ebf2710073b8ca3c4fa07f53012a3e8f98e5db5f3dabda050b405119dadf78b7a5583476da35fd11af5c5c7
7
- data.tar.gz: 07e6832ea6946949d3042f62b03930d5e6f882dd8f246449f314c994459b4f16ce4e32700ab4467b55d44e01f5ba35dbc3788f742d44a7fd79b36026b2d61ccf
6
+ metadata.gz: 6feb604302f7e6fd428e8dcd2d1c6a888ed2e6d4c96f3e7b75b6537a5694c3053da6a69da751275c8c168f627f6b71b031ed502cf02b1b0eb8bb2dfd72e2e354
7
+ data.tar.gz: 26f65f4e16312694c1163b0de7fe0545ca8ad7b8e1cdea647d931f131de6aaef89f0fe8b39be72509932295c1ad1521066c88722d5654cb6a856891c1c19e860
data/Gemfile CHANGED
@@ -20,7 +20,7 @@ gem 'base32', '0.3.4'
20
20
  gem 'bitcoin-ruby', '0.0.20'
21
21
  gem 'brakeman', '8.0.5'
22
22
  gem 'bson', '5.2.0'
23
- gem 'bundler', '>=4.0.17'
23
+ gem 'bundler', '>=4.0.18'
24
24
  gem 'bundler-audit', '>=0.9.3'
25
25
  gem 'bunny', '3.1.0'
26
26
  gem 'colorize', '1.1.0'
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PWN
4
+ module AI
5
+ module Agent
6
+ # Coalesce a burst of tool calls into periodic
7
+ # "summary_of_current_task" UI lines without stopping the loop.
8
+ module TaskSummarizer
9
+ DEFAULT_EVERY = 5
10
+ DEFAULT_INTERVAL_S = 8.0
11
+ MAX_BUFFER = 64
12
+
13
+ module_function
14
+
15
+ def enabled?
16
+ v = PWN::Env.dig(:ai, :agent, :task_summary)
17
+ v.nil? || !!v
18
+ rescue StandardError
19
+ true
20
+ end
21
+
22
+ def verbose?
23
+ !!PWN::Env.dig(:ai, :agent, :task_summary_verbose)
24
+ rescue StandardError
25
+ false
26
+ end
27
+
28
+ def every_n
29
+ n = PWN::Env.dig(:ai, :agent, :task_summary_every)
30
+ n = DEFAULT_EVERY if n.nil?
31
+ [n.to_i, 1].max
32
+ rescue StandardError
33
+ DEFAULT_EVERY
34
+ end
35
+
36
+ def interval_s
37
+ t = PWN::Env.dig(:ai, :agent, :task_summary_interval_s)
38
+ t = DEFAULT_INTERVAL_S if t.nil?
39
+ [t.to_f, 1.0].max
40
+ rescue StandardError
41
+ DEFAULT_INTERVAL_S
42
+ end
43
+
44
+ # Per-run state (also safe for nested/swarm if callers keep their own hash)
45
+ def fresh(opts = {})
46
+ {
47
+ request: opts[:request].to_s,
48
+ events: [],
49
+ since_emit: 0,
50
+ last_emit_at: Time.now,
51
+ total: 0,
52
+ counts: Hash.new(0)
53
+ }
54
+ end
55
+
56
+ def record!(state, name, args, result)
57
+ return nil unless state
58
+
59
+ preview = args.is_a?(String) ? args.to_s[0, 60] : args.inspect[0, 60]
60
+ rs = result.to_s
61
+ ok = !rs.match?(/\A\s*\{?\s*"?(success|ok)"?\s*=>\s*false/i) &&
62
+ !rs.match?(/ERROR:|Traceback|NoMethodError|StandardError/i)
63
+ state[:events] << { name: name.to_s, preview: preview, ok: ok, t: Time.now }
64
+ state[:events].shift while state[:events].size > MAX_BUFFER
65
+ state[:counts][name.to_s] += 1
66
+ state[:total] += 1
67
+ state[:since_emit] += 1
68
+
69
+ due = state[:since_emit] >= every_n ||
70
+ (Time.now - state[:last_emit_at]) >= interval_s
71
+ due ? emit!(state) : nil
72
+ end
73
+
74
+ def emit!(state, final: false)
75
+ return nil if state.nil? || state[:events].empty?
76
+
77
+ counts = state[:counts].sort_by { |_, c| -c }.map { |n, c| "#{n}×#{c}" }
78
+ recent = state[:events].last(every_n)
79
+ focus = recent.map { |e| e[:name] }.uniq.first(4).join(', ')
80
+ fails = state[:events].count { |e| !e[:ok] }
81
+ tail = recent.map { |e| e[:preview] }.compact.reject(&:empty?).last
82
+ bit = tail && !tail.empty? ? "; e.g. #{tail}" : ''
83
+ fail_bit = fails.positive? ? "; failures=#{fails}" : ''
84
+ phase = final ? 'done' : 'in progress'
85
+ state[:since_emit] = 0
86
+ state[:last_emit_at] = Time.now
87
+ "#{phase}: #{focus} — #{state[:total]} tools (#{counts.first(6).join(', ')})#{fail_bit}#{bit}"
88
+ end
89
+
90
+ def flush!(state)
91
+ emit!(state, final: true)
92
+ end
93
+
94
+ # Author(s):: 0day Inc. <support@0dayinc.com>
95
+
96
+ public_class_method def self.authors
97
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
98
+ end
99
+
100
+ # Display Usage for this Module
101
+
102
+ public_class_method def self.help
103
+ puts <<~USAGE
104
+ USAGE:
105
+ state = PWN::AI::Agent::TaskSummarizer.fresh(request: 'do the thing')
106
+ line = PWN::AI::Agent::TaskSummarizer.record!(state, 'shell', 'ls', '{success:true}')
107
+ line = PWN::AI::Agent::TaskSummarizer.flush!(state)
108
+ PWN::AI::Agent::TaskSummarizer.enabled?
109
+ PWN::AI::Agent::TaskSummarizer.verbose?
110
+ PWN::AI::Agent::TaskSummarizer.every_n
111
+ PWN::AI::Agent::TaskSummarizer.interval_s
112
+
113
+ #{self}.authors
114
+ USAGE
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
data/lib/pwn/ai/agent.rb CHANGED
@@ -31,6 +31,7 @@ module PWN
31
31
  autoload :Swarm, 'pwn/ai/agent/swarm'
32
32
  autoload :Reward, 'pwn/ai/agent/reward'
33
33
  autoload :Curriculum, 'pwn/ai/agent/curriculum'
34
+ autoload :TaskSummarizer, 'pwn/ai/agent/task_summarizer'
34
35
 
35
36
  # Display a List of Every PWN::AI Module
36
37
 
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.658'
4
+ VERSION = '0.5.660'
5
5
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PWN::AI::Agent::TaskSummarizer do
6
+ it 'fresh method should exist' do
7
+ expect(described_class).to respond_to :fresh
8
+ end
9
+
10
+ it 'record! method should exist' do
11
+ expect(described_class).to respond_to :record!
12
+ end
13
+
14
+ it 'emit! method should exist' do
15
+ expect(described_class).to respond_to :emit!
16
+ end
17
+
18
+ it 'flush! method should exist' do
19
+ expect(described_class).to respond_to :flush!
20
+ end
21
+
22
+ it 'enabled? method should exist' do
23
+ expect(described_class).to respond_to :enabled?
24
+ end
25
+
26
+ it 'should display information for authors' do
27
+ expect(described_class).to respond_to :authors
28
+ end
29
+
30
+ it 'should display information for existing help method' do
31
+ expect(described_class).to respond_to :help
32
+ end
33
+
34
+ it 'coalesces tool bursts into a summary line' do
35
+ allow(PWN::Env).to receive(:dig).and_call_original
36
+ allow(PWN::Env).to receive(:dig).with(:ai, :agent, :task_summary_every).and_return(2)
37
+ allow(PWN::Env).to receive(:dig).with(:ai, :agent, :task_summary_interval_s).and_return(9_999)
38
+ allow(PWN::Env).to receive(:dig).with(:ai, :agent, :task_summary).and_return(true)
39
+ allow(PWN::Env).to receive(:dig).with(:ai, :agent, :task_summary_verbose).and_return(false)
40
+
41
+ state = described_class.fresh(request: 'fix rake')
42
+ expect(described_class.record!(state, 'shell', 'rake', '{success:true}')).to be_nil
43
+ line = described_class.record!(state, 'shell', 'rake 2>&1', '{success:true}')
44
+ expect(line).to be_a(String)
45
+ expect(line).to include('in progress')
46
+ expect(line).to include('shell')
47
+ expect(state[:total]).to eq 2
48
+
49
+ fin = described_class.flush!(state)
50
+ expect(fin).to include('done')
51
+ expect(fin).to include('2 tools')
52
+ end
53
+ end
@@ -460,6 +460,16 @@
460
460
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Swarm.retire Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Swarm.retire`: Supported Method Parameters\n\nPWN::AI::Agent::Swarm.retire(name: ‘required - persona name’)\n"}]}
461
461
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Swarm.spawn Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Swarm.spawn`: Supported Method Parameters\n\nPWN::AI::Agent::Swarm.spawn(\n\nname: 'required - persona name (snake_case)',\nrole: 'required - system_role_content overlay for this persona',\ntoolsets: 'optional - Array of Registry toolset names',\nengine: 'optional - :openai / :anthropic / :grok / :gemini / :ollama',\nmax_iters: 'optional - per-turn iteration cap for this persona'\n\n)\n"}]}
462
462
  {"messages":[{"role":"user","content":"PWN::AI::Agent::Swarm.with_persona_env Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Swarm.with_persona_env`: "}]}
463
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.authors Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
464
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.help Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.help`: "}]}
465
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.emit! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.emit!`: "}]}
466
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.enabled? Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.enabled?`: "}]}
467
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.every_n Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.every_n`: "}]}
468
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.flush! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.flush!`: "}]}
469
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.fresh Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.fresh`: "}]}
470
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.interval_s Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.interval_s`: "}]}
471
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.record! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.record!`: "}]}
472
+ {"messages":[{"role":"user","content":"PWN::AI::Agent::TaskSummarizer.verbose? Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TaskSummarizer.verbose?`: "}]}
463
473
  {"messages":[{"role":"user","content":"PWN::AI::Agent::TransparentBrowser.analyze Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TransparentBrowser.analyze`: Supported Method Parameters\n\nai_analysis = PWN::AI::Agent::TransparentBrowser.analyze(\n\nrequest: 'required - current step in the JavaScript debugging session to analyze',\nsource_to_review: 'required - the block of JavaScript code in which the current step resides'\n\n)\n"}]}
464
474
  {"messages":[{"role":"user","content":"PWN::AI::Agent::TransparentBrowser.authors Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TransparentBrowser.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
465
475
  {"messages":[{"role":"user","content":"PWN::AI::Agent::TransparentBrowser.help Usage"},{"role":"assistant","content":"`PWN::AI::Agent::TransparentBrowser.help`: "}]}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.658
4
+ version: 0.5.660
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -141,14 +141,14 @@ dependencies:
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
- version: 4.0.17
144
+ version: 4.0.18
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - ">="
150
150
  - !ruby/object:Gem::Version
151
- version: 4.0.17
151
+ version: 4.0.18
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: bundler-audit
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -1856,6 +1856,7 @@ files:
1856
1856
  - lib/pwn/ai/agent/reward.rb
1857
1857
  - lib/pwn/ai/agent/sast.rb
1858
1858
  - lib/pwn/ai/agent/swarm.rb
1859
+ - lib/pwn/ai/agent/task_summarizer.rb
1859
1860
  - lib/pwn/ai/agent/tools/cron.rb
1860
1861
  - lib/pwn/ai/agent/tools/curriculum.rb
1861
1862
  - lib/pwn/ai/agent/tools/extrospection.rb
@@ -2317,6 +2318,7 @@ files:
2317
2318
  - spec/lib/pwn/ai/agent/reward_spec.rb
2318
2319
  - spec/lib/pwn/ai/agent/sast_spec.rb
2319
2320
  - spec/lib/pwn/ai/agent/swarm_spec.rb
2321
+ - spec/lib/pwn/ai/agent/task_summarizer_spec.rb
2320
2322
  - spec/lib/pwn/ai/agent/tools/cron_spec.rb
2321
2323
  - spec/lib/pwn/ai/agent/tools/curriculum_spec.rb
2322
2324
  - spec/lib/pwn/ai/agent/tools/extrospection_spec.rb
@@ -2717,7 +2719,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
2717
2719
  - !ruby/object:Gem::Version
2718
2720
  version: '0'
2719
2721
  requirements: []
2720
- rubygems_version: 4.0.17
2722
+ rubygems_version: 4.0.18
2721
2723
  specification_version: 4
2722
2724
  summary: Automated Security Testing for CI/CD Pipelines & Beyond
2723
2725
  test_files: []