Python API
The Python FastAPI backend provides full access to the ACP consensus engine for local development. It supports both asynchronous (task-based) and synchronous consensus modes. Base URL: http://localhost:8000
Starting the server
Run the FastAPI server with:
uvicorn main:app --reload --port 8000
Endpoint Overview
| Method | Path | Description |
|---|---|---|
POST | /consensus | Create async consensus task (returns task ID for polling) |
GET | /consensus/{id} | Poll status and result of a consensus task |
POST | /consensus/sync | Synchronous consensus (blocks until complete) |
GET | /health | Health check |
ConsensusRequest Schema
Both POST /consensus and POST /consensus/sync accept the same request body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes | -- | The question or prompt to reach consensus on |
models | ModelConfig[] | Yes | -- | Array of model configurations (at least 2) |
max_iterations | integer | No | 7 | Maximum number of phi-spiral iterations |
structure | string | No | "sonata" | Musical structure: "fugue" (deep analysis), "sonata" (conflict resolution), "concert" (creative) |
ModelConfig Object
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | LLM provider: "openrouter", "openai", "anthropic" |
name | string | Yes | Human-readable model name (e.g., "gpt4", "claude") |
model | string | Yes | Full model identifier (e.g., "openai/gpt-5.4-mini") |
temperature | float | No | Sampling temperature (default: 0.7) |
{
"query": "What is 2+2?",
"models": [
{
"provider": "openrouter",
"name": "gpt4",
"model": "openai/gpt-5.4-mini",
"temperature": 0.7
},
{
"provider": "openrouter",
"name": "claude",
"model": "anthropic/claude-haiku-4-5",
"temperature": 0.7
}
],
"max_iterations": 7,
"structure": "sonata"
}POST /consensus -- Async Consensus
Creates a consensus task that runs in the background. Returns immediately with a task ID that you can poll for status and results. Ideal for long-running queries or when you want non-blocking behavior.
curl -X POST http://localhost:8000/consensus \
-H "Content-Type: application/json" \
-d '{
"query": "What is 2+2?",
"models": [
{"provider": "openrouter", "name": "gpt4", "model": "openai/gpt-5.4-mini"},
{"provider": "openrouter", "name": "claude", "model": "anthropic/claude-haiku-4-5"}
],
"max_iterations": 5,
"structure": "sonata"
}'{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"progress": 0.0
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique task identifier for polling |
status | string | Task status: "pending", "running", "completed", or "failed" |
progress | float | Progress from 0.0 to 1.0 |
GET /consensus/{id} -- Poll Task Status
Poll a consensus task by its ID. When the task is still running, the response includes progress. When complete, the full result is included.
curl http://localhost:8000/consensus/550e8400-e29b-41d4-a716-446655440000{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"progress": 0.4
}{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"progress": 1.0,
"result": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"query": "What is 2+2?",
"final_answer": "4",
"consensus_reached": true,
"iterations_used": 1,
"final_D": 0.0,
"final_H_total": 1.0,
"iterations": []
}
}Polling strategy
Poll every 1-2 seconds. Check the progress field to estimate remaining time. A progress of 0.4 means roughly 40% of iterations have completed.
ConsensusResponse Schema
When a task completes, the result field contains the full consensus response. The same schema is returned directly by the synchronous endpoint.
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Consensus task identifier |
query | string | The original input query |
final_answer | string | The synthesized consensus answer |
consensus_reached | boolean | Whether models converged to agreement |
iterations_used | integer | Number of phi-spiral iterations performed |
final_D | float | Final divergence score (0 = perfect consensus) |
final_H_total | float | Final harmony score (H = 1 - D) |
iterations | array | Detailed data for each iteration (responses, D-scores, axioms used) |
POST /consensus/sync -- Synchronous Consensus
Runs consensus synchronously and blocks until the result is available. The request body is the same as the async endpoint, but the response returns the full ConsensusResponse directly (no polling required).
Timeout considerations
Synchronous consensus can take 10-60 seconds depending on model count, iteration depth, and model latency. Make sure your HTTP client timeout is set accordingly. For long-running queries, prefer the async endpoint.
curl -X POST http://localhost:8000/consensus/sync \
-H "Content-Type: application/json" \
-d '{
"query": "What is 2+2?",
"models": [
{"provider": "openrouter", "name": "gpt4", "model": "openai/gpt-5.4-mini"},
{"provider": "openrouter", "name": "claude", "model": "anthropic/claude-haiku-4-5"}
],
"max_iterations": 5
}'{
"id": "550e8400-e29b-41d4-a716-446655440000",
"query": "What is 2+2?",
"final_answer": "4",
"consensus_reached": true,
"iterations_used": 1,
"final_D": 0.0,
"final_H_total": 1.0,
"iterations": []
}GET /health -- Health Check
Returns the service status. Use for readiness probes and uptime monitoring.
curl http://localhost:8000/health{
"status": "healthy",
"service": "ACP Python API",
"version": "4.0.0"
}Async Workflow Example
A complete example showing the create-then-poll pattern:
TASK_ID=$(curl -s -X POST http://localhost:8000/consensus \
-H "Content-Type: application/json" \
-d '{
"query": "Explain quantum entanglement",
"models": [
{"provider": "openrouter", "name": "gpt4", "model": "openai/gpt-5.4-mini"},
{"provider": "openrouter", "name": "claude", "model": "anthropic/claude-haiku-4-5"}
]
}' | jq -r '.id')
echo "Task created: $TASK_ID"while true; do
STATUS=$(curl -s http://localhost:8000/consensus/$TASK_ID)
STATE=$(echo $STATUS | jq -r '.status')
PROGRESS=$(echo $STATUS | jq -r '.progress')
echo "Status: $STATE Progress: $PROGRESS"
if [ "$STATE" = "completed" ] || [ "$STATE" = "failed" ]; then
echo $STATUS | jq '.result'
break
fi
sleep 2
done