Lifecycle functions

Signatures and defaults for capsera.init(), flush(), shutdown(), and get_interception_report() — every parameter, including the ones with no docstring.

Four functions control the SDK's lifetime: one to start it, two to control delivery, and one to check that interception actually happened.

init()

capsera.init(
    api_key: str = "dev",
    endpoint: str = "http://localhost:8000",
    agent_name: str | None = None,
    team: str | None = None,
    gateway: str | None = None,
    env: str = "development",
    flush_interval_ms: int = 500,
    enable_routing: bool = False,
    routing_rules: list[dict] | None = None,
    routing_refresh_interval: int = 60,
    critical_task_types: list[str] | None = None,
    enable_budget_enforcement: bool = True,
    budget_check_timeout: float = 1.0,
    enable_prompt_analysis: bool = False,
    prompt_size_threshold: int = 4000,
    on_oversized_prompt: Callable[[int, int], None] | None = None,
    debug: bool = False,
    max_retries: int = 3,
    on_error: Callable[[str], None] | None = None,
) -> None

Builds the configuration, starts the emitter thread, creates the router and prompt analyser if enabled, and patches every provider and gateway library it finds installed. Returns None.

Connection

ParameterDefaultNotes
api_key"dev"Your cap- key. "dev" is for local experiments.
endpoint"http://localhost:8000"Backend base URL. A trailing slash is stripped.
env"development"Environment label recorded on every event.

Default attribution

ParameterDefaultNotes
agent_nameNoneFallback agent for calls with no scope, replacing unknown.
teamNoneFallback team.
gatewayNoneDeclares the gateway all traffic rides through. Only needed for a self-hosted gateway whose host the SDK cannot recognise. Added in 0.4.0.

Decorators and tag() override all three.

Delivery

ParameterDefaultNotes
flush_interval_ms500How often the worker ships a batch.
max_retries3Attempts per failed batch, with exponential backoff.
on_errorNonecallback(message: str), called on dropped events, circuit-breaker trips, and the monthly limit being reached. Exceptions it raises are swallowed.

Nothing in your call path waits on delivery, so lowering flush_interval_ms does not make calls faster — it makes events appear sooner and sends more requests.

Budget enforcement

ParameterDefaultNotes
enable_budget_enforcementTruePre-call budget check. See Budgets and enforcement.
budget_check_timeout1.0Seconds before the check gives up and allows the call.

This is the one default that adds latency: one round trip to the backend before each provider call. A blocking decision raises BudgetExceededError; a downgrade decision rewrites the model on the call.

Routing

ParameterDefaultNotes
enable_routingFalseTurns the routing engine on.
routing_rulesNoneRules defined in code. See Routing for the dict shape.
routing_refresh_interval60Seconds between backend refreshes of rules and budget utilisation.
critical_task_typesNoneTask types exempt from cost-cap routing and from budget-margin downgrades.

Prompt analysis

ParameterDefaultNotes
enable_prompt_analysisFalseRecords prompt structure. Never records content.
prompt_size_threshold4000Estimated-token threshold that fires the callback below.
on_oversized_promptNonecallback(estimated_tokens, threshold). Exceptions it raises are swallowed.

Diagnostics

ParameterDefaultNotes
debugFalseDetailed logging on the capsera logger, roughly one line per intercepted call. Also calls logging.basicConfig(level=DEBUG).

Calling it twice

init() is safe to call again, and safe to call after your LLM clients are imported or even instantiated — patches are applied to the classes and to live instances.

A second call flushes and stops the previous emitter, so events recorded under the old configuration are delivered rather than stranded, then starts a new one. Pooled budget-check clients are discarded so a changed endpoint, api_key, or timeout takes effect immediately. Patching itself is idempotent, guarded by a flag on each patched class.

capsera.init(
    api_key=os.environ["CAPSERA_API_KEY"],
    endpoint="https://api.capsera.ai",
    env="production",
    on_error=lambda msg: logger.warning(msg),
)

flush()

capsera.flush() -> None

Ships everything currently queued, on the calling thread. Useful in a short-lived script or a test teardown, where the process may exit before the worker's next tick.

No-op if init() has not run. Skipped while the circuit breaker is open, since the backend is known to be failing.

shutdown()

capsera.shutdown() -> None

Flushes remaining events, signals the worker thread to stop, and joins it, waiting up to 10 seconds.

Already registered with atexit, so a normal process exit calls it for you. Call it explicitly only when delivery must complete at a specific point — before a container is killed, for instance. Safe from any thread, and a no-op before init().

get_interception_report()

capsera.get_interception_report() -> dict[str, str]

Returns the live patch status of every surface the SDK knows how to hook.

ValueMeaning
"patched"Calls through this surface are captured.
"unpatched"The library is importable but not hooked — init() has not run, or patching failed.
"not-installed"The library is absent from this environment.

The keys are fixed:

anthropic.messages                openai.embeddings           mistral.chat_complete
anthropic.messages_async          openai.embeddings_async     cohere.chat
openai.chat_completions           google.generativeai         vertex.generate_content
openai.chat_completions_async     google.genai                bedrock.converse
litellm.callbacks                 portkey.chat_completions

The point of it is to turn a silent gap into a startup failure. An empty dashboard has many causes; this narrows it to one question in one line.

report = capsera.get_interception_report()
assert report["anthropic.messages"] == "patched", report

See Verify it works for what to check after this, and No data appearing when a surface reports unpatched.