narcolepticchicken commited on
Commit
3b67aea
·
verified ·
1 Parent(s): a98a7f5

Upload broker/broker.py

Browse files
Files changed (1) hide show
  1. broker/broker.py +197 -0
broker/broker.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Resource Broker: capability-based rights based on credits, task state, and risk.
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+ from typing import Any, Dict, Optional
8
+
9
+
10
+ class Decision(Enum):
11
+ ALLOW = "allow"
12
+ DENY = "deny"
13
+ REQUIRE_APPROVAL = "require_approval"
14
+ DOWNGRADE = "downgrade"
15
+ ESCALATE = "escalate"
16
+ ASK_JUSTIFICATION = "ask_justification"
17
+
18
+
19
+ @dataclass
20
+ class ResourceDecision:
21
+ decision: Decision
22
+ resource: str
23
+ agent_id: str
24
+ reason: str
25
+ allowed_quota: Optional[int] = None
26
+ downgrade_to: Optional[str] = None
27
+ requires_human: bool = False
28
+
29
+
30
+ class ResourceBroker:
31
+ """
32
+ Grants capability-based rights based on:
33
+ - credit balance (per capability_scope)
34
+ - task state (urgency, progress)
35
+ - risk profile (safety class of resource)
36
+ - agent behavior history (gaming flags)
37
+ """
38
+
39
+ # Resource safety classes
40
+ SAFETY_LOW = {"model_call_small", "retrieval_call", "debate_turn", "verifier_call"}
41
+ SAFETY_MEDIUM = {"model_call_large", "memory_write", "shell_execute"}
42
+ SAFETY_HIGH = {"file_write", "human_escalation"}
43
+
44
+ # Default credit thresholds
45
+ DEFAULT_THRESHOLDS = {
46
+ "model_call_small": 1.0,
47
+ "model_call_large": 10.0,
48
+ "retrieval_call": 2.0,
49
+ "verifier_call": 5.0,
50
+ "debate_turn": 1.0,
51
+ "file_write": 15.0,
52
+ "shell_execute": 20.0,
53
+ "memory_write": 8.0,
54
+ "human_escalation": 50.0,
55
+ }
56
+
57
+ def __init__(
58
+ self,
59
+ thresholds: Optional[Dict[str, float]] = None,
60
+ risk_multiplier: float = 1.5,
61
+ ):
62
+ self.thresholds = thresholds or dict(self.DEFAULT_THRESHOLDS)
63
+ self.risk_multiplier = risk_multiplier
64
+ self._agent_flags: Dict[str, Dict[str, Any]] = {}
65
+
66
+ def request(
67
+ self,
68
+ resource: str,
69
+ agent_id: str,
70
+ credit_balance: float,
71
+ task_state: Optional[Dict] = None,
72
+ agent_flags: Optional[Dict] = None,
73
+ ) -> ResourceDecision:
74
+ """
75
+ Decide whether to grant a resource request.
76
+ """
77
+ task_state = task_state or {}
78
+ agent_flags = agent_flags or {}
79
+
80
+ # Store flags for audit
81
+ self._agent_flags.setdefault(agent_id, {}).update(agent_flags)
82
+
83
+ # Determine safety class
84
+ if resource in self.SAFETY_LOW:
85
+ safety = "low"
86
+ elif resource in self.SAFETY_MEDIUM:
87
+ safety = "medium"
88
+ else:
89
+ safety = "high"
90
+
91
+ # Adjust threshold based on safety and task urgency
92
+ threshold = self.thresholds.get(resource, 10.0)
93
+ urgency = task_state.get("urgency", 0.5)
94
+ progress = task_state.get("progress", 0.0)
95
+ gaming_score = agent_flags.get("gaming_score", 0.0)
96
+
97
+ # Risk-adjusted threshold
98
+ if safety == "medium":
99
+ threshold *= self.risk_multiplier
100
+ elif safety == "high":
101
+ threshold *= self.risk_multiplier * 2.0
102
+
103
+ # Urgency can lower threshold slightly
104
+ threshold *= max(0.5, 1.0 - urgency * 0.3)
105
+
106
+ # Progress bonus: as task progresses, lower threshold (momentum)
107
+ threshold *= max(0.7, 1.0 - progress * 0.3)
108
+
109
+ # Gaming flags override
110
+ if gaming_score > 0.5:
111
+ return ResourceDecision(
112
+ decision=Decision.ESCALATE,
113
+ resource=resource,
114
+ agent_id=agent_id,
115
+ reason=f"Gaming detected (score={gaming_score:.2f}). Escalating to human.",
116
+ requires_human=True,
117
+ )
118
+
119
+ if gaming_score > 0.2:
120
+ return ResourceDecision(
121
+ decision=Decision.REQUIRE_APPROVAL,
122
+ resource=resource,
123
+ agent_id=agent_id,
124
+ reason=f"Suspicious activity (score={gaming_score:.2f}). Approval required.",
125
+ requires_human=True,
126
+ )
127
+
128
+ # Main decision logic
129
+ if credit_balance >= threshold:
130
+ if safety == "high":
131
+ return ResourceDecision(
132
+ decision=Decision.REQUIRE_APPROVAL,
133
+ resource=resource,
134
+ agent_id=agent_id,
135
+ reason=f"High-safety resource. Credit sufficient ({credit_balance:.1f} >= {threshold:.1f}) but approval needed.",
136
+ requires_human=True,
137
+ )
138
+ return ResourceDecision(
139
+ decision=Decision.ALLOW,
140
+ resource=resource,
141
+ agent_id=agent_id,
142
+ reason=f"Credit sufficient ({credit_balance:.1f} >= {threshold:.1f}). Safety={safety}.",
143
+ allowed_quota=int(credit_balance / max(1.0, threshold)),
144
+ )
145
+
146
+ # Credit insufficient — consider downgrade for model calls
147
+ if resource == "model_call_large" and credit_balance >= self.thresholds.get("model_call_small", 1.0):
148
+ return ResourceDecision(
149
+ decision=Decision.DOWNGRADE,
150
+ resource=resource,
151
+ agent_id=agent_id,
152
+ reason=f"Insufficient credit for large model ({credit_balance:.1f} < {threshold:.1f}). Downgrading to small.",
153
+ downgrade_to="model_call_small",
154
+ )
155
+
156
+ if resource == "shell_execute" and credit_balance >= self.thresholds.get("file_write", 15.0):
157
+ return ResourceDecision(
158
+ decision=Decision.DOWNGRADE,
159
+ resource=resource,
160
+ agent_id=agent_id,
161
+ reason=f"Insufficient credit for shell. Downgrading to file_write.",
162
+ downgrade_to="file_write",
163
+ )
164
+
165
+ # Low credit but high urgency -> ask for justification
166
+ if urgency > 0.8:
167
+ return ResourceDecision(
168
+ decision=Decision.ASK_JUSTIFICATION,
169
+ resource=resource,
170
+ agent_id=agent_id,
171
+ reason=f"Credit insufficient ({credit_balance:.1f} < {threshold:.1f}) but urgency high. Justification required.",
172
+ )
173
+
174
+ return ResourceDecision(
175
+ decision=Decision.DENY,
176
+ resource=resource,
177
+ agent_id=agent_id,
178
+ reason=f"Credit insufficient ({credit_balance:.1f} < {threshold:.1f}).",
179
+ )
180
+
181
+ def batch_request(
182
+ self,
183
+ resources: list,
184
+ agent_id: str,
185
+ credit_balance: float,
186
+ task_state: Optional[Dict] = None,
187
+ agent_flags: Optional[Dict] = None,
188
+ ) -> list:
189
+ """Evaluate multiple resource requests, returning decisions."""
190
+ return [
191
+ self.request(r, agent_id, credit_balance, task_state, agent_flags)
192
+ for r in resources
193
+ ]
194
+
195
+ def audit_log(self, agent_id: str) -> Dict:
196
+ """Return agent's flagged behavior history."""
197
+ return self._agent_flags.get(agent_id, {})