Batch runs
Agenta has no endpoint that accepts a list of inputs and runs an agent once per entry. POST /services/agent/v0/invoke takes one message list and produces one turn. The request body carries data.inputs as a single object, not an array.
To run an agent over many inputs, send one request per input and manage the fan-out in your own code.
One request per input
# /// script
# requires-python = ">=3.10"
# dependencies = ["httpx>=0.27"]
# ///
import asyncio
import os
import uuid
import httpx
BASE = "https://eu.cloud.agenta.ai"
PROJECT_ID = "019d952f-0000-0000-0000-000000000000"
REVISION_ID = "019d952f-0000-0000-0000-000000000002"
API_KEY = os.environ["AGENTA_API_KEY"]
INPUTS = [
"Summarize ticket 4821.",
"Summarize ticket 4822.",
"Summarize ticket 4823.",
]
CONCURRENCY = 4
async def run_one(client: httpx.AsyncClient, gate: asyncio.Semaphore, text: str) -> dict:
async with gate:
response = await client.post(
f"{BASE}/services/agent/v0/invoke",
params={"project_id": PROJECT_ID},
headers={
"Authorization": f"ApiKey {API_KEY}",
"Accept": "application/json",
"Content-Type": "application/json",
},
json={
"session_id": uuid.uuid4().hex,
"references": {"workflow_revision": {"id": REVISION_ID}},
"data": {"inputs": {"messages": [{"role": "user", "content": text}]}},
},
timeout=300.0,
)
return response.json()
async def main() -> None:
gate = asyncio.Semaphore(CONCURRENCY)
async with httpx.AsyncClient() as client:
results = await asyncio.gather(
*(run_one(client, gate, text) for text in INPUTS)
)
for text, result in zip(INPUTS, results):
outputs = (result.get("data") or {}).get("outputs") or {}
messages = outputs.get("messages") or []
reply = messages[-1].get("content") if messages else ""
print(text, "->", reply)
asyncio.run(main())
Field-by-field detail for the request and the response is in Invoke an agent.
Choosing session ids
The session_id decides whether the runs share a conversation.
| Pattern | Effect |
|---|---|
A fresh session_id per input | Each input runs as its own conversation, with its own session folder. Nothing carries over. |
One session_id for every input, with the growing history in data.inputs.messages | One conversation. Each turn sees the previous ones, and the session folder persists across them. |
No session_id | The server mints one per request and returns it in session_id and in the x-ag-session-id response header. |
What the client handles
| Concern | Behaviour |
|---|---|
| Concurrency | There is no server-side queue for these requests. Bound the fan-out in your own code. |
| Failures | Each run reports its own outcome in status.code. A failed run does not affect the others. |
| Approvals | Under a runner.permissions.default of ask or allow_reads, a run can stop with stop_reason: "paused" and wait for an approval. A default of allow never pauses. See Permissions. |
| Ordering | Concurrent runs complete in any order. |
Evaluation runs
Agenta has a separate fan-out engine for evaluations. An evaluation run takes a testset revision and a workflow revision, and invokes the workflow once per testcase, bounded by data.concurrency.batch_size. It stores each result and computes metrics.
| Method and path | Purpose |
|---|---|
POST /api/simple/testsets/ | Create a testset and its rows in one call. The response carries the revision_id. |
POST /api/simple/evaluations/ | Create an evaluation run. This also starts it. |
GET /api/simple/evaluations/{evaluation_id} | Read the run's status at data.status. |
POST /api/simple/evaluations/{evaluation_id}/stop | Stop a running evaluation. |
POST /api/evaluations/results/query | Read the per-testcase results. |
POST /api/evaluations/metrics/query | Read the run's metrics. |
The run's steps are revision ids:
{
"evaluation": {
"name": "Ticket summaries",
"data": {
"testset_steps": {"019d952f-0000-0000-0000-000000000010": "auto"},
"application_steps": {"019d952f-0000-0000-0000-000000000002": "auto"},
"repeats": 1,
"concurrency": {"batch_size": 10, "max_retries": 0, "retry_delay": 0}
}
}
}
Two constraints apply:
- A run carries exactly one entry in
application_steps. A run with more than one is never dispatched and stays in its running state. - Each testcase is filtered against the target workflow's declared input schema before the call. The agent workflow declares one input,
messages, so a testset column with any other name does not reach the agent.
The playground's run-all control does not apply to agents. An agent runs from the chat composer, one turn at a time, so there are no testcase rows to fan out in the playground.