Class: Collavre::Orchestration::PolicyResolver

Inherits:
Object
  • Object
show all
Defined in:
app/services/collavre/orchestration/policy_resolver.rb

Overview

PolicyResolver finds and merges applicable policies for a given context.

Policy precedence (later overrides earlier):

  1. Global policies

  2. Creative-level policies

  3. Topic-level policies

  4. Agent-level policies (for scheduling)

Usage:

resolver = PolicyResolver.new(context)
resolver.arbitration_config
# => { "strategy" => "primary_first", "max_responders" => 1 }

Constant Summary collapse

DEFAULTS =

Default configurations when no policy is set

{
  "arbitration" => {
    "strategy" => "all",
    "max_responders" => nil # nil means unlimited
  },
  "scheduling" => {
    "max_concurrent_jobs" => 5,
    "daily_token_limit" => 100_000,
    "rate_limit_per_minute" => 20,
    "backoff_strategy" => "exponential",
    "topic_max_concurrent_jobs" => 1,
    # Loop breaker settings
    "loop_breaker_enabled" => true,
    "ping_pong_threshold" => 5,           # Max back-and-forth between same agents
    "creative_retry_threshold" => 10,     # Max tasks on same creative in time window
    "creative_retry_window_minutes" => 30,
    "task_timeout_minutes" => 60,         # Max time for a single task
    "token_spike_threshold" => 50_000,    # Token usage spike in window
    "token_spike_window_minutes" => 10
  },
  "stuck_detection" => {
    "enabled" => false,
    "task_stuck_threshold_minutes" => 30,       # Task running for > N minutes
    "creative_stall_threshold_minutes" => 120,  # Creative no progress for > N minutes
    "create_system_comment" => true             # Create system comment on escalation
  },
  "collaboration" => {
    "a2a_focus_instruction" => nil,         # nil = locale default
    "a2a_completion_instruction" => nil,
    "a2a_followup_instruction" => nil,
    "mention_rule" => nil,
    "confidence_rule" => nil,
    "escalation_rule" => nil,
    "review_rule" => nil
  }
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(context) ⇒ PolicyResolver

Returns a new instance of PolicyResolver.



57
58
59
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 57

def initialize(context)
  @context = context
end

Instance Method Details

#arbitration_configObject

Get merged arbitration config



62
63
64
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 62

def arbitration_config
  @arbitration_config ||= merge_policies("arbitration")
end

#arbitration_strategyObject

Convenience methods



90
91
92
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 90

def arbitration_strategy
  arbitration_config["strategy"]
end

#bid_fallback_enabled?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 107

def bid_fallback_enabled?
  arbitration_config["bid_fallback_enabled"] != false
end

#collaboration_configObject

Collaboration config



129
130
131
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 129

def collaboration_config
  @collaboration_config ||= merge_policies("collaboration")
end

#confidence_thresholdObject

Bid strategy specific



103
104
105
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 103

def confidence_threshold
  arbitration_config["confidence_threshold"]
end

#loop_breaker_configObject



116
117
118
119
120
121
122
123
124
125
126
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 116

def loop_breaker_config
  {
    "enabled" => scheduling_config["loop_breaker_enabled"],
    "ping_pong_threshold" => scheduling_config["ping_pong_threshold"],
    "creative_retry_threshold" => scheduling_config["creative_retry_threshold"],
    "creative_retry_window_minutes" => scheduling_config["creative_retry_window_minutes"],
    "task_timeout_minutes" => scheduling_config["task_timeout_minutes"],
    "token_spike_threshold" => scheduling_config["token_spike_threshold"],
    "token_spike_window_minutes" => scheduling_config["token_spike_window_minutes"]
  }
end

#loop_breaker_enabled?Boolean

Loop breaker settings

Returns:

  • (Boolean)


112
113
114
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 112

def loop_breaker_enabled?
  scheduling_config["loop_breaker_enabled"] == true
end

#max_respondersObject



94
95
96
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 94

def max_responders
  arbitration_config["max_responders"]
end

#primary_agent_idObject



98
99
100
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 98

def primary_agent_id
  arbitration_config["primary_agent_id"]
end

#resolve(policy_type) ⇒ Object

Generic resolve method for any policy type



143
144
145
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 143

def resolve(policy_type)
  merge_policies(policy_type)
end

#scheduling_configObject

Get merged scheduling config (without agent-specific overrides)



80
81
82
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 80

def scheduling_config
  @scheduling_config ||= merge_policies("scheduling")
end

#scheduling_config_for(agent) ⇒ Object

Get merged scheduling config for a specific agent



67
68
69
70
71
72
73
74
75
76
77
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 67

def scheduling_config_for(agent)
  base = merge_policies("scheduling")

  # Layer agent-specific policies on top
  agent_policies = OrchestratorPolicy.for_agent(agent.id, policy_type: "scheduling")
  agent_policies.each do |policy|
    base = base.merge(policy.config)
  end

  base
end

#stuck_detection_configObject



138
139
140
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 138

def stuck_detection_config
  @stuck_detection_config ||= resolve("stuck_detection")
end

#stuck_detection_enabled?Boolean

Stuck detection settings

Returns:

  • (Boolean)


134
135
136
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 134

def stuck_detection_enabled?
  stuck_detection_config["enabled"] == true
end

#topic_max_concurrent_jobsObject

Topic-level concurrency limit



85
86
87
# File 'app/services/collavre/orchestration/policy_resolver.rb', line 85

def topic_max_concurrent_jobs
  scheduling_config["topic_max_concurrent_jobs"]
end