aragora-client 2.1.10__py3-none-any.whl
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.
- aragora_client/__init__.py +75 -0
- aragora_client/client.py +544 -0
- aragora_client/exceptions.py +67 -0
- aragora_client/py.typed +0 -0
- aragora_client/types.py +323 -0
- aragora_client/websocket.py +262 -0
- aragora_client-2.1.10.dist-info/METADATA +425 -0
- aragora_client-2.1.10.dist-info/RECORD +9 -0
- aragora_client-2.1.10.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aragora-client
|
|
3
|
+
Version: 2.1.10
|
|
4
|
+
Summary: Python SDK for Aragora multi-agent debate framework
|
|
5
|
+
Project-URL: Homepage, https://aragora.ai
|
|
6
|
+
Project-URL: Documentation, https://docs.aragora.ai/sdk/python
|
|
7
|
+
Project-URL: Repository, https://github.com/an0mium/aragora
|
|
8
|
+
Project-URL: Issues, https://github.com/an0mium/aragora/issues
|
|
9
|
+
Author-email: Aragora Team <team@aragora.ai>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: ai,anthropic,aragora,debate,llm,multi-agent,openai,sdk
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Requires-Dist: websockets>=12.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# aragora-client
|
|
34
|
+
|
|
35
|
+
Python SDK for the Aragora multi-agent debate framework.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install aragora-client
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import asyncio
|
|
47
|
+
from aragora_client import AragoraClient
|
|
48
|
+
|
|
49
|
+
async def main():
|
|
50
|
+
client = AragoraClient("http://localhost:8080")
|
|
51
|
+
|
|
52
|
+
# Run a debate
|
|
53
|
+
debate = await client.debates.run(
|
|
54
|
+
task="Should we use microservices?",
|
|
55
|
+
agents=["anthropic-api", "openai-api"],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
print(f"Consensus: {debate.consensus.conclusion}")
|
|
59
|
+
|
|
60
|
+
asyncio.run(main())
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Reference
|
|
64
|
+
|
|
65
|
+
### Client Initialization
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from aragora_client import AragoraClient
|
|
69
|
+
|
|
70
|
+
client = AragoraClient(
|
|
71
|
+
base_url="http://localhost:8080",
|
|
72
|
+
api_key="your-api-key", # optional
|
|
73
|
+
timeout=30.0, # optional, default 30s
|
|
74
|
+
headers={"X-Custom": "value"} # optional
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Use as context manager for automatic cleanup
|
|
78
|
+
async with AragoraClient("http://localhost:8080") as client:
|
|
79
|
+
debate = await client.debates.run(task="...")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Debates API
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# Create a debate
|
|
86
|
+
response = await client.debates.create(
|
|
87
|
+
task="Design a rate limiter",
|
|
88
|
+
agents=["anthropic-api", "openai-api"],
|
|
89
|
+
max_rounds=5,
|
|
90
|
+
consensus_threshold=0.8,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Get debate details
|
|
94
|
+
debate = await client.debates.get("debate-123")
|
|
95
|
+
|
|
96
|
+
# List debates
|
|
97
|
+
debates = await client.debates.list(limit=10, status="completed")
|
|
98
|
+
|
|
99
|
+
# Run debate and wait for completion
|
|
100
|
+
result = await client.debates.run(
|
|
101
|
+
task="Should we use TypeScript?",
|
|
102
|
+
timeout=300.0, # optional timeout
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Graph Debates API
|
|
107
|
+
|
|
108
|
+
Graph debates support automatic branching when agents identify different approaches.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# Create graph debate
|
|
112
|
+
response = await client.graph_debates.create(
|
|
113
|
+
task="Design a distributed system",
|
|
114
|
+
agents=["anthropic-api", "openai-api"],
|
|
115
|
+
max_rounds=5,
|
|
116
|
+
branch_threshold=0.5,
|
|
117
|
+
max_branches=10,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Get debate with branches
|
|
121
|
+
debate = await client.graph_debates.get("debate-123")
|
|
122
|
+
|
|
123
|
+
# Get branches
|
|
124
|
+
branches = await client.graph_debates.get_branches("debate-123")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Matrix Debates API
|
|
128
|
+
|
|
129
|
+
Matrix debates run the same question across different scenarios.
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# Create matrix debate
|
|
133
|
+
response = await client.matrix_debates.create(
|
|
134
|
+
task="Should we adopt microservices?",
|
|
135
|
+
scenarios=[
|
|
136
|
+
{"name": "small_team", "parameters": {"team_size": 5}},
|
|
137
|
+
{"name": "large_team", "parameters": {"team_size": 50}},
|
|
138
|
+
{"name": "high_traffic", "parameters": {"rps": 100000}, "is_baseline": True},
|
|
139
|
+
],
|
|
140
|
+
max_rounds=3,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Get conclusions
|
|
144
|
+
conclusions = await client.matrix_debates.get_conclusions("matrix-123")
|
|
145
|
+
print(f"Universal: {conclusions.universal}")
|
|
146
|
+
print(f"Conditional: {conclusions.conditional}")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Verification API
|
|
150
|
+
|
|
151
|
+
Formal verification of claims using Z3 or Lean 4.
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
# Verify a claim
|
|
155
|
+
result = await client.verification.verify(
|
|
156
|
+
claim="All primes > 2 are odd",
|
|
157
|
+
backend="z3", # "z3" | "lean"
|
|
158
|
+
timeout=30,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if result.status == "valid":
|
|
162
|
+
print("Claim is valid!")
|
|
163
|
+
print(f"Formal translation: {result.formal_translation}")
|
|
164
|
+
|
|
165
|
+
# Check backend status
|
|
166
|
+
status = await client.verification.status()
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Agents API
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# List available agents
|
|
173
|
+
agents = await client.agents.list()
|
|
174
|
+
|
|
175
|
+
# Get agent profile
|
|
176
|
+
agent = await client.agents.get("anthropic-api")
|
|
177
|
+
print(f"ELO rating: {agent.elo_rating}")
|
|
178
|
+
|
|
179
|
+
# Get match history
|
|
180
|
+
history = await client.agents.history("anthropic-api", limit=20)
|
|
181
|
+
|
|
182
|
+
# Get rivals and allies
|
|
183
|
+
rivals = await client.agents.rivals("anthropic-api")
|
|
184
|
+
allies = await client.agents.allies("anthropic-api")
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Gauntlet API
|
|
188
|
+
|
|
189
|
+
Adversarial validation of specifications.
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
# Run gauntlet
|
|
193
|
+
response = await client.gauntlet.run(
|
|
194
|
+
input_content="Your spec content here...",
|
|
195
|
+
input_type="spec",
|
|
196
|
+
persona="security",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Get receipt
|
|
200
|
+
receipt = await client.gauntlet.get_receipt(response["gauntlet_id"])
|
|
201
|
+
print(f"Score: {receipt.score}")
|
|
202
|
+
print(f"Findings: {receipt.findings}")
|
|
203
|
+
|
|
204
|
+
# Run and wait for completion
|
|
205
|
+
result = await client.gauntlet.run_and_wait(
|
|
206
|
+
input_content=spec_content,
|
|
207
|
+
persona="devil_advocate",
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Selection API
|
|
212
|
+
|
|
213
|
+
Agent selection plugins for team building.
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
# List available plugins
|
|
217
|
+
plugins = await client.selection.list_plugins()
|
|
218
|
+
print(f"Scorers: {[s.name for s in plugins.scorers]}")
|
|
219
|
+
print(f"Team Selectors: {[t.name for t in plugins.team_selectors]}")
|
|
220
|
+
|
|
221
|
+
# Score agents for a task
|
|
222
|
+
scores = await client.selection.score_agents(
|
|
223
|
+
task_description="Design a distributed cache system",
|
|
224
|
+
primary_domain="systems",
|
|
225
|
+
scorer="elo_weighted",
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
for agent in scores:
|
|
229
|
+
print(f"{agent.name}: {agent.score}")
|
|
230
|
+
|
|
231
|
+
# Select an optimal team
|
|
232
|
+
team = await client.selection.select_team(
|
|
233
|
+
task_description="Build a secure authentication system",
|
|
234
|
+
min_agents=3,
|
|
235
|
+
max_agents=5,
|
|
236
|
+
diversity_preference=0.7,
|
|
237
|
+
quality_priority=0.8,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
print(f"Team: {[f'{a.name} ({a.role})' for a in team.agents]}")
|
|
241
|
+
print(f"Expected quality: {team.expected_quality}")
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Memory API
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
# Get analytics
|
|
248
|
+
analytics = await client.memory.analytics(days=30)
|
|
249
|
+
print(f"Total entries: {analytics.total_entries}")
|
|
250
|
+
print(f"Learning velocity: {analytics.learning_velocity}")
|
|
251
|
+
|
|
252
|
+
# Get tier-specific stats
|
|
253
|
+
fast_tier = await client.memory.tier_stats("fast")
|
|
254
|
+
|
|
255
|
+
# Take manual snapshot
|
|
256
|
+
snapshot = await client.memory.snapshot()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Health Check
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
health = await client.health()
|
|
263
|
+
print(f"Status: {health.status}")
|
|
264
|
+
print(f"Version: {health.version}")
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## WebSocket Streaming
|
|
268
|
+
|
|
269
|
+
Stream debate events in real-time.
|
|
270
|
+
|
|
271
|
+
### Class-based API
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from aragora_client import DebateStream
|
|
275
|
+
|
|
276
|
+
debate_id = "debate-123"
|
|
277
|
+
stream = DebateStream("ws://localhost:8765", debate_id)
|
|
278
|
+
|
|
279
|
+
stream.on("agent_message", lambda e: print(f"Agent: {e.data}"))
|
|
280
|
+
stream.on("consensus", lambda e: print("Consensus reached!"))
|
|
281
|
+
stream.on("debate_end", lambda e: stream.disconnect())
|
|
282
|
+
stream.on_error(lambda e: print(f"Error: {e}"))
|
|
283
|
+
|
|
284
|
+
await stream.connect()
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Async Iterator API
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from aragora_client import stream_debate
|
|
291
|
+
|
|
292
|
+
async for event in stream_debate("ws://localhost:8765", "debate-123"):
|
|
293
|
+
print(event.type, event.data)
|
|
294
|
+
|
|
295
|
+
if event.type == "debate_end":
|
|
296
|
+
break
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### WebSocket Options
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
stream = DebateStream(
|
|
303
|
+
"ws://localhost:8765",
|
|
304
|
+
"debate-123",
|
|
305
|
+
reconnect=True, # Auto-reconnect on disconnect
|
|
306
|
+
reconnect_interval=1.0, # Base reconnect delay (seconds)
|
|
307
|
+
max_reconnect_attempts=5, # Max reconnect attempts
|
|
308
|
+
heartbeat_interval=30.0, # Heartbeat ping interval (seconds)
|
|
309
|
+
)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Error Handling
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from aragora_client import (
|
|
316
|
+
AragoraError,
|
|
317
|
+
AragoraConnectionError,
|
|
318
|
+
AragoraAuthenticationError,
|
|
319
|
+
AragoraNotFoundError,
|
|
320
|
+
AragoraValidationError,
|
|
321
|
+
AragoraTimeoutError,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
await client.debates.get("nonexistent-123")
|
|
326
|
+
except AragoraNotFoundError as e:
|
|
327
|
+
print(f"Resource: {e.resource}")
|
|
328
|
+
print(f"ID: {e.resource_id}")
|
|
329
|
+
except AragoraError as e:
|
|
330
|
+
print(f"Code: {e.code}")
|
|
331
|
+
print(f"Status: {e.status}")
|
|
332
|
+
print(f"Message: {e.message}")
|
|
333
|
+
print(f"Details: {e.details}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Type Hints
|
|
337
|
+
|
|
338
|
+
All types are exported for use in your application:
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from aragora_client import (
|
|
342
|
+
# Debate types
|
|
343
|
+
Debate,
|
|
344
|
+
DebateStatus,
|
|
345
|
+
ConsensusResult,
|
|
346
|
+
GraphDebate,
|
|
347
|
+
GraphBranch,
|
|
348
|
+
MatrixDebate,
|
|
349
|
+
MatrixConclusion,
|
|
350
|
+
# Verification types
|
|
351
|
+
VerificationResult,
|
|
352
|
+
VerificationStatus,
|
|
353
|
+
# Agent types
|
|
354
|
+
AgentProfile,
|
|
355
|
+
GauntletReceipt,
|
|
356
|
+
# Event types
|
|
357
|
+
DebateEvent,
|
|
358
|
+
# Selection types
|
|
359
|
+
SelectionPlugins,
|
|
360
|
+
TeamSelection,
|
|
361
|
+
AgentScore,
|
|
362
|
+
)
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Advanced Patterns
|
|
366
|
+
|
|
367
|
+
### Retry with Exponential Backoff
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
from aragora_client import AragoraClient, AragoraError
|
|
371
|
+
|
|
372
|
+
async def with_retry(fn, max_retries=3, base_delay=1.0):
|
|
373
|
+
last_error = None
|
|
374
|
+
|
|
375
|
+
for attempt in range(max_retries):
|
|
376
|
+
try:
|
|
377
|
+
return await fn()
|
|
378
|
+
except AragoraError as e:
|
|
379
|
+
last_error = e
|
|
380
|
+
# Don't retry client errors (4xx)
|
|
381
|
+
if e.status and e.status < 500:
|
|
382
|
+
raise
|
|
383
|
+
if attempt < max_retries - 1:
|
|
384
|
+
delay = base_delay * (2 ** attempt)
|
|
385
|
+
await asyncio.sleep(delay)
|
|
386
|
+
|
|
387
|
+
raise last_error
|
|
388
|
+
|
|
389
|
+
# Usage
|
|
390
|
+
debate = await with_retry(
|
|
391
|
+
lambda: client.debates.run(task="Design a system")
|
|
392
|
+
)
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Concurrent Debates with Semaphore
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
import asyncio
|
|
399
|
+
from aragora_client import AragoraClient
|
|
400
|
+
|
|
401
|
+
async def run_debates_concurrent(tasks: list[str], max_concurrent: int = 3):
|
|
402
|
+
client = AragoraClient("http://localhost:8080")
|
|
403
|
+
semaphore = asyncio.Semaphore(max_concurrent)
|
|
404
|
+
|
|
405
|
+
async def run_with_semaphore(task: str):
|
|
406
|
+
async with semaphore:
|
|
407
|
+
return await client.debates.run(task=task)
|
|
408
|
+
|
|
409
|
+
return await asyncio.gather(*[run_with_semaphore(t) for t in tasks])
|
|
410
|
+
|
|
411
|
+
# Run multiple debates with controlled concurrency
|
|
412
|
+
tasks = ["Design auth system", "Choose database", "API architecture"]
|
|
413
|
+
debates = await run_debates_concurrent(tasks, max_concurrent=2)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Requirements
|
|
417
|
+
|
|
418
|
+
- Python 3.10+
|
|
419
|
+
- httpx >= 0.25.0
|
|
420
|
+
- websockets >= 12.0
|
|
421
|
+
- pydantic >= 2.0.0
|
|
422
|
+
|
|
423
|
+
## License
|
|
424
|
+
|
|
425
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
aragora_client/__init__.py,sha256=-cYE0IbQYSAqyLwsQ77mDHWniel-Zj0kGWHonjtY3s4,1688
|
|
2
|
+
aragora_client/client.py,sha256=IBlnoMjiHIc4ngIK7S4ujnbfxvS-Lkybj6G4JrLLEOo,17610
|
|
3
|
+
aragora_client/exceptions.py,sha256=1NBVuh-X6a4lpaxmssYlD7ctqY5ddsQsYULQ85vBFoA,2042
|
|
4
|
+
aragora_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
aragora_client/types.py,sha256=pidpy1iV8ETekSyeq7Q6nmXg7Gq0u_HGXH3X96O4BFM,7397
|
|
6
|
+
aragora_client/websocket.py,sha256=eHWjGkzqd9U7aw_IsEcrqh_BuS3f7fsuJSw-u9jG1i8,8897
|
|
7
|
+
aragora_client-2.1.10.dist-info/METADATA,sha256=w64inPM2H5swuMaT8opI2s4sQQZXQuGmY6D1jD4iosE,10347
|
|
8
|
+
aragora_client-2.1.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
9
|
+
aragora_client-2.1.10.dist-info/RECORD,,
|