Skip to content

Telemetry and redaction

Typed in-process events, payload-free by default, plus the redaction registry that keeps secrets out of everything. Concepts: telemetry · credentials and redaction.

Observing

anyinfer.Observer

Bases: Protocol

A telemetry sink.

Implementations receive every event the client emits. Keep on_event fast and non-blocking; queue work elsewhere if it might be slow.

on_event

on_event(event: TelemetryEvent) -> None

Handle one telemetry event.

anyinfer.TelemetryEvent module-attribute

TelemetryEvent = (
    RequestStarted
    | TargetResolved
    | AttemptStarted
    | FirstToken
    | AttemptCompleted
    | RetryScheduled
    | FallbackTriggered
    | RepairAttempted
    | RequestCompleted
    | RequestFailed
    | ParameterDropped
    | UsageEstimated
    | ServerLifecycle
    | DownloadProgress
    | ContextReduced
)

Any event an observer may receive.

Request lifecycle events

anyinfer.RequestStarted dataclass

RequestStarted(
    request_id: str,
    targets: tuple[Target, ...],
    metadata: Mapping[str, str] = dict(),
    prompt_text: str | None = None,
)

A generation request entered the router.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

targets tuple[Target, ...]

The fallback chain as requested, in the order the router will try it.

metadata Mapping[str, str]

Caller-supplied labels from the request, passed through untouched.

prompt_text str | None

The prompt text; None unless the receiving observer registered with payloads=True.

anyinfer.TargetResolved dataclass

TargetResolved(request_id: str, target: ResolvedTarget)

A target string resolved to a concrete provider and model.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The concrete provider and model the target string resolved to.

anyinfer.AttemptStarted dataclass

AttemptStarted(
    request_id: str,
    target: ResolvedTarget,
    attempt_number: int,
)

An attempt against one resolved target began.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target being attempted.

attempt_number int

1-based count of attempts against this target; retries increment it, and falling back to a new target restarts it at 1.

anyinfer.FirstToken dataclass

FirstToken(
    request_id: str, target: ResolvedTarget, at_ms: float
)

The first content delta arrived — the centrally-measured TTFT.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target that produced the token.

at_ms float

Milliseconds from attempt start to the first content delta.

anyinfer.AttemptCompleted dataclass

AttemptCompleted(
    request_id: str,
    target: ResolvedTarget,
    usage: Usage,
    timing: Timing,
    finish_reason: str,
)

An attempt finished successfully.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target that served the attempt.

usage Usage

Token usage for the attempt, merged across every report the provider sent.

timing Timing

Centrally-measured attempt timings, comparable across providers.

finish_reason str

Normalized reason generation stopped, e.g. stop or length.

anyinfer.RetryScheduled dataclass

RetryScheduled(
    request_id: str,
    target: ResolvedTarget,
    attempt_number: int,
    delay_s: float,
    error: ErrorInfo,
)

A retryable failure will be retried against the same target after a delay.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target that will be retried.

attempt_number int

The 1-based attempt that just failed; the retry is the next one.

delay_s float

Seconds the router sleeps before the retry.

error ErrorInfo

Snapshot of the retryable failure.

anyinfer.FallbackTriggered dataclass

FallbackTriggered(
    request_id: str,
    from_target: ResolvedTarget,
    to_target: Target,
    error: ErrorInfo | None = None,
)

A target was abandoned; the router advanced to the next in the chain.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

from_target ResolvedTarget

The resolved target that was abandoned.

to_target Target

The next target string the router will try, not yet resolved.

error ErrorInfo | None

Snapshot of the failure that caused the abandonment, or None when the switch was a content-policy redirect rather than an error.

anyinfer.RepairAttempted dataclass

RepairAttempted(
    request_id: str,
    target: ResolvedTarget,
    attempt_number: int,
    mechanism: Mechanism | None,
    errors: tuple[str, ...] = (),
    raw_text: str | None = None,
)

A schema violation triggered a repair re-prompt.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target being re-prompted.

attempt_number int

1-based count of repair attempts within this generation.

mechanism Mechanism | None

The structured-output mechanism in force when validation failed, when one was chosen.

errors tuple[str, ...]

The schema-validation messages that triggered the repair.

raw_text str | None

The response text that failed validation; None unless the receiving observer registered with payloads=True.

anyinfer.ParameterDropped dataclass

ParameterDropped(
    request_id: str,
    target: ResolvedTarget,
    parameter: str,
    reason: str,
)

A requested parameter was not sent, because the target cannot accept it.

Dropping a parameter silently is how a caller ends up debugging why temperature=0 had no effect. Every drop is observable instead.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target the parameter was withheld from.

parameter str

Name of the request parameter that was not sent.

reason str

Human-readable explanation of why the target cannot accept it.

anyinfer.ContextReduced dataclass

ContextReduced(
    strategy: str,
    representation: str,
    candidate_count: int,
    selected_count: int,
    omitted_count: int,
    estimated_tokens: int,
    max_tokens: int,
    binding_constraints: tuple[str, ...] = (),
    calls: int = 0,
)

A context corpus was reduced to fit a budget.

Reduction emulates a larger context window, and emulation is observable rather than silent. Content-free by construction: counts and ceilings only, never paths or document text — a path name can itself be sensitive.

Attributes:

Name Type Description
strategy str

The strategy requested (auto stays auto).

representation str

The strategy actually applied.

candidate_count int

Documents offered to the reducer.

selected_count int

Documents represented at detail fidelity.

omitted_count int

Documents not represented in detail.

estimated_tokens int

Planning-side estimate of the rendered envelope.

max_tokens int

The budget the reduction was held to.

binding_constraints tuple[str, ...]

Which ceilings excluded at least one document.

calls int

Generation calls spent; non-zero only for distill.

anyinfer.UsageEstimated dataclass

UsageEstimated(
    request_id: str,
    target: ResolvedTarget,
    field_name: str,
    method: str,
)

A usage figure was derived rather than reported by the provider.

Estimated and reported numbers must never be indistinguishable downstream; this event is what marks the difference for observers.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target the estimate applies to.

field_name str

The usage field that was estimated, e.g. input_tokens.

method str

How the estimate was derived.

anyinfer.RequestCompleted dataclass

RequestCompleted(
    request_id: str,
    target: ResolvedTarget,
    usage: Usage,
    timing: Timing,
    repair_attempts: int = 0,
    response_text: str | None = None,
)

A request produced a result.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

target ResolvedTarget

The resolved target that produced the result.

usage Usage

Final token usage for the request.

timing Timing

Final centrally-measured timings for the request.

repair_attempts int

How many repair re-prompts were needed; 0 means the first response validated.

response_text str | None

The final response text; None unless the receiving observer registered with payloads=True.

anyinfer.RequestFailed dataclass

RequestFailed(request_id: str, error: ErrorInfo)

A request exhausted its route without a result.

Attributes:

Name Type Description
request_id str

Correlation id shared by every event this request emits.

error ErrorInfo

Snapshot of the terminal failure, after every target and retry was spent.

Local subsystem events

anyinfer.DownloadProgress dataclass

DownloadProgress(
    artifact_id: str,
    downloaded_bytes: int,
    total_bytes: int | None,
    done: bool = False,
    phase: str = "",
    file_index: int = 0,
    file_count: int = 0,
    filename: str = "",
    session_bytes: int = 0,
)

Progress of a model acquisition.

downloaded_bytes and total_bytes are aggregate across the whole acquisition, which is what their names have always implied. Earlier builds reported them per file, so a sharded artifact restarted the counter at zero on every shard with no way for an observer to tell. The remaining fields carry the per-file detail that the aggregate figures deliberately no longer mix in.

Attributes:

Name Type Description
artifact_id str

The artifact or catalog variant being acquired.

downloaded_bytes int

Bytes present across every file, including bytes that were already on disk before this run — so resuming reports the resumed position.

total_bytes int | None

Total expected bytes, or None when a size is genuinely unknown.

done bool

Whether the acquisition finished.

phase str

Which stage emitted this, when the acquisition engine supplied one.

file_index int

1-based index of the file that most recently advanced.

file_count int

How many files this acquisition covers.

filename str

Name of that file.

session_bytes int

Bytes this run actually transferred, as opposed to resumed.

anyinfer.ServerLifecycle dataclass

ServerLifecycle(
    server_id: str,
    state: Literal[
        "starting",
        "ready",
        "stopping",
        "stopped",
        "crashed",
    ],
    detail: str = "",
)

A supervised local server changed state.

Attributes:

Name Type Description
server_id str

Identifies the supervised server — the key of the model it serves.

state Literal['starting', 'ready', 'stopping', 'stopped', 'crashed']

The state the server just entered.

detail str

Human-readable context, such as a stop reason or a tail of crash output; empty when there is nothing to add.

Redaction

anyinfer.RedactionRegistry

RedactionRegistry()

A thread-safe set of secrets to strip from outbound strings.

register

register(secret: str | None) -> None

Register a secret for redaction.

Values shorter than MIN_SECRET_LEN are ignored: redacting them would corrupt unrelated text far more often than it would protect anything.

redact

redact(text: str) -> str

Replace every registered secret in text with REDACTED.

clear

clear() -> None

Forget all registered secrets. Intended for tests.

__len__

__len__() -> int

Number of registered secrets.

anyinfer.register_secret

register_secret(secret: str | None) -> None

Register a secret with the process-wide registry.

anyinfer.redact

redact(text: str) -> str

Redact registered secrets from text using the process-wide registry.

OpenTelemetry export

The optional [otel] extra maps these events onto OpenTelemetry spans and metrics. Guide: observability.

anyinfer.otel.install

install(
    client: Any, *, record_payloads: bool = False
) -> OTelObserver

Attach an OTelObserver to a client.

Parameters:

Name Type Description Default
client Any

An AsyncClient or Client.

required
record_payloads bool

Attach prompt and response text to spans.

False

Returns:

Type Description
OTelObserver

The observer, so it can be detached later.

anyinfer.otel.OTelObserver

OTelObserver(
    *,
    tracer: Any = None,
    meter: Any = None,
    record_payloads: bool = False,
)

Maps AnyInfer telemetry events onto OpenTelemetry spans and metrics.

One span per request, with attempts as span events. Requests and attempts are correlated by request_id, so a fallback chain reads as a single trace rather than several disconnected ones.

Parameters:

Name Type Description Default
tracer Any

An OpenTelemetry tracer. Defaults to one from the global provider.

None
meter Any

An OpenTelemetry meter. Defaults to one from the global provider.

None
record_payloads bool

Attach prompt and response text to spans. Off by default, matching the payload-free default of the event contract itself. Subscribe with payloads=True as well for this to have any effect.

False

Raises:

Type Description
ConfigError

If opentelemetry-api is not installed.

on_event

on_event(event: TelemetryEvent) -> None

Handle one telemetry event.

Never raises: the dispatcher isolates observer failures, but a telemetry bridge that can break a generation would be a poor trade regardless.

anyinfer.otel.GEN_AI module-attribute

GEN_AI = 'gen_ai'

Prefix of the GenAI semantic-convention attribute namespace.