Retry & auth
Retry and auth are interceptors, layered around the transport. Order matters: the
first in the list is the outermost wrapper, so put RetryInterceptor first to
re-run the whole call (re-stamping auth on each attempt).
import 'package:koel/koel.dart' show HttpAgent, KoelClient;
import 'package:koel_http/koel_http.dart'
show AuthInterceptor, RetryInterceptor;
final client = KoelClient(
agent: HttpAgent(url: Uri.parse('https://your-backend.example/agui')),
interceptors: [
RetryInterceptor(), // outermost
AuthInterceptor(headers: () async => {
'Authorization': 'Bearer ${await tokenStore.read()}',
}),
],
);
Retry policy
RetryInterceptor backs off exponentially with jitter and only retries
transient transport failures — a parsed in-band RUN_ERROR is the agent's
answer, not a transport fault, so it is never retried.
RetryInterceptor(
maxAttempts: 5,
baseDelay: const Duration(seconds: 1),
maxDelay: const Duration(seconds: 30),
jitter: 0.2,
);
Auth from an async provider
AuthInterceptor takes a headers provider called per attempt, so a token
refreshed between retries is picked up automatically. Return whatever header map
your backend expects:
AuthInterceptor(headers: () async => {'x-api-key': await keyStore.read()});
For a known backend, the bridge package already wires its convention —
AgnoAgent(token:),
LangGraphAgent(apiKey:) — so you rarely add
AuthInterceptor by hand there.