Reliability

Timeouts, retries, and failure boundaries that match what actually failed.

Reliability

Reliability in Shiro means knowing which boundary failed. Provider timeouts, tool hangs, approval rejections, and validation errors need different responses. One generic catch makes unsafe retries likely.

Failure boundaries#

BoundaryTypical signalSafe default
Providertimeout / HTTP / rate limitRetry with backoff
Tool (read)timeout / 5xxRetry if idempotent
Tool (write)partial failureRetry only with idempotency keys
ApprovalrejectedSurface to user; do not auto-retry
Output validationparse failureRepair policy or fail the run
Handoffunresolved agentFix registration; do not loop

See Error Handling.

Timeouts#

Bound the slow parts you do not control: model latency and external tools. Prefer configuring timeouts at the execution / tool edge rather than hoping the platform kills the process.

Keep mutating tools short or explicitly async with a job id you can poll.

Retries#

Retry reads liberally; retry writes only when the operation is idempotent.

const issueRefund = tool({
  name: "issueRefund",
  requiresApproval: true,
  parameters: z.object({
    orderId: z.string(),
    amount: z.number(),
    idempotencyKey: z.string(),
  }),
  execute: async (input) => refunds.issue(input),
});

Trace failed runs#

A retry without a trace is a guess. Export failures with Tracing and inspect them in Studio before changing prompts.

Best practices#

  • Idempotency keys on refunds, deletes, deploys
  • Explicit timeouts before production traffic
  • Treat approval rejection as a valid outcome
  • Store enough tool I/O to reproduce bugs

Common mistakes#

  • Retrying payments because the provider timed out afterward
  • Catching all errors at the HTTP layer and returning 500
  • Hiding provider errors inside tool return strings