active_harness 0.1.0 → 0.2.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_harness/agent/hooks.rb +75 -0
  3. data/lib/active_harness/agent/models.rb +147 -0
  4. data/lib/active_harness/agent/output_parser.rb +57 -0
  5. data/lib/active_harness/agent/prompt.rb +58 -0
  6. data/lib/active_harness/agent/providers.rb +54 -0
  7. data/lib/active_harness/agent.rb +107 -228
  8. data/lib/active_harness/core/errors.rb +22 -28
  9. data/lib/active_harness/http/client.rb +8 -19
  10. data/lib/active_harness/http/streaming_client.rb +60 -0
  11. data/lib/active_harness/memory/adapter/base.rb +36 -0
  12. data/lib/active_harness/memory/adapter/file.rb +141 -0
  13. data/lib/active_harness/memory.rb +212 -0
  14. data/lib/active_harness/pipeline/step.rb +36 -0
  15. data/lib/active_harness/pipeline.rb +207 -0
  16. data/lib/active_harness/providers/PROVIDER_CONTRACT.md +54 -0
  17. data/lib/active_harness/providers/anthropic.rb +76 -4
  18. data/lib/active_harness/providers/base.rb +41 -13
  19. data/lib/active_harness/providers/gemini.rb +61 -0
  20. data/lib/active_harness/providers/groq.rb +64 -0
  21. data/lib/active_harness/providers/openai.rb +39 -47
  22. data/lib/active_harness/providers/openrouter.rb +40 -54
  23. data/lib/active_harness/railtie.rb +12 -0
  24. data/lib/active_harness/result.rb +10 -0
  25. data/lib/active_harness/tribunal.rb +215 -0
  26. data/lib/active_harness.rb +17 -46
  27. data/lib/generators/active_harness/install/install_generator.rb +54 -0
  28. data/lib/generators/active_harness/install/templates/agents/test_support_agent.rb +10 -0
  29. data/lib/generators/active_harness/install/templates/agents/test_support_guard_agent.rb +11 -0
  30. data/lib/generators/active_harness/install/templates/controllers/ai_controller.rb +105 -0
  31. data/lib/generators/active_harness/install/templates/memory/test_support_memory.rb +16 -0
  32. data/lib/generators/active_harness/install/templates/pipelines/test_support_pipeline.rb +31 -0
  33. data/lib/generators/active_harness/install/templates/prompts/test_support_guard_prompt.rb +9 -0
  34. data/lib/generators/active_harness/install/templates/prompts/test_support_prompt.rb +5 -0
  35. data/lib/generators/active_harness/install/templates/tribunals/test_support_guard_tribunal.rb +11 -0
  36. metadata +32 -72
  37. data/LICENSE +0 -21
  38. data/README.md +0 -113
  39. data/lib/active_harness/core/configuration.rb +0 -55
  40. data/lib/active_harness/core/version.rb +0 -3
  41. data/lib/active_harness/http/retry_policy.rb +0 -47
  42. data/lib/active_harness/models/model_request.rb +0 -14
  43. data/lib/active_harness/models/model_response.rb +0 -13
  44. data/lib/active_harness/payload.rb +0 -47
  45. data/lib/active_harness/pipeline/engine.rb +0 -251
  46. data/lib/active_harness/pipeline/fallback_runner.rb +0 -76
  47. data/lib/active_harness/pipeline/guard_runner.rb +0 -125
  48. data/lib/active_harness/pipeline/output_parser.rb +0 -43
  49. data/lib/active_harness/pipeline/prompt_builder.rb +0 -46
  50. data/lib/active_harness/pipeline/provider_registry.rb +0 -16
  51. data/lib/active_harness/prompts/guard_system_prompt.rb +0 -33
  52. data/lib/active_harness/providers/google.rb +0 -11
  53. data/lib/active_harness/rate_limit/request_limiter.rb +0 -50
  54. data/lib/active_harness/rate_limit/risk_holdback.rb +0 -69
  55. data/lib/active_harness/results/debug_result.rb +0 -19
  56. data/lib/active_harness/results/input_result.rb +0 -27
  57. data/lib/active_harness/results/result.rb +0 -55
@@ -1,69 +0,0 @@
1
- module ActiveHarness
2
- module RateLimit
3
- # Progressive hold-back for users who repeatedly submit risky requests.
4
- #
5
- # Every RISKY_THRESHOLD blocked requests trigger a hold. The hold duration
6
- # escalates with each offense:
7
- #
8
- # Offense 1 (3rd risky request) → 5 minutes
9
- # Offense 2 (6th risky request) → 30 minutes
10
- # Offense 3+ (9th+ risky request) → 2 hours
11
- #
12
- # Storage is in-memory (per-process). Thread-safe via Mutex.
13
- #
14
- # Usage:
15
- # holdback = RiskHoldback.new
16
- # holdback.check!(user_id) # before each request; raises if held
17
- # holdback.record_risky!(user_id) # after guard blocks a request
18
- #
19
- class RiskHoldback
20
- RISKY_THRESHOLD = 3
21
- HOLD_SCHEDULE = [5 * 60, 30 * 60, 2 * 60 * 60].freeze # 5 min / 30 min / 2 h
22
-
23
- # @param risky_threshold [Integer] number of risky requests before a hold is applied
24
- def initialize(risky_threshold: RISKY_THRESHOLD)
25
- @risky_threshold = risky_threshold
26
- @state = {}
27
- @mutex = Mutex.new
28
- end
29
-
30
- # Records a risky (guard-blocked) request for the user.
31
- # Applies a hold when the count reaches the next threshold multiple.
32
- # @param user_id [String, Integer, nil] nil is a no-op
33
- def record_risky!(user_id)
34
- return if user_id.nil?
35
-
36
- key = user_id.to_s
37
- @mutex.synchronize do
38
- s = @state[key] ||= { risky_count: 0, offense_count: 0, held_until: nil }
39
- s[:risky_count] += 1
40
-
41
- if (s[:risky_count] % @risky_threshold).zero?
42
- offense_idx = [s[:offense_count], HOLD_SCHEDULE.size - 1].min
43
- s[:held_until] = Time.now.to_f + HOLD_SCHEDULE[offense_idx]
44
- s[:offense_count] += 1
45
- end
46
- end
47
- end
48
-
49
- # Raises if the user is currently held back due to risky behaviour.
50
- # @param user_id [String, Integer, nil] nil disables the check
51
- # @raise [Errors::UserHoldbackError]
52
- def check!(user_id)
53
- return if user_id.nil?
54
-
55
- key = user_id.to_s
56
- @mutex.synchronize do
57
- s = @state[key]
58
- return unless s&.dig(:held_until)
59
- return if Time.now.to_f >= s[:held_until]
60
-
61
- remaining = (s[:held_until] - Time.now.to_f).ceil
62
- raise Errors::UserHoldbackError,
63
- "Requests paused due to repeated safety violations. " \
64
- "Retry in #{remaining}s (user: #{key})"
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,19 +0,0 @@
1
- module ActiveHarness
2
- # Available only when ActiveHarness.config.debug == true
3
- class DebugResult
4
- attr_reader :system_prompt,
5
- :guard_runs,
6
- :callback_log
7
-
8
- def initialize(system_prompt: nil,
9
- guard_runs: [], callback_log: [])
10
- @system_prompt = system_prompt
11
- @guard_runs = guard_runs
12
- @callback_log = callback_log
13
- end
14
-
15
- def full_prompt
16
- @system_prompt.to_s
17
- end
18
- end
19
- end
@@ -1,27 +0,0 @@
1
- module ActiveHarness
2
- # Holds the result of the guard (input safety) layer.
3
- class InputResult
4
- attr_reader :raw, :processed, :errors, :risk_level, :intent, :reason
5
-
6
- def initialize(raw:, processed:, safe:, valid:,
7
- risk_level: :low, errors: [],
8
- intent: nil, reason: nil)
9
- @raw = raw
10
- @processed = processed
11
- @safe = safe
12
- @valid = valid
13
- @risk_level = risk_level
14
- @errors = errors
15
- @intent = intent
16
- @reason = reason
17
- end
18
-
19
- def safe?
20
- @safe
21
- end
22
-
23
- def valid?
24
- @valid
25
- end
26
- end
27
- end
@@ -1,55 +0,0 @@
1
- module ActiveHarness
2
- class Result
3
- SUCCESS = :success
4
- FAILED = :failed
5
- BLOCKED = :blocked
6
-
7
- attr_reader :input, :output, :raw_response,
8
- :provider, :model, :usage, :attempts,
9
- :debug, :error
10
-
11
- def initialize(status:, input: nil, output: nil, raw_response: nil,
12
- provider: nil, model: nil, usage: {}, attempts: [],
13
- debug: nil, error: nil)
14
- @status = status
15
- @input = input
16
- @output = output
17
- @raw_response = raw_response
18
- @provider = provider
19
- @model = model
20
- @usage = usage
21
- @attempts = attempts
22
- @debug = debug
23
- @error = error
24
- end
25
-
26
- def success?
27
- @status == SUCCESS
28
- end
29
-
30
- def failed?
31
- @status == FAILED
32
- end
33
-
34
- def blocked?
35
- @status == BLOCKED
36
- end
37
-
38
- # Factory helpers
39
-
40
- def self.success(input:, output:, raw_response:, provider:, model:,
41
- usage:, attempts:, debug: nil)
42
- new(status: SUCCESS, input: input, output: output,
43
- raw_response: raw_response, provider: provider,
44
- model: model, usage: usage, attempts: attempts, debug: debug)
45
- end
46
-
47
- def self.blocked(input:, output: nil, debug: nil)
48
- new(status: BLOCKED, input: input, output: output, debug: debug)
49
- end
50
-
51
- def self.failed(error: nil, input: nil, debug: nil)
52
- new(status: FAILED, error: error, input: input, debug: debug)
53
- end
54
- end
55
- end