rb125 commited on
Commit
f0fd6e7
·
1 Parent(s): 748a25e

tier distributed task marketplace

Browse files
Files changed (2) hide show
  1. cgae_engine/contracts.py +315 -0
  2. cgae_engine/marketplace.py +225 -0
cgae_engine/contracts.py ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ CGAE Contract System (Section 3.2.2 of cgae.tex)
3
+
4
+ Implements:
5
+ - CGAE Contracts: C = (O, Phi, V, T_min, r, p)
6
+ - Contract lifecycle: creation, acceptance, execution, verification, settlement
7
+ - Budget ceiling enforcement per tier
8
+ - Escrow mechanism for rewards and penalties
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import uuid
14
+ from dataclasses import dataclass, field
15
+ from enum import Enum
16
+ from typing import Any, Callable, Optional
17
+
18
+ from cgae_engine.gate import Tier, DEFAULT_BUDGET_CEILINGS
19
+
20
+
21
+ class ContractStatus(Enum):
22
+ OPEN = "open" # Available for bidding
23
+ ASSIGNED = "assigned" # Accepted by an agent
24
+ EXECUTING = "executing" # Agent is working on it
25
+ VERIFYING = "verifying" # Output submitted, verification pending
26
+ COMPLETED = "completed" # Verified and settled
27
+ FAILED = "failed" # Constraint violation or timeout
28
+ CANCELLED = "cancelled" # Cancelled by issuer
29
+ EXPIRED = "expired" # No agent accepted in time
30
+
31
+
32
+ @dataclass
33
+ class Constraint:
34
+ """A machine-verifiable constraint (element of Phi)."""
35
+ name: str
36
+ description: str
37
+ verify: Callable[[Any], bool] # V: Output -> {0, 1}
38
+
39
+ def check(self, output: Any) -> bool:
40
+ return self.verify(output)
41
+
42
+
43
+ @dataclass
44
+ class CGAEContract:
45
+ """
46
+ A valid CGAE contract (Definition 5 in paper).
47
+ C = (O, Phi, V, T_min, r, p)
48
+ """
49
+ contract_id: str
50
+ objective: str # O: task description
51
+ constraints: list[Constraint] # Phi: machine-verifiable constraints
52
+ min_tier: Tier # T_min: minimum required tier
53
+ reward: float # r: reward for successful completion
54
+ penalty: float # p: penalty for constraint violation
55
+ issuer_id: str # Who posted the contract
56
+ deadline: float # Time limit for completion
57
+
58
+ # Mutable state
59
+ status: ContractStatus = ContractStatus.OPEN
60
+ assigned_agent_id: Optional[str] = None
61
+ assigned_time: Optional[float] = None
62
+ output: Any = None
63
+ verification_result: Optional[bool] = None
64
+ settlement_time: Optional[float] = None
65
+
66
+ # Metadata
67
+ domain: str = "general"
68
+ difficulty: float = 0.5 # 0-1 scale, used for simulation
69
+ created_time: float = 0.0
70
+
71
+ def verify_output(self, output: Any) -> tuple[bool, list[str]]:
72
+ """
73
+ Run all constraints against the output.
74
+ Returns (passed, list_of_failed_constraint_names).
75
+ """
76
+ failures = []
77
+ for constraint in self.constraints:
78
+ if not constraint.check(output):
79
+ failures.append(constraint.name)
80
+ return len(failures) == 0, failures
81
+
82
+ def to_dict(self) -> dict:
83
+ return {
84
+ "contract_id": self.contract_id,
85
+ "objective": self.objective,
86
+ "min_tier": self.min_tier.name,
87
+ "reward": self.reward,
88
+ "penalty": self.penalty,
89
+ "status": self.status.value,
90
+ "domain": self.domain,
91
+ "difficulty": self.difficulty,
92
+ "assigned_agent_id": self.assigned_agent_id,
93
+ "issuer_id": self.issuer_id,
94
+ "deadline": self.deadline,
95
+ }
96
+
97
+
98
+ class ContractManager:
99
+ """
100
+ Manages the lifecycle of CGAE contracts.
101
+ Enforces budget ceilings, handles escrow, and tracks economic flow.
102
+ """
103
+
104
+ def __init__(self, budget_ceilings: Optional[dict[Tier, float]] = None):
105
+ self.budget_ceilings = budget_ceilings or DEFAULT_BUDGET_CEILINGS
106
+ self._contracts: dict[str, CGAEContract] = {}
107
+ self._agent_active_exposure: dict[str, float] = {} # agent_id -> sum of penalties
108
+ self._escrow: dict[str, float] = {} # contract_id -> escrowed amount
109
+ self._events: list[dict] = []
110
+ self._total_rewards_paid: float = 0.0
111
+ self._total_penalties_collected: float = 0.0
112
+
113
+ @property
114
+ def contracts(self) -> dict[str, CGAEContract]:
115
+ return dict(self._contracts)
116
+
117
+ @property
118
+ def open_contracts(self) -> list[CGAEContract]:
119
+ return [c for c in self._contracts.values() if c.status == ContractStatus.OPEN]
120
+
121
+ def create_contract(
122
+ self,
123
+ objective: str,
124
+ constraints: list[Constraint],
125
+ min_tier: Tier,
126
+ reward: float,
127
+ penalty: float,
128
+ issuer_id: str,
129
+ deadline: float,
130
+ domain: str = "general",
131
+ difficulty: float = 0.5,
132
+ timestamp: float = 0.0,
133
+ ) -> CGAEContract:
134
+ """Create a new contract and add it to the marketplace."""
135
+ contract_id = f"contract_{uuid.uuid4().hex[:12]}"
136
+ contract = CGAEContract(
137
+ contract_id=contract_id,
138
+ objective=objective,
139
+ constraints=constraints,
140
+ min_tier=min_tier,
141
+ reward=reward,
142
+ penalty=penalty,
143
+ issuer_id=issuer_id,
144
+ deadline=deadline,
145
+ domain=domain,
146
+ difficulty=difficulty,
147
+ created_time=timestamp,
148
+ )
149
+ self._contracts[contract_id] = contract
150
+ # Escrow the reward
151
+ self._escrow[contract_id] = reward
152
+ self._log_event("contract_created", timestamp, {
153
+ "contract_id": contract_id, "min_tier": min_tier.name,
154
+ "reward": reward, "penalty": penalty, "domain": domain,
155
+ })
156
+ return contract
157
+
158
+ def assign_contract(
159
+ self,
160
+ contract_id: str,
161
+ agent_id: str,
162
+ agent_tier: Tier,
163
+ timestamp: float = 0.0,
164
+ ) -> bool:
165
+ """
166
+ Assign a contract to an agent. Enforces:
167
+ 1. Agent tier >= contract min_tier
168
+ 2. Agent's total exposure + this penalty <= budget ceiling
169
+ """
170
+ contract = self._get_contract(contract_id)
171
+ if contract.status != ContractStatus.OPEN:
172
+ return False
173
+
174
+ # Tier check
175
+ if agent_tier < contract.min_tier:
176
+ return False
177
+
178
+ # Budget ceiling check (Theorem 1: Bounded Economic Exposure)
179
+ current_exposure = self._agent_active_exposure.get(agent_id, 0.0)
180
+ ceiling = self.budget_ceilings[agent_tier]
181
+ if current_exposure + contract.penalty > ceiling:
182
+ return False
183
+
184
+ # Assign
185
+ contract.status = ContractStatus.ASSIGNED
186
+ contract.assigned_agent_id = agent_id
187
+ contract.assigned_time = timestamp
188
+ self._agent_active_exposure[agent_id] = current_exposure + contract.penalty
189
+
190
+ self._log_event("contract_assigned", timestamp, {
191
+ "contract_id": contract_id, "agent_id": agent_id,
192
+ "exposure_after": self._agent_active_exposure[agent_id],
193
+ "ceiling": ceiling,
194
+ })
195
+ return True
196
+
197
+ def submit_output(
198
+ self,
199
+ contract_id: str,
200
+ output: Any,
201
+ timestamp: float = 0.0,
202
+ ) -> tuple[bool, list[str]]:
203
+ """
204
+ Submit output for a contract. Runs verification against constraints.
205
+ Returns (passed, failed_constraints).
206
+ """
207
+ contract = self._get_contract(contract_id)
208
+ if contract.status not in (ContractStatus.ASSIGNED, ContractStatus.EXECUTING):
209
+ raise ValueError(f"Contract {contract_id} is not in assignable state: {contract.status}")
210
+
211
+ contract.output = output
212
+ contract.status = ContractStatus.VERIFYING
213
+ passed, failures = contract.verify_output(output)
214
+ contract.verification_result = passed
215
+
216
+ return passed, failures
217
+
218
+ def settle_contract(
219
+ self,
220
+ contract_id: str,
221
+ timestamp: float = 0.0,
222
+ ) -> dict:
223
+ """
224
+ Settle a verified contract. Distributes reward or penalty.
225
+ Returns settlement details.
226
+ """
227
+ contract = self._get_contract(contract_id)
228
+ if contract.status != ContractStatus.VERIFYING:
229
+ raise ValueError(f"Contract {contract_id} not in verifying state")
230
+
231
+ agent_id = contract.assigned_agent_id
232
+ settlement = {"contract_id": contract_id, "agent_id": agent_id}
233
+
234
+ if contract.verification_result:
235
+ # Success: release escrow to agent
236
+ contract.status = ContractStatus.COMPLETED
237
+ settlement["outcome"] = "success"
238
+ settlement["reward"] = contract.reward
239
+ settlement["penalty"] = 0.0
240
+ self._total_rewards_paid += contract.reward
241
+ else:
242
+ # Failure: agent pays penalty
243
+ contract.status = ContractStatus.FAILED
244
+ settlement["outcome"] = "failure"
245
+ settlement["reward"] = 0.0
246
+ settlement["penalty"] = contract.penalty
247
+ self._total_penalties_collected += contract.penalty
248
+
249
+ # Release exposure
250
+ current_exposure = self._agent_active_exposure.get(agent_id, 0.0)
251
+ self._agent_active_exposure[agent_id] = max(0, current_exposure - contract.penalty)
252
+
253
+ # Clean up escrow
254
+ self._escrow.pop(contract_id, None)
255
+ contract.settlement_time = timestamp
256
+
257
+ self._log_event("contract_settled", timestamp, settlement)
258
+ return settlement
259
+
260
+ def expire_contracts(self, current_time: float) -> list[str]:
261
+ """Expire contracts past their deadline."""
262
+ expired = []
263
+ for contract in self._contracts.values():
264
+ if contract.status == ContractStatus.OPEN and current_time > contract.deadline:
265
+ contract.status = ContractStatus.EXPIRED
266
+ self._escrow.pop(contract.contract_id, None)
267
+ expired.append(contract.contract_id)
268
+ elif contract.status in (ContractStatus.ASSIGNED, ContractStatus.EXECUTING):
269
+ if current_time > contract.deadline:
270
+ contract.status = ContractStatus.FAILED
271
+ contract.verification_result = False
272
+ agent_id = contract.assigned_agent_id
273
+ if agent_id:
274
+ exposure = self._agent_active_exposure.get(agent_id, 0.0)
275
+ self._agent_active_exposure[agent_id] = max(
276
+ 0, exposure - contract.penalty
277
+ )
278
+ self._total_penalties_collected += contract.penalty
279
+ self._escrow.pop(contract.contract_id, None)
280
+ expired.append(contract.contract_id)
281
+ return expired
282
+
283
+ def agent_exposure(self, agent_id: str) -> float:
284
+ """Current economic exposure for an agent (Theorem 1)."""
285
+ return self._agent_active_exposure.get(agent_id, 0.0)
286
+
287
+ def get_contracts_for_tier(self, tier: Tier) -> list[CGAEContract]:
288
+ """Get open contracts accessible to an agent at the given tier."""
289
+ return [
290
+ c for c in self._contracts.values()
291
+ if c.status == ContractStatus.OPEN and c.min_tier <= tier
292
+ ]
293
+
294
+ def economics_summary(self) -> dict:
295
+ status_counts = {}
296
+ for c in self._contracts.values():
297
+ status_counts[c.status.value] = status_counts.get(c.status.value, 0) + 1
298
+ return {
299
+ "total_contracts": len(self._contracts),
300
+ "status_distribution": status_counts,
301
+ "total_rewards_paid": self._total_rewards_paid,
302
+ "total_penalties_collected": self._total_penalties_collected,
303
+ "total_escrowed": sum(self._escrow.values()),
304
+ "active_exposures": dict(self._agent_active_exposure),
305
+ }
306
+
307
+ def _get_contract(self, contract_id: str) -> CGAEContract:
308
+ if contract_id not in self._contracts:
309
+ raise KeyError(f"Contract {contract_id} not found")
310
+ return self._contracts[contract_id]
311
+
312
+ def _log_event(self, event_type: str, timestamp: float, data: dict):
313
+ self._events.append({
314
+ "type": event_type, "timestamp": timestamp, "data": data,
315
+ })
cgae_engine/marketplace.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Task Marketplace - Generates and manages contracts for the CGAE economy.
3
+
4
+ Creates tier-distributed task demand (Assumption 2a) with tier premiums
5
+ (Assumption 2b), implementing the market structure required for
6
+ Theorem 2 (incentive-compatible robustness investment).
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import random
12
+ from dataclasses import dataclass, field
13
+ from typing import Optional
14
+
15
+ from cgae_engine.gate import Tier
16
+ from cgae_engine.contracts import CGAEContract, Constraint, ContractManager
17
+
18
+
19
+ @dataclass
20
+ class TaskTemplate:
21
+ """Template for generating contracts in a specific domain."""
22
+ domain: str
23
+ objective_template: str
24
+ min_tier: Tier
25
+ base_reward: float
26
+ base_penalty: float
27
+ difficulty_range: tuple[float, float] # (min, max)
28
+ constraint_names: list[str]
29
+
30
+
31
+ # Predefined task templates across tiers and domains
32
+ TASK_TEMPLATES = [
33
+ # Tier 1: Microtasks
34
+ TaskTemplate(
35
+ domain="data_labeling",
36
+ objective_template="Label {n} data points for {topic}",
37
+ min_tier=Tier.T1,
38
+ base_reward=0.002,
39
+ base_penalty=0.001,
40
+ difficulty_range=(0.1, 0.3),
41
+ constraint_names=["format_compliance", "completeness"],
42
+ ),
43
+ TaskTemplate(
44
+ domain="summarization",
45
+ objective_template="Summarize document about {topic} in {n} words",
46
+ min_tier=Tier.T1,
47
+ base_reward=0.003,
48
+ base_penalty=0.001,
49
+ difficulty_range=(0.1, 0.4),
50
+ constraint_names=["length_constraint", "accuracy"],
51
+ ),
52
+
53
+ # Tier 2: Verified contracts
54
+ TaskTemplate(
55
+ domain="analysis",
56
+ objective_template="Analyze {topic} dataset and produce structured report",
57
+ min_tier=Tier.T2,
58
+ base_reward=0.015,
59
+ base_penalty=0.008,
60
+ difficulty_range=(0.3, 0.5),
61
+ constraint_names=["format_compliance", "accuracy", "completeness"],
62
+ ),
63
+ TaskTemplate(
64
+ domain="translation",
65
+ objective_template="Translate {topic} document with domain terminology",
66
+ min_tier=Tier.T2,
67
+ base_reward=0.012,
68
+ base_penalty=0.006,
69
+ difficulty_range=(0.3, 0.6),
70
+ constraint_names=["accuracy", "terminology_consistency"],
71
+ ),
72
+
73
+ # Tier 3: Autonomous contracting
74
+ TaskTemplate(
75
+ domain="contract_review",
76
+ objective_template="Review and summarize contract terms for {topic}",
77
+ min_tier=Tier.T3,
78
+ base_reward=0.08,
79
+ base_penalty=0.05,
80
+ difficulty_range=(0.5, 0.7),
81
+ constraint_names=["accuracy", "completeness", "legal_compliance", "format_compliance"],
82
+ ),
83
+ TaskTemplate(
84
+ domain="financial_analysis",
85
+ objective_template="Produce financial analysis of {topic} with risk assessment",
86
+ min_tier=Tier.T3,
87
+ base_reward=0.10,
88
+ base_penalty=0.06,
89
+ difficulty_range=(0.5, 0.8),
90
+ constraint_names=["accuracy", "numerical_precision", "risk_disclosure"],
91
+ ),
92
+
93
+ # Tier 4: Delegation tasks
94
+ TaskTemplate(
95
+ domain="multi_step_workflow",
96
+ objective_template="Orchestrate {n}-step workflow for {topic}",
97
+ min_tier=Tier.T4,
98
+ base_reward=0.50,
99
+ base_penalty=0.30,
100
+ difficulty_range=(0.6, 0.85),
101
+ constraint_names=["accuracy", "completeness", "coordination", "deadline_compliance"],
102
+ ),
103
+
104
+ # Tier 5: Self-modification tasks
105
+ TaskTemplate(
106
+ domain="system_optimization",
107
+ objective_template="Optimize {topic} system with self-tuning parameters",
108
+ min_tier=Tier.T5,
109
+ base_reward=2.0,
110
+ base_penalty=1.0,
111
+ difficulty_range=(0.8, 0.95),
112
+ constraint_names=["accuracy", "safety_bounds", "rollback_capability", "audit_trail"],
113
+ ),
114
+ ]
115
+
116
+ TOPICS = [
117
+ "healthcare data", "supply chain", "climate metrics", "user behavior",
118
+ "financial instruments", "legal documents", "scientific papers",
119
+ "social media trends", "energy consumption", "logistics routing",
120
+ ]
121
+
122
+
123
+ def _make_constraint(name: str) -> Constraint:
124
+ """Create a simple constraint for simulation. In production, these would
125
+ be real verification functions."""
126
+ # For simulation: constraint passes based on the output value (True/False)
127
+ return Constraint(
128
+ name=name,
129
+ description=f"Verify {name.replace('_', ' ')}",
130
+ verify=lambda output, _name=name: bool(output),
131
+ )
132
+
133
+
134
+ class TaskMarketplace:
135
+ """
136
+ Generates contracts with tier-distributed demand.
137
+
138
+ Implements the market structure from Assumption 2:
139
+ (a) Positive demand at each tier
140
+ (b) Tier premium: E[r|T_k] < E[r|T_{k+1}]
141
+ (c) Non-increasing supply at higher tiers
142
+ """
143
+
144
+ def __init__(
145
+ self,
146
+ contract_manager: ContractManager,
147
+ demand_distribution: Optional[dict[Tier, float]] = None,
148
+ contracts_per_step: int = 10,
149
+ ):
150
+ self.contract_manager = contract_manager
151
+ self.contracts_per_step = contracts_per_step
152
+
153
+ # Demand weights per tier (higher tiers have less volume but more value)
154
+ self.demand_distribution = demand_distribution or {
155
+ Tier.T1: 0.40, # 40% of contracts are microtasks
156
+ Tier.T2: 0.25, # 25% verified contracts
157
+ Tier.T3: 0.20, # 20% autonomous
158
+ Tier.T4: 0.10, # 10% delegation
159
+ Tier.T5: 0.05, # 5% self-modification
160
+ }
161
+
162
+ # Group templates by tier
163
+ self._templates_by_tier: dict[Tier, list[TaskTemplate]] = {}
164
+ for t in TASK_TEMPLATES:
165
+ self._templates_by_tier.setdefault(t.min_tier, []).append(t)
166
+
167
+ def generate_contracts(
168
+ self,
169
+ current_time: float,
170
+ deadline_offset: float = 50.0,
171
+ ) -> list[CGAEContract]:
172
+ """Generate a batch of contracts for this time step."""
173
+ contracts = []
174
+ for tier, weight in self.demand_distribution.items():
175
+ n = max(1, int(self.contracts_per_step * weight))
176
+ templates = self._templates_by_tier.get(tier, [])
177
+ if not templates:
178
+ continue
179
+
180
+ for _ in range(n):
181
+ template = random.choice(templates)
182
+ topic = random.choice(TOPICS)
183
+ n_items = random.randint(5, 50)
184
+
185
+ # Reward jitter (+/- 20%)
186
+ reward = template.base_reward * random.uniform(0.8, 1.2)
187
+ penalty = template.base_penalty * random.uniform(0.8, 1.2)
188
+ difficulty = random.uniform(*template.difficulty_range)
189
+
190
+ constraints = [_make_constraint(cn) for cn in template.constraint_names]
191
+
192
+ contract = self.contract_manager.create_contract(
193
+ objective=template.objective_template.format(topic=topic, n=n_items),
194
+ constraints=constraints,
195
+ min_tier=template.min_tier,
196
+ reward=reward,
197
+ penalty=penalty,
198
+ issuer_id="marketplace",
199
+ deadline=current_time + deadline_offset,
200
+ domain=template.domain,
201
+ difficulty=difficulty,
202
+ timestamp=current_time,
203
+ )
204
+ contracts.append(contract)
205
+
206
+ return contracts
207
+
208
+ def market_summary(self) -> dict:
209
+ """Summarize current market state."""
210
+ open_contracts = self.contract_manager.open_contracts
211
+ tier_counts = {}
212
+ tier_rewards = {}
213
+ for c in open_contracts:
214
+ tier = c.min_tier.name
215
+ tier_counts[tier] = tier_counts.get(tier, 0) + 1
216
+ tier_rewards.setdefault(tier, []).append(c.reward)
217
+
218
+ avg_rewards = {
219
+ t: sum(rs) / len(rs) for t, rs in tier_rewards.items()
220
+ }
221
+ return {
222
+ "open_contracts": len(open_contracts),
223
+ "by_tier": tier_counts,
224
+ "avg_reward_by_tier": avg_rewards,
225
+ }