Choose a policy from the endpoint's failure mode
Read effects before enabling retries for a write. A read that fails before returning data and a booking that times out after being accepted need different recovery decisions.
For an availability GET, start with two total attempts, a short timeout, and a response ceiling sized to your real fixture. For a booking POST, keep one attempt until the backend supports idempotency or the operation is truly idempotent.
# Merge into request on a read-only tool.
timeout_ms: 5000
max_response_bytes: 262144
retry:
attempts: 2
backoff_ms: 300
multiplier: 2
jitter: true
With a first 503 followed by 200, this allows one retry and two tool-call budget units. With 401, there is no retry. With a consistently slow API, each attempt has its own timeout; the total operation can take longer than five seconds because attempts and waits accumulate.
Setting idempotent: true is your assertion about the API contract. It does not add deduplication to the API. Setting attempts: 3 alone on an unsafe write still permits only one attempt. A circuit can stop retrying earlier than the configured attempt count.
Verify the consequences of each limit
The default timeout is 8,000 ms, response ceiling is 1 MiB, and attempt count is one. Increasing them lets more work finish but increases wait time, memory exposure, and downstream load. Backoff defaults to 500 ms with multiplier 2 and jitter enabled; jitter chooses a delay between half and all of the calculated backoff, capped before jitter at 60 seconds.
A circuit opens after the configured number of transient failures, including failed retry attempts. Its default threshold is five and reset interval is 30 seconds. It is tracked per tool on one runtime instance, not globally across your fleet.
Test 503→200, 401, 429, a redirect, oversized response, malformed JSON, and abort. For writes, assert the same idempotency header is reused within retries and reconcile ambiguous delivery rather than assuming no success response means no write.
HttpExecutor is a separate runtime boundary. It does more than fetch(config.url).
Request safety
Before and during execution AGENTO enforces:
- fixed configured origin;
- no embedded URL username/password;
- HTTPS for credentials unless explicitly disabled for local development;
- manual redirect mode with 3xx rejection;
- bounded timeout;
- abort support;
- bounded response bytes;
- deterministic method, headers, query and body.
Timeouts
request:
timeout_ms: 8000
The timeout covers fetch and body reading. You may also pass an AbortSignal from the host:
await runtime.chat({
sessionId,
message,
signal: request.signal,
});
Retry policy
request:
retry:
attempts: 3
backoff_ms: 500
multiplier: 2
jitter: true
idempotent: true
attempts is the total number of attempts, not “extra retries,” and is capped at 5 by the schema.
Automatic retry is allowed when the operation is considered safe:
- read-only; or
- explicitly marked idempotent; or
- configured with an idempotency key.
Otherwise a side effect gets one attempt.
Transient classes include network/timeout conditions, 429 and 5xx responses.
Idempotency key
request:
idempotency:
header: Idempotency-Key
source: generated
AGENTO generates the key as part of the prepared operation. Your backend must implement idempotency semantics; sending a header alone does not create them.
Circuit breaker
request:
circuit_breaker:
threshold: 5
reset_ms: 30000
Circuit state is per runtime/tool. Ordinary 4xx authorization/client failures do not count as server instability. After reset, one probe is allowed.
Response parsing
- 204/205 and HEAD return
null. - JSON content types are parsed.
- malformed JSON is a distinct runtime error.
- text responses remain text.
- 3xx redirects are rejected.
- 401/403 map to
AUTH_REJECTED. - 429 maps to a rate-limited tool error class.
- 5xx maps to server error behavior.
Response byte limit
request:
max_response_bytes: 1048576
AGENTO streams the body and stops if the byte ceiling is exceeded. This protects memory and limits model-bound downstream work.