/** * Telemetry bridge between the main thread and subagent workers. * * A subagent's `AgentTelemetryConfig` (`ExecutorOptions.parentTelemetry`) * must cross to the worker through {@link toWorkerTelemetryConfig}, called on * main inside the parent's `execute_tool task` context. The result: * * - carries a {@link BridgedTracer}: the resolved main tracer plus the OTEL * context active at that call. A worker receives it as a `RemoteTracer` that * starts every span on main's real tracer (one blocking call per span) and * gets back a `RemoteSpan` whose mutators are ordered notifications. Spans * the worker starts with no active span nest under the captured context; * spans started under a bridged span nest under it on main. Hooks receive * spans that travel back as main's real spans. Times are stamped in the * worker so durations do not include main's queueing delay. * - wraps the synchronous hooks (`resolveAttributes`, `costEstimator`, * `normalizeProvider`, `normalizeAgentName`, `contentSerializer.*`) so the * worker calls them synchronously, and guards the void hooks (`onSpanStart`, * `onSpanEnd`, `onRunEnd`, `onCostDelta`, `onTelemetryWarning`) on main: * their failures reach `onTelemetryWarning` exactly as in-process instead of * rejecting in the worker. `onChatUsage` crosses as an async call (the loop * awaits it). * - accepts whatever an in-process caller would pass: every hook, and the * bridged tracer's and spans' methods, take their arguments lossily * (`rpcLossy`). Spans, functions (`model.resolveHeaders`), and other proxies * still cross by reference and errors keep their class; any other class * instance (a class-based `Model`, a tool, a library object) reaches main as * a plain copy of its data fields and getters instead of failing the call. * - is matched by the {@link TELEMETRY_CONFIG_KIND} codec; decoding it on a * worker installs an async-local context manager there if none exists. * * Spans a worker leaves open when it exits are ended on main with an error status. */ import { type AgentTelemetryConfig } from "@oh-my-pi/pi-agent-core"; import { type Context, type Span, type SpanOptions, type Tracer } from "@opentelemetry/api"; import type { ThreadService } from "../services.js"; /** Main-thread tracer handed to workers: delegates to `target`, remembers the context the run left main in. */ export declare class BridgedTracer implements Tracer { /** The real tracer spans start on. */ readonly target: Tracer; /** Context active when the run was handed off; parents worker spans that have no parent of their own. */ readonly parentContext: Context; constructor(target: Tracer, parentContext: Context); startSpan(name: string, options?: SpanOptions, ctx?: Context): Span; startActiveSpan(name: string, fn: (span: Span) => R): R; startActiveSpan(name: string, options: SpanOptions | undefined, fn: (span: Span) => R): R; startActiveSpan(name: string, options: SpanOptions | undefined, ctx: Context | undefined, fn: (span: Span) => R): R; } /** * Prepare `config` for a subagent worker (see the module doc). Call on main * inside the OTEL context the subagent's spans should nest under. */ export declare function toWorkerTelemetryConfig(config: AgentTelemetryConfig): AgentTelemetryConfig; /** OTEL tracer, span, and telemetry-hook bridging for subagent workers. */ export declare const telemetryThreadService: ThreadService;