Skip to main content
rebuno.Agent serves an HTTP webhook and runs your handler once per dispatch. It runs under an active execution context, so @tool, http_client(), and step() record durably.

The handler

The handler is the async function you hand to agent.run() or agent.bind(), named process in the examples below. Its signature is the input schema: the parameters decide how an execution’s input is delivered. Three shapes:
Binding happens before your handler runs. A missing required field or a pydantic error fails the execution. The return value becomes the execution’s output and has to be JSON-serializable.

run() vs app

run() binds the handler and serves it with uvicorn. It blocks:
Use agent.app to mount the agent into an existing service, or to run your own uvicorn/gunicorn. It is a FastAPI instance with the webhook route registered:
agent.app’s lifespan closes the kernel HTTP client on shutdown. agent.run(...) does the equivalent cleanup itself.

Dispatch and resume

Each webhook POST carries an execution_id, a dispatch_id, a dispatch_attempt, and a lease_timeout_seconds. The agent:
  1. Verifies the Rebuno-Signature header (see Signing). A bad or missing signature gets a 401.
  2. Acknowledges immediately. The handler runs in a background task and the webhook returns 200 right away, so delivery isn’t held open for the whole execution.
  3. Cancels the handler still running for that execution when the webhook supersedes it, so a re-delivery doesn’t leave two copies racing. A repeat of the attempt already running, or of one the kernel has moved past, is ignored.
  4. Skips terminal executions. Nothing to do if it is already completed, failed, or cancelled.
  5. Runs. It fetches the execution’s input, binds it, and calls your handler under the ambient execution context.
The same handler runs on every dispatch, and each recorded step returns its stored result instead of executing again. See How it works for what breaks this. A Blocked or Terminated your handler swallows still ends the dispatch correctly, because the execution context remembers it and Agent re-raises it. A denial or rate limit has no such backstop and has to escape the handler, but it may arrive wrapped in a provider SDK’s own error type, which raise_for_refusal() unwraps.

What happens on failure

The agent maps outcomes from your handler onto the execution: See Errors for what each exception means.

Lifecycle

run() and the app lifespan call close() for you. Call these directly only when you manage the agent’s lifetime yourself.