pwn 0.5.722 → 0.5.724
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 +4 -4
- data/Gemfile +2 -2
- data/bin/pwn_setup +5 -5
- data/documentation/AI-Integration.md +34 -1
- data/documentation/Policy-Benchmark.md +296 -0
- data/documentation/Reinforcement-Learning.md +81 -3
- data/etc/default_skills/pwn/ai/agent/engagement/SKILL.md +1 -0
- data/etc/default_skills/pwn/ai/agent/metrics/SKILL.md +3 -0
- data/etc/default_skills/pwn/ai/agent/policy/SKILL.md +4 -1
- data/etc/default_skills/pwn/ai/agent/policy_evaluation/SKILL.md +49 -0
- data/etc/default_skills/pwn/ai/agent/registry/SKILL.md +2 -0
- data/etc/default_skills/pwn/ai/agent/reward/SKILL.md +3 -0
- data/etc/default_skills/pwn/ai/agent/swarm/SKILL.md +6 -0
- data/etc/default_skills/pwn/ai/agent/tools/capabilities/SKILL.md +45 -0
- data/etc/default_skills/pwn/ai/agent/tools/context/SKILL.md +45 -0
- data/etc/default_skills/pwn/ai/agent/verification/SKILL.md +48 -0
- data/etc/default_skills/pwn/ai/context/SKILL.md +50 -0
- data/etc/default_skills/pwn/ai/http_retry/SKILL.md +7 -0
- data/etc/default_skills/pwn/ai/http_retry/references/urls.md +4 -0
- data/etc/default_skills/pwn/ai/open_ai/SKILL.md +1 -0
- data/etc/default_skills/pwn/ai/open_ai/references/urls.md +1 -0
- data/etc/default_skills/pwn/plugins/findings/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/gdbmi/SKILL.md +55 -0
- data/etc/default_skills/pwn/plugins/ghidra_headless/SKILL.md +49 -0
- data/etc/default_skills/pwn/plugins/jobs/SKILL.md +5 -0
- data/etc/default_skills/pwn/plugins/packet/SKILL.md +3 -0
- data/etc/default_skills/pwn/plugins/preflight_checker/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/radare2/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/transparent_browser/SKILL.md +3 -0
- data/etc/default_skills/pwn/reports/engagement/SKILL.md +3 -2
- data/lib/pwn/ai/agent/curriculum.rb +37 -45
- data/lib/pwn/ai/agent/engagement.rb +59 -0
- data/lib/pwn/ai/agent/learning.rb +85 -52
- data/lib/pwn/ai/agent/loop.rb +72 -9
- data/lib/pwn/ai/agent/metrics.rb +52 -2
- data/lib/pwn/ai/agent/policy.rb +288 -49
- data/lib/pwn/ai/agent/policy_evaluation.rb +230 -0
- data/lib/pwn/ai/agent/registry.rb +44 -4
- data/lib/pwn/ai/agent/reward.rb +188 -46
- data/lib/pwn/ai/agent/swarm.rb +235 -35
- data/lib/pwn/ai/agent/tool_guard.rb +13 -1
- data/lib/pwn/ai/agent/tools/artifacts.rb +42 -0
- data/lib/pwn/ai/agent/tools/capabilities.rb +19 -0
- data/lib/pwn/ai/agent/tools/context.rb +38 -0
- data/lib/pwn/ai/agent/tools/finding_record.rb +18 -0
- data/lib/pwn/ai/agent/tools/fuzz_campaign.rb +10 -1
- data/lib/pwn/ai/agent/tools/job_run.rb +32 -0
- data/lib/pwn/ai/agent/tools/learning.rb +5 -6
- data/lib/pwn/ai/agent/tools/metrics.rb +16 -0
- data/lib/pwn/ai/agent/tools/pty_session.rb +4 -4
- data/lib/pwn/ai/agent/tools/ruby_eval.rb +6 -5
- data/lib/pwn/ai/agent/tools/shell.rb +10 -1
- data/lib/pwn/ai/agent/tools/skills.rb +30 -0
- data/lib/pwn/ai/agent/tools/swarm.rb +8 -2
- data/lib/pwn/ai/agent/verification.rb +202 -0
- data/lib/pwn/ai/agent.rb +2 -0
- data/lib/pwn/ai/context.rb +193 -0
- data/lib/pwn/ai/http_retry.rb +53 -7
- data/lib/pwn/ai/open_ai.rb +315 -45
- data/lib/pwn/ai.rb +1 -0
- data/lib/pwn/migrate.rb +10 -1
- data/lib/pwn/plugins/artifact_registry.rb +13 -6
- data/lib/pwn/plugins/findings.rb +48 -8
- data/lib/pwn/plugins/gdbmi.rb +128 -0
- data/lib/pwn/plugins/ghidra_headless.rb +104 -0
- data/lib/pwn/plugins/jobs.rb +53 -0
- data/lib/pwn/plugins/packet.rb +51 -0
- data/lib/pwn/plugins/preflight_checker.rb +29 -0
- data/lib/pwn/plugins/process_tube.rb +24 -7
- data/lib/pwn/plugins/radare2.rb +14 -2
- data/lib/pwn/plugins/transparent_browser.rb +64 -0
- data/lib/pwn/plugins.rb +2 -0
- data/lib/pwn/reports/engagement.rb +19 -0
- data/lib/pwn/sessions.rb +3 -1
- data/lib/pwn/version.rb +1 -1
- data/scripts/benchmark_policy.rb +376 -0
- data/spec/documentation/installation_md_spec.rb +18 -4
- data/spec/integration/reinforced_feedback_loop_spec.rb +33 -19
- data/spec/lib/pwn/ai/agent/curriculum_spec.rb +267 -0
- data/spec/lib/pwn/ai/agent/engagement_spec.rb +12 -0
- data/spec/lib/pwn/ai/agent/learning_spec.rb +100 -3
- data/spec/lib/pwn/ai/agent/loop_spec.rb +104 -0
- data/spec/lib/pwn/ai/agent/metrics_spec.rb +44 -0
- data/spec/lib/pwn/ai/agent/policy_evaluation_spec.rb +221 -0
- data/spec/lib/pwn/ai/agent/policy_spec.rb +246 -6
- data/spec/lib/pwn/ai/agent/registry_spec.rb +123 -0
- data/spec/lib/pwn/ai/agent/reward_spec.rb +196 -12
- data/spec/lib/pwn/ai/agent/swarm_spec.rb +121 -1
- data/spec/lib/pwn/ai/agent/tool_guard_spec.rb +6 -0
- data/spec/lib/pwn/ai/agent/tools/capabilities_spec.rb +14 -0
- data/spec/lib/pwn/ai/agent/tools/context_spec.rb +14 -0
- data/spec/lib/pwn/ai/agent/tools/job_run_spec.rb +2 -0
- data/spec/lib/pwn/ai/agent/tools/learning_spec.rb +25 -0
- data/spec/lib/pwn/ai/agent/verification_spec.rb +172 -0
- data/spec/lib/pwn/ai/context_spec.rb +48 -0
- data/spec/lib/pwn/ai/http_retry_spec.rb +27 -0
- data/spec/lib/pwn/ai/open_ai_oauth_transport_spec.rb +245 -0
- data/spec/lib/pwn/ai/open_ai_spec.rb +235 -0
- data/spec/lib/pwn/migrate_spec.rb +24 -0
- data/spec/lib/pwn/plugins/artifact_registry_spec.rb +10 -0
- data/spec/lib/pwn/plugins/findings_spec.rb +2 -0
- data/spec/lib/pwn/plugins/gdbmi_spec.rb +17 -0
- data/spec/lib/pwn/plugins/ghidra_headless_spec.rb +17 -0
- data/third_party/pwn_rdoc.jsonl +100 -4
- metadata +30 -5
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-ai-agent-tools-capabilities
|
|
3
|
+
description: Drive PWN::Ai::Agent::Tools::Capabilities from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::Ai::Agent::Tools::Capabilities
|
|
10
|
+
source: pwn/ai/agent/tools/capabilities.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::Ai::Agent::Tools::Capabilities
|
|
14
|
+
|
|
15
|
+
Public API for PWN::Ai::Agent::Tools::Capabilities.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::Ai::Agent::Tools::Capabilities` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/ai/agent/tools/capabilities.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::Ai::Agent::Tools::Capabilities.help
|
|
31
|
+
PWN::Ai::Agent::Tools::Capabilities.help(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- _(no public class methods parsed)_
|
|
37
|
+
|
|
38
|
+
## Source
|
|
39
|
+
|
|
40
|
+
`pwn/ai/agent/tools/capabilities.rb`
|
|
41
|
+
|
|
42
|
+
## Verification
|
|
43
|
+
|
|
44
|
+
`PWN::Ai::Agent::Tools::Capabilities.respond_to?(:help)` after the
|
|
45
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-ai-agent-tools-context
|
|
3
|
+
description: Drive PWN::Ai::Agent::Tools::Context from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::Ai::Agent::Tools::Context
|
|
10
|
+
source: pwn/ai/agent/tools/context.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::Ai::Agent::Tools::Context
|
|
14
|
+
|
|
15
|
+
Public API for PWN::Ai::Agent::Tools::Context.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::Ai::Agent::Tools::Context` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/ai/agent/tools/context.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::Ai::Agent::Tools::Context.help
|
|
31
|
+
PWN::Ai::Agent::Tools::Context.help(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- _(no public class methods parsed)_
|
|
37
|
+
|
|
38
|
+
## Source
|
|
39
|
+
|
|
40
|
+
`pwn/ai/agent/tools/context.rb`
|
|
41
|
+
|
|
42
|
+
## Verification
|
|
43
|
+
|
|
44
|
+
`PWN::Ai::Agent::Tools::Context.respond_to?(:help)` after the
|
|
45
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-ai-agent-verification
|
|
3
|
+
description: Drive PWN::AI::Agent::Verification from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::AI::Agent::Verification
|
|
10
|
+
source: pwn/ai/agent/verification.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::AI::Agent::Verification
|
|
14
|
+
|
|
15
|
+
Explicit host-owned acceptance checks, not a model-facing tool.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::AI::Agent::Verification` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/ai/agent/verification.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::AI::Agent::Verification.help
|
|
31
|
+
PWN::AI::Agent::Verification.run(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- `run`
|
|
37
|
+
- `snapshot`
|
|
38
|
+
- `authors`
|
|
39
|
+
- `help`
|
|
40
|
+
|
|
41
|
+
## Source
|
|
42
|
+
|
|
43
|
+
`pwn/ai/agent/verification.rb`
|
|
44
|
+
|
|
45
|
+
## Verification
|
|
46
|
+
|
|
47
|
+
`PWN::AI::Agent::Verification.respond_to?(:run)` after the
|
|
48
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-ai-context
|
|
3
|
+
description: Drive PWN::AI::Context from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::AI::Context
|
|
10
|
+
source: pwn/ai/context.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::AI::Context
|
|
14
|
+
|
|
15
|
+
Attach files, hexdumps, disassembly, and HTTP transcripts to model context with auto-chunking. Oversize artifacts are summarized inline and persisted under ~/.pwn/artifacts/<session_id>/ with SHA-256.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::AI::Context` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/ai/context.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::AI::Context.help
|
|
31
|
+
PWN::AI::Context.attach_file(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- `attach_file`
|
|
37
|
+
- `attach_hexdump`
|
|
38
|
+
- `attach_disasm`
|
|
39
|
+
- `attach_http_transcript`
|
|
40
|
+
- `authors`
|
|
41
|
+
- `help`
|
|
42
|
+
|
|
43
|
+
## Source
|
|
44
|
+
|
|
45
|
+
`pwn/ai/context.rb`
|
|
46
|
+
|
|
47
|
+
## Verification
|
|
48
|
+
|
|
49
|
+
`PWN::AI::Context.respond_to?(:attach_file)` after the
|
|
50
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -37,11 +37,18 @@ PWN::AI::HttpRetry.timeout_s(opts)
|
|
|
37
37
|
- `max_attempts`
|
|
38
38
|
- `retryable`
|
|
39
39
|
- `retry_after_s`
|
|
40
|
+
- `quota_exhausted`
|
|
41
|
+
- `quota_message`
|
|
40
42
|
- `report_event`
|
|
41
43
|
- `authors`
|
|
42
44
|
- `help`
|
|
45
|
+
- `quota_exhausted?`
|
|
43
46
|
- `retryable?`
|
|
44
47
|
|
|
48
|
+
## References
|
|
49
|
+
|
|
50
|
+
- `references/urls.md` — URLs from source
|
|
51
|
+
|
|
45
52
|
## Source
|
|
46
53
|
|
|
47
54
|
`pwn/ai/http_retry.rb`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-plugins-gdbmi
|
|
3
|
+
description: Drive PWN::Plugins::GDBMI from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::Plugins::GDBMI
|
|
10
|
+
source: pwn/plugins/gdbmi.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::Plugins::GDBMI
|
|
14
|
+
|
|
15
|
+
GDB machine-interface bridge: breakpoints, stepping, registers, memory, backtraces, checksec. Pairs with ProcessTube for interactive sessions.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::Plugins::GDBMI` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/plugins/gdbmi.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::Plugins::GDBMI.help
|
|
31
|
+
PWN::Plugins::GDBMI.required_bins(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- `required_bins`
|
|
37
|
+
- `open`
|
|
38
|
+
- `break`
|
|
39
|
+
- `step`
|
|
40
|
+
- `registers`
|
|
41
|
+
- `read_memory`
|
|
42
|
+
- `backtrace`
|
|
43
|
+
- `checksec`
|
|
44
|
+
- `mi`
|
|
45
|
+
- `authors`
|
|
46
|
+
- `help`
|
|
47
|
+
|
|
48
|
+
## Source
|
|
49
|
+
|
|
50
|
+
`pwn/plugins/gdbmi.rb`
|
|
51
|
+
|
|
52
|
+
## Verification
|
|
53
|
+
|
|
54
|
+
`PWN::Plugins::GDBMI.respond_to?(:required_bins)` after the
|
|
55
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-plugins-ghidraheadless
|
|
3
|
+
description: Drive PWN::Plugins::GhidraHeadless from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::Plugins::GhidraHeadless
|
|
10
|
+
source: pwn/plugins/ghidra_headless.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::Plugins::GhidraHeadless
|
|
14
|
+
|
|
15
|
+
analyzeHeadless wrapper that exports decompiled C plus the symbol table as JSON, cached by binary SHA-256.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::Plugins::GhidraHeadless` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/plugins/ghidra_headless.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::Plugins::GhidraHeadless.help
|
|
31
|
+
PWN::Plugins::GhidraHeadless.required_bins(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- `required_bins`
|
|
37
|
+
- `analyze`
|
|
38
|
+
- `decompile`
|
|
39
|
+
- `authors`
|
|
40
|
+
- `help`
|
|
41
|
+
|
|
42
|
+
## Source
|
|
43
|
+
|
|
44
|
+
`pwn/plugins/ghidra_headless.rb`
|
|
45
|
+
|
|
46
|
+
## Verification
|
|
47
|
+
|
|
48
|
+
`PWN::Plugins::GhidraHeadless.respond_to?(:required_bins)` after the
|
|
49
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -28,11 +28,12 @@ Class methods take `(opts = {})` and read `opts`.
|
|
|
28
28
|
|
|
29
29
|
```ruby
|
|
30
30
|
PWN::Reports::Engagement.help
|
|
31
|
-
PWN::Reports::Engagement.
|
|
31
|
+
PWN::Reports::Engagement.render(opts)
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Public methods
|
|
35
35
|
|
|
36
|
+
- `render`
|
|
36
37
|
- `generate`
|
|
37
38
|
- `authors`
|
|
38
39
|
- `help`
|
|
@@ -43,5 +44,5 @@ PWN::Reports::Engagement.generate(opts)
|
|
|
43
44
|
|
|
44
45
|
## Verification
|
|
45
46
|
|
|
46
|
-
`PWN::Reports::Engagement.respond_to?(:
|
|
47
|
+
`PWN::Reports::Engagement.respond_to?(:render)` after the
|
|
47
48
|
module is loaded. Read the source for parameter names.
|
|
@@ -104,11 +104,12 @@ module PWN
|
|
|
104
104
|
|
|
105
105
|
prompts = generate_reproducers(mistake: m, count: [per, 2].max)
|
|
106
106
|
runs = dry_run ? [] : prompts.map { |p| self_play(prompt: p, tag: "practice:#{m[:signature]}") }
|
|
107
|
-
solved = runs.select { |r| r[:
|
|
108
|
-
|
|
107
|
+
solved = runs.select { |r| r[:success] == true && !r[:training_score].nil? }
|
|
108
|
+
scored = runs.reject { |r| r[:training_score].nil? }
|
|
109
|
+
mean = scored.empty? ? nil : (scored.sum { |r| r[:training_score].to_f } / scored.length)
|
|
109
110
|
resolved = false
|
|
110
111
|
# 2.4 — auto-resolve only with N≥2 holdout successes + store trace
|
|
111
|
-
# P23 — auto-resolve only with N≥2
|
|
112
|
+
# P23 — auto-resolve only with N≥2 trusted holdout successes AND a
|
|
112
113
|
# real tool trace (not empty-final luck). Budget fingerprints
|
|
113
114
|
# additionally require mean holdout ≥0.7 and short-horizon tags.
|
|
114
115
|
if solved.length >= 2 && defined?(Mistakes)
|
|
@@ -130,7 +131,7 @@ module PWN
|
|
|
130
131
|
bump_cooldown!(cooldown: cool, signature: m[:signature], mean: mean) unless dry_run
|
|
131
132
|
results << {
|
|
132
133
|
signature: m[:signature], tool: m[:tool], prompts: prompts,
|
|
133
|
-
runs: runs
|
|
134
|
+
runs: runs,
|
|
134
135
|
resolved: false, mean_score: mean.round(3),
|
|
135
136
|
reason: 'holdouts_ok_but_trace_weak'
|
|
136
137
|
}
|
|
@@ -177,14 +178,14 @@ module PWN
|
|
|
177
178
|
end
|
|
178
179
|
resolved = true
|
|
179
180
|
cool.delete(m[:signature].to_s)
|
|
180
|
-
elsif !dry_run
|
|
181
|
+
elsif !dry_run && !mean.nil?
|
|
181
182
|
# P1 — track zero-progress nights; park after COOLDOWN_FAIL_NIGHTS
|
|
182
183
|
bump_cooldown!(cooldown: cool, signature: m[:signature], mean: mean)
|
|
183
184
|
end
|
|
184
185
|
results << {
|
|
185
186
|
signature: m[:signature], tool: m[:tool], prompts: prompts,
|
|
186
|
-
runs: runs
|
|
187
|
-
resolved: resolved, mean_score: mean
|
|
187
|
+
runs: runs,
|
|
188
|
+
resolved: resolved, mean_score: mean&.round(3)
|
|
188
189
|
}
|
|
189
190
|
end
|
|
190
191
|
end
|
|
@@ -264,7 +265,7 @@ module PWN
|
|
|
264
265
|
|
|
265
266
|
if commit && defined?(Learning)
|
|
266
267
|
prior = Learning.outcomes(limit: 500).find do |o|
|
|
267
|
-
o[:session_id].to_s == sid.to_s && o[:
|
|
268
|
+
o[:session_id].to_s == sid.to_s && !o[:training_score].nil? && Array(o[:tags]).include?('offline_judge')
|
|
268
269
|
end
|
|
269
270
|
next if prior
|
|
270
271
|
end
|
|
@@ -278,38 +279,31 @@ module PWN
|
|
|
278
279
|
next if req.strip.empty? || fin.strip.empty?
|
|
279
280
|
|
|
280
281
|
v = Reward.judge(request: req, final: fin, session_id: sid, commit: commit)
|
|
281
|
-
|
|
282
|
+
known = !v[:training_score].nil?
|
|
283
|
+
Reward.prm(request: req, session_id: sid) if do_prm && commit && known
|
|
282
284
|
# P7/W3 — offline path must also fill calibration so the controller
|
|
283
285
|
# (force plan_first/critic at n≥8) actually becomes reachable under
|
|
284
286
|
# :failure_only local introspect. Pull p(success)= out of any PLAN.
|
|
285
|
-
if commit
|
|
287
|
+
if commit && known
|
|
286
288
|
plan = t.find { |e| e[:role].to_s == 'assistant' && e[:content].to_s.start_with?('PLAN:') }
|
|
287
289
|
pred = plan && plan[:content].to_s[/p\(success\)\s*=\s*([01](?:\.\d+)?)/i, 1]
|
|
288
290
|
if pred
|
|
289
291
|
eng = (PWN::Env.dig(:ai, :active) if defined?(PWN::Env))
|
|
290
|
-
calibrate(predicted: pred.to_f, actual: v[:
|
|
292
|
+
calibrate(predicted: pred.to_f, actual: v[:success] ? 1.0 : 0.0, engine: eng)
|
|
291
293
|
end
|
|
292
294
|
end
|
|
293
295
|
if commit && defined?(Learning)
|
|
294
|
-
|
|
295
|
-
sc = v[:score].to_f
|
|
296
|
-
verd = if defined?(Learning) && Learning.respond_to?(:verdict_for_score, true)
|
|
297
|
-
Learning.send(:verdict_for_score, score: sc).to_s
|
|
298
|
-
elsif sc >= 0.6 then 'solved'
|
|
299
|
-
elsif sc >= 0.3 then 'partial'
|
|
300
|
-
else 'wrong'
|
|
301
|
-
end
|
|
296
|
+
verd = v[:verdict].to_s
|
|
302
297
|
Learning.note_outcome(
|
|
303
298
|
task: req[0, 120],
|
|
304
|
-
|
|
305
|
-
score:
|
|
306
|
-
details: "offline_judge #{verd}(#{sc.round(2)}) #{v[:rationale]}",
|
|
299
|
+
outcome: v,
|
|
300
|
+
details: "offline_judge #{verd}(#{v[:score]}) #{v[:rationale]}",
|
|
307
301
|
session_id: sid,
|
|
308
302
|
tags: ['offline_judge', 'auto', verd],
|
|
309
303
|
judge_source: v[:source]
|
|
310
304
|
)
|
|
311
305
|
end
|
|
312
|
-
scored <<
|
|
306
|
+
scored << v.merge(session_id: sid)
|
|
313
307
|
end
|
|
314
308
|
|
|
315
309
|
mean = scored.empty? ? nil : (scored.sum { |r| r[:score].to_f } / scored.length).round(3)
|
|
@@ -1059,9 +1053,11 @@ module PWN
|
|
|
1059
1053
|
rescue StandardError
|
|
1060
1054
|
nil
|
|
1061
1055
|
end
|
|
1062
|
-
|
|
1056
|
+
v.merge(session_id: sid, prompt: opts[:prompt], final: final, trace: trace)
|
|
1063
1057
|
rescue StandardError => e
|
|
1064
|
-
{
|
|
1058
|
+
Reward.resolve_outcome(outcome: { source: :error, error: e.message }).merge(
|
|
1059
|
+
session_id: sid, prompt: opts[:prompt], final: final, trace: trace
|
|
1060
|
+
)
|
|
1065
1061
|
end
|
|
1066
1062
|
|
|
1067
1063
|
private_class_method def self.score_branch(opts = {})
|
|
@@ -1204,7 +1200,8 @@ module PWN
|
|
|
1204
1200
|
smoke_ok = cand_smoke[:resolved].to_i >= base_smoke[:resolved].to_i &&
|
|
1205
1201
|
cand_smoke[:mean_score].to_f + 0.05 >= base_smoke[:mean_score].to_f
|
|
1206
1202
|
|
|
1207
|
-
|
|
1203
|
+
outcomes_known = [baseline, candid, base_smoke, cand_smoke].all? { |r| r[:unknown]&.zero? }
|
|
1204
|
+
promote = outcomes_known && resolved_win && mean_win && smoke_ok
|
|
1208
1205
|
{
|
|
1209
1206
|
baseline: opts[:baseline],
|
|
1210
1207
|
candidate: opts[:candidate],
|
|
@@ -1223,6 +1220,7 @@ module PWN
|
|
|
1223
1220
|
resolved_win: resolved_win,
|
|
1224
1221
|
mean_win: mean_win,
|
|
1225
1222
|
smoke_ok: smoke_ok,
|
|
1223
|
+
outcomes_known: outcomes_known,
|
|
1226
1224
|
promote: promote,
|
|
1227
1225
|
evalset_size: evalset.length,
|
|
1228
1226
|
gate_version: 2
|
|
@@ -1270,34 +1268,28 @@ module PWN
|
|
|
1270
1268
|
|
|
1271
1269
|
private_class_method def self.replay_on_detailed(opts = {})
|
|
1272
1270
|
tag = opts[:tag].to_s
|
|
1273
|
-
return { resolved: 0, mean_score: 0.0, scores: [] } if tag.empty?
|
|
1271
|
+
return { resolved: 0, mean_score: 0.0, scores: [], outcomes: [], unknown: Array(opts[:evalset]).length } if tag.empty?
|
|
1274
1272
|
|
|
1275
|
-
|
|
1273
|
+
outcomes = []
|
|
1276
1274
|
with_ollama_model(tag: tag) do
|
|
1277
1275
|
Array(opts[:evalset]).each do |e|
|
|
1278
|
-
|
|
1279
|
-
scores << r[:score].to_f
|
|
1276
|
+
outcomes << self_play(prompt: e[:prompt], tag: "gate:#{tag}")
|
|
1280
1277
|
end
|
|
1281
1278
|
end
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1279
|
+
known = outcomes.reject { |r| r[:training_score].nil? }
|
|
1280
|
+
resolved = known.count { |r| r[:success] == true }
|
|
1281
|
+
mean = known.empty? ? 0.0 : (known.sum { |r| r[:training_score] } / known.length)
|
|
1282
|
+
{
|
|
1283
|
+
resolved: resolved, mean_score: mean.round(3),
|
|
1284
|
+
scores: outcomes.map { |r| r[:score] }, outcomes: outcomes,
|
|
1285
|
+
unknown: outcomes.length - known.length
|
|
1286
|
+
}
|
|
1285
1287
|
rescue StandardError
|
|
1286
|
-
{ resolved: 0, mean_score: 0.0, scores: [] }
|
|
1288
|
+
{ resolved: 0, mean_score: 0.0, scores: [], outcomes: outcomes || [], unknown: Array(opts[:evalset]).length }
|
|
1287
1289
|
end
|
|
1288
1290
|
|
|
1289
1291
|
private_class_method def self.replay_on(opts = {})
|
|
1290
|
-
tag
|
|
1291
|
-
return 0 if tag.empty?
|
|
1292
|
-
|
|
1293
|
-
with_ollama_model(tag: tag) do
|
|
1294
|
-
opts[:evalset].count do |e|
|
|
1295
|
-
r = self_play(prompt: e[:prompt], tag: "gate:#{tag}")
|
|
1296
|
-
r[:score].to_f >= 0.7
|
|
1297
|
-
end
|
|
1298
|
-
end
|
|
1299
|
-
rescue StandardError
|
|
1300
|
-
0
|
|
1292
|
+
replay_on_detailed(tag: opts[:tag], evalset: opts[:evalset])[:resolved]
|
|
1301
1293
|
end
|
|
1302
1294
|
|
|
1303
1295
|
private_class_method def self.with_ollama_model(opts = {})
|