Shirube

Documentation

Tracing, reliability, and errors

Every run has a runId. Traces, retries, timeouts, typed errors, and provider fallbacks.

Tracing

Every run has a `runId`. result.traces is an ordered list of what happened: start/end, model route and calls, tools, handoffs, memory search/add, graph read/ingest, retries, errors.

Use traces for support (“show me why this refund didn’t fire”), cost (token usage on each model.call), and SLOs (durationMs on run.end).

tracing.ts
.tracing({
  enabled: true,
  onEvent: (event) => logger.debug({ runId: event.runId, type: event.type, ...event.data }),
})

result.traces;
result.usage;
result.durationMs;
result.turns;

Disable with .tracing(false) in hot tests if you want.

Retries and timeouts

Provider calls use .retry({ maxAttempts, baseDelayMs }). The whole run is bounded by .timeout(ms) (default 120s) and .maxTurns(n) (default 10).

limits.ts
.retry({ maxAttempts: 3, baseDelayMs: 200 })
.timeout(60_000)
.maxTurns(8)

await agent.run(prompt, { abortSignal: controller.signal });

AbortError if the signal fires. TimeoutError / MaxTurnsError if limits hit. Tool failures inside the loop are *not* those — they become error payloads unless you throw from a guardrail.

Error types

Catch ShirubeError or a subclass:

ClassMeaning
ConfigErrorMissing name, instructions, or API key
GuardrailTripwireErrorA rail blocked the run
MaxTurnsErrorTool loop too long
TimeoutErrorWall clock limit
ToolErrorBad tool definition or unknown tool
ModelErrorProvider HTTP / empty response (including after fallbacks)
MemoryErrorMemory backend
McpErrorMCP connect/serve
OutputValidationErrorJSON schema still invalid after repairs
AbortErrorCaller cancelled

Fallbacks

If OpenAI is down, try Claude (or Gemini) with the same ChatRequest shape:

fallback.ts
import { OpenAIProvider, AnthropicProvider, GeminiProvider } from "shirube-ai";

.provider(new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }))
.fallback(
  new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY }),
  new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY }),
)

The first provider that returns successfully wins. All failing is ModelError. See Model providers.