Module: PWN::AI::Agent::Reflect

Defined in:
lib/pwn/ai/agent/reflect.rb

Overview

PWN::AI::Agent::Reflect is the inward-facing counterpart to PWN::AI::Agent::Extrospection. Where Extrospection looks OUTWARD at the world the agent operates in (host state, toolchain, network, threat-intel), Reflect looks INWARD - it lets pwn hand a request to the active AI engine and reflect on its own artifacts, transcripts, findings, code, or decisions.

This module is gated by PWN::Env[:ai][:module_reflection] so that potentially-sensitive local data is never shipped to a remote LLM unless the operator has explicitly opted in via pwn-vault / config.

It is the single choke-point every PWN::AI::Agent::* domain agent (Assembly, BurpSuite, GQRX, HackerOne, SAST, VulnGen, ...) routes through when it wants an LLM opinion on locally-produced data, and it is also what PWN::AI::Agent::Learning.reflect uses to distill session transcripts into durable PWN::Memory lessons.

TEACHER-STUDENT REFLECTION

When PWN::Env[:reflect_engine] (or opts) names a different provider than :active, Reflect.on temporarily flips :active for the duration of the introspection call. This lets a local Ollama model EXECUTE the task while a frontier model WRITES the durable lessons about it — the local model then reads back distilled reasoning it could never have produced itself.

IMPLEMENTATION NOTE

Reflect.on MUST call the engine's text .chat API directly — never Loop.run. Nesting Loop.run re-enters TaskSummarizer/PromptBuilder/ auto_introspect and produces SystemStackError at the Pry after_read boundary whenever module_reflection is enabled. A thread-local depth counter still gates re-entrant Reflect.on (e.g. chat_for_plan inside an outer agent turn that also judges/reflects).

Constant Summary collapse

ENGINE_MODS =
{
  openai: 'PWN::AI::OpenAI',
  grok: 'PWN::AI::Grok',
  ollama: 'PWN::AI::Ollama',
  anthropic: 'PWN::AI::Anthropic',
  gemini: 'PWN::AI::Gemini'
}.freeze

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. support@0dayinc.com



157
158
159
160
161
# File 'lib/pwn/ai/agent/reflect.rb', line 157

public_class_method def self.authors
  "AUTHOR(S):
    0day Inc. <support@0dayinc.com>
  "
end

.helpObject

Display Usage for this Module



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/pwn/ai/agent/reflect.rb', line 165

public_class_method def self.help
  puts "USAGE:
    #{self}.on(
      request: 'required - String - What you want the AI to reflect on',
      system_role_content: 'optional - context to set up the model behavior for reflection',
      engine: 'optional - override engine (Symbol) for teacher-student reflection; defaults to PWN::Env[:ai][:reflect_engine]',
      spinner: 'optional - Boolean - Display spinner during operation (default: false)',
      suppress_pii_warning: 'optional - Boolean - Suppress PII Warnings (default: false)'
    )

    Teacher-student config:
      PWN::Env[:ai][:reflect_engine] = :anthropic   # execute on :active, critique on :anthropic

    #{self}.authors
  "
end

.on(opts = {}) ⇒ Object

Supported Method Parameters

response = PWN::AI::Agent::Reflect.on( request: 'required - String - What you want the AI to reflect on', system_role_content: 'optional - context to set up the model behavior for reflection', engine: 'optional - override engine for THIS reflection only (Symbol/String); defaults to PWN::Env[:reflect_engine] || :active', model: 'optional - override model on the reflection engine for THIS call only; defaults to PWN::Env[:reflect_model]', spinner: 'optional - Boolean - Display spinner during operation (default: false)', suppress_pii_warning: 'optional - Boolean - Suppress PII Warnings (default: false)' )



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/pwn/ai/agent/reflect.rb', line 61

public_class_method def self.on(opts = {})
  request = opts[:request]
  raise 'ERROR: request must be provided' if request.nil?

  system_role_content = opts[:system_role_content]

  spinner = opts[:spinner] || false

  suppress_pii_warning = opts[:suppress_pii_warning] || false

  response = nil

  ai_module_reflection = PWN::Env[:ai][:module_reflection]

  # Re-entrancy guard: nested Reflect.on (TaskSummarizer inside a
  # Reflect call, Reward.judge during auto_introspect, etc.) returns
  # nil so the outer caller can fall back. Never Loop.run from here.
  return nil if Thread.current[:pwn_reflect_depth].to_i.positive?

  if ai_module_reflection && request.length.positive?
    override = opts[:engine] || PWN::Env.dig(:ai, :reflect_engine)
    model    = opts[:model]  || PWN::Env.dig(:ai, :reflect_model)
    engine   = (override || PWN::Env[:ai][:active]).to_s.downcase.to_sym
    valid_ai_engines = ENGINE_MODS.keys
    raise "ERROR: Unsupported AI engine. Supported engines are: #{valid_ai_engines}" unless valid_ai_engines.include?(engine)

    warn "AI Reflection is enabled.  Ensure #{engine} has been authorized for use and/or requests are sanitized properly." unless suppress_pii_warning
    Thread.current[:pwn_reflect_depth] = Thread.current[:pwn_reflect_depth].to_i + 1
    begin
      response = with_engine(engine: override, model: model) do
        engine_chat(
          engine: engine,
          request: request.chomp,
          system_role_content: system_role_content,
          spinner: spinner
        )
      end
    ensure
      d = Thread.current[:pwn_reflect_depth].to_i - 1
      if d.positive?
        Thread.current[:pwn_reflect_depth] = d
      else
        Thread.current[:pwn_reflect_depth] = nil
      end
    end
  end

  response
rescue StandardError => e
  raise e
end