/** * OTel Gen AI Semantic Convention types. * * Standardized JSON shapes for the `gen_ai.input.messages`, * `gen_ai.output.messages`, `gen_ai.system_instructions`, and * `gen_ai.tool.definitions` span attributes. * * Used by all `@introspection-sdk/*` packages that emit GenAI spans: * `introspection-node`, `introspection-pi`. * * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/ */ /** * A text content part in a message. * * `text_signature` carries opaque per-block signatures used by some * providers (e.g. OpenAI Responses message metadata) so a replayed * conversation can be sent back to the same provider without losing * signed continuity. */ export interface TextPart { /** Discriminator — always `"text"`. */ type: "text"; /** The text body of this part. */ content: string; /** Optional opaque per-block signature for replay continuity. */ text_signature?: string; } /** * A reasoning / thinking content part in a message. * * `"thinking"` is the canonical spelling: it is what the platform stores and * the vocabulary the provider SDKs use. The semantic * conventions spell it `"reasoning"`, which this SDK emits and ingest accepts — * OTLP ingest normalizes either to `"thinking"` before writing. * * Both are declared because this type is used on **both** sides: converters * build parts for emission, and readers parse parts back out of a stored span. * A stored span always says `"thinking"`, so a reader narrowing on `type` needs * that member to exist. The alias is permanent rather than transitional — * telemetry is append-only, so a part type is stored bytes. * * `signature` carries the encrypted reasoning payload (Anthropic * `signature` / `redacted_thinking`, OpenAI `encrypted_content`). * `redacted` is set when the upstream provider redacted the visible * content but kept the signed payload. */ export interface ThinkingPart { /** Discriminator — `"thinking"` as stored, `"reasoning"` per the semantic conventions. */ type: "thinking" | "reasoning"; /** The reasoning / thinking summary content. */ content: string; /** Encrypted reasoning signature (Anthropic signature / redacted_thinking, OpenAI encrypted_content). */ signature?: string; /** Provider that produced this thinking block (e.g. `"anthropic"`, `"openai"`). Used to reconstruct the correct wire format on replay. */ provider_name?: string; /** True when the thinking content was redacted by safety filters but the signed payload is preserved. */ redacted?: boolean; } /** * @deprecated Prefer {@link ThinkingPart}. Kept as an alias so existing * converters keep compiling; the two are the same type. */ export type ReasoningPart = ThinkingPart; /** A tool / function-call request part in a message. */ export interface ToolCallRequestPart { /** Discriminator — always `"tool_call"`. */ type: "tool_call"; /** Function / tool name. */ name: string; /** Correlation ID linking request to response. */ id?: string; /** Arguments passed to the tool. */ arguments?: unknown; } /** A tool / function-call response part in a message. */ export interface ToolCallResponsePart { /** Discriminator — always `"tool_call_response"`. */ type: "tool_call_response"; /** The value returned by the tool. */ response: unknown; /** Correlation ID linking response to request. */ id?: string; /** Optional tool name. Stored on `tool` messages whose tool_call counterpart was lost. */ name?: string; } /** * A media content part referenced by URL. * * The `type` discriminator names the media kind (image / audio / video / * document); the payload itself lives behind `url`. */ export interface MediaUrlPart { /** Discriminator — the media kind, or the semantic conventions' `"uri"`. */ type: "image-url" | "audio-url" | "video-url" | "document-url" | "uri"; /** URL to the media content. */ url?: string; /** Semantic-convention spelling of `url`, accepted on read. */ uri?: string; /** Modality of the referenced content. Set only on a `"uri"` part, where the type name does not carry it. */ modality?: string; /** IANA MIME type of the referenced content, when known. */ mime_type?: string; } /** * Content referenced by a provider-assigned file id (semconv `file`). * * The payload never travels with the span — only the handle the provider * issued for it — so this part is a reference, not content. */ export interface FilePart { /** Discriminator — always `"file"`. */ type: "file"; /** Provider-assigned file identifier. */ file_id?: string; /** IANA MIME type of the referenced file, when known. */ mime_type?: string; /** Modality of the referenced file. */ modality?: string; } /** * A binary data part carrying inline base64-encoded content. * * Used when media is embedded directly in the message instead of being * referenced by URL. */ export interface BinaryDataPart { /** Discriminator — always `"binary"`. */ type: "binary"; /** MIME type of the content (e.g. `"image/png"`). */ media_type: string; /** Base64-encoded content. */ content?: string; } /** * A blob part per the OTel GenAI message schemas (inline binary data such * as an image sent to the model). * * `content` (base64) is optional in this SDK: instrumentations omit the * payload to keep span attribute sizes bounded, recording only the * modality / MIME type so the message structure is preserved. */ export interface BlobPart { /** Discriminator — always `"blob"`. */ type: "blob"; /** General modality of the data (e.g. `"image"`, `"audio"`). */ modality: string; /** IANA MIME type of the data (e.g. `"image/png"`). */ mime_type?: string; /** Base64-encoded payload, when captured. */ content: string; } /** * A compacted-history summary part. * * Emitted when an agent compacts its conversation history: the model-visible * summary that replaced the compacted messages, without the prose wrapper the * agent renders around it (e.g. Pi's "The conversation history before this * point was compacted…" preamble). */ export interface CompactionPart { /** Discriminator — always `"compaction"`. */ type: "compaction"; /** Compacted summary text shown to the model. */ content: string; } /** * Union of all possible message-part shapes. * * Deliberately closed. TypeScript does not validate at runtime, so an * unrecognized part is not an error here — it simply flows through as data, * and a `switch` over `type` falls to its default. Adding an open catch-all * member would buy nothing and would cost the narrowing every consumer relies * on. (A runtime-validated union would need one, because it *is* a runtime * validator and an unknown tag there fails the whole message.) */ export type MessagePart = TextPart | ThinkingPart | ToolCallRequestPart | ToolCallResponsePart | CompactionPart | MediaUrlPart | BinaryDataPart | BlobPart | FilePart; /** A system instruction entry for `gen_ai.system_instructions`. */ export interface SystemInstruction { /** Part type — always `"text"`. */ type: "text"; /** The instruction text content. */ content: string; } /** Roles allowed on input/output messages. */ export type MessageRole = "system" | "user" | "assistant" | "tool"; /** * An input message (`gen_ai.input.messages` element). */ export interface InputMessage { role: MessageRole; parts: MessagePart[]; /** Optional tool name when `role` is `"tool"`. */ name?: string; } /** * An output message (`gen_ai.output.messages` element). */ export interface OutputMessage { role: MessageRole; parts: MessagePart[]; /** Model-reported finish reason (e.g. `"stop"`, `"length"`, `"tool_use"`). */ finish_reason?: string; /** Optional tool name when `role` is `"tool"`. */ name?: string; /** Provider name as reported by the model — useful when output messages are replayed across providers. */ provider?: string; /** Concrete model id used for the response. */ model?: string; /** API surface used to produce this response (e.g. `"openai-responses"`). */ api?: string; /** Provider-specific response identifier when the upstream API exposes one. */ response_id?: string; } /** A tool definition for the `gen_ai.tool.definitions` attribute. */ export interface ToolDefinition { /** * Tool type. Function tools use the canonical `"function"` value. * * Optional because the platform does not model it: the DP's `ToolDefinition` * declares only `name` and `description` and serializes with * `exclude_none`, so a definition read back from a conversation carries * `type` only when the emitter happened to set it. */ type?: string; /** Tool / function name. */ name: string; /** Human-readable description of what the tool does. */ description?: string; /** JSON Schema describing the tool's parameters. */ parameters?: unknown; } /** * Camel-cased GenAI attribute bag, convenient for callers that don't want to * deal with OTel's dotted attribute names directly. * * {@link toAttributes} converts this to a flat OTel attribute record with * `gen_ai.*` keys (primitive arrays like `finishReasons` pass through as * native string arrays; nested objects are JSON-serialized). */ export interface GenAiAttributes { /** Model name (gen_ai.request.model) */ requestModel?: string; /** Provider name (gen_ai.provider.name) */ providerName?: string; /** Operation name (gen_ai.operation.name) */ operationName?: string; /** Tool definitions (gen_ai.tool.definitions) — serialized to JSON by {@link toAttributes}. */ toolDefinitions?: ToolDefinition[]; /** Input messages (gen_ai.input.messages) — serialized to JSON by {@link toAttributes}. */ inputMessages?: InputMessage[]; /** Output messages (gen_ai.output.messages) — serialized to JSON by {@link toAttributes}. */ outputMessages?: OutputMessage[]; /** System instructions (gen_ai.system_instructions) — serialized to JSON by {@link toAttributes}. */ systemInstructions?: SystemInstruction[]; /** Response ID (gen_ai.response.id) */ responseId?: string; /** Response model (gen_ai.response.model) */ responseModel?: string; /** Finish reason array (gen_ai.response.finish_reasons) — emitted as a native OTel string array. */ finishReasons?: string[]; /** Input token count (gen_ai.usage.input_tokens) */ inputTokens?: number; /** Output token count (gen_ai.usage.output_tokens) */ outputTokens?: number; /** Cache creation input tokens (gen_ai.usage.cache_creation.input_tokens) */ cacheCreationInputTokens?: number; /** Cache read input tokens (gen_ai.usage.cache_read.input_tokens) */ cacheReadInputTokens?: number; /** Cost in USD (gen_ai.cost.usd) */ costUsd?: number; } /** * Convert a {@link GenAiAttributes} object into an OTel-compatible * attribute record with `gen_ai.*` dotted keys. * * Properties that are `undefined` are omitted. Primitive arrays (e.g. * `finishReasons: string[]`) pass through as native OTel string arrays. * Object-valued properties (`toolDefinitions`, `inputMessages`, …) are * JSON-serialized with `null` and `undefined` stripped, since OTel * attributes can't carry nested objects. */ export declare function toAttributes(attrs: GenAiAttributes): Record; /** * GenAI semantic-convention attribute names. * * Useful when setting attributes on a span directly (`span.setAttributes`) * without going through {@link toAttributes}. */ export declare const GenAi: { readonly CONVERSATION_ID: "gen_ai.conversation.id"; readonly AGENT_ID: "gen_ai.agent.id"; readonly AGENT_NAME: "gen_ai.agent.name"; readonly OPERATION_NAME: "gen_ai.operation.name"; readonly PROVIDER_NAME: "gen_ai.provider.name"; readonly REQUEST_MODEL: "gen_ai.request.model"; readonly RESPONSE_MODEL: "gen_ai.response.model"; readonly RESPONSE_ID: "gen_ai.response.id"; readonly RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons"; readonly USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens"; readonly USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens"; readonly USAGE_CACHE_READ_INPUT_TOKENS: "gen_ai.usage.cache_read.input_tokens"; readonly USAGE_CACHE_CREATION_INPUT_TOKENS: "gen_ai.usage.cache_creation.input_tokens"; readonly USAGE_REASONING_TOKENS: "gen_ai.usage.reasoning.output_tokens"; /** * Extension attribute (not part of the GenAI semconv registry): total * computed cost of the call in USD. Kept under `gen_ai.` for downstream * compatibility; a coordinated move to the `introspection.` namespace is * pending. */ readonly COST_USD: "gen_ai.cost.usd"; readonly TOOL_DESCRIPTION: "gen_ai.tool.description"; readonly INPUT_MESSAGES: "gen_ai.input.messages"; readonly OUTPUT_MESSAGES: "gen_ai.output.messages"; readonly SYSTEM_INSTRUCTIONS: "gen_ai.system_instructions"; readonly TOOL_DEFINITIONS: "gen_ai.tool.definitions"; readonly TOOL_NAME: "gen_ai.tool.name"; readonly TOOL_TYPE: "gen_ai.tool.type"; readonly TOOL_CALL_ID: "gen_ai.tool.call.id"; readonly TOOL_CALL_ARGUMENTS: "gen_ai.tool.call.arguments"; readonly TOOL_CALL_RESULT: "gen_ai.tool.call.result"; }; /** * Introspection-namespaced span attribute names (companions to the GenAI * semconv attributes above). */ export declare const IntrospectionAttr: { readonly TERMINATION_REASON: "introspection.termination_reason"; /** Provider-reported total cost of the call in USD (e.g. OpenRouter `usage.cost`). */ readonly LLM_COST_USD: "introspection.llm.cost_usd"; /** Provider-reported upstream inference cost in USD (OpenRouter `usage.cost_details.upstream_inference_cost`). */ readonly LLM_UPSTREAM_COST_USD: "introspection.llm.upstream_cost_usd"; }; /** * Extract provider-reported cost attributes from a raw LLM usage block. * * OpenAI-compatible gateways (e.g. OpenRouter with `usage: {include: true}`) * report the price charged for the call directly inside the usage payload. * Provider-reported cost is the ceiling comparison point vs table pricing in * platform billing, so instrumentations attach it whenever the provider * surfaces it: * * - `usage.cost` → `introspection.llm.cost_usd` * - `usage.cost_details.upstream_inference_cost` → * `introspection.llm.upstream_cost_usd` * - `usage.completion_tokens_details.reasoning_tokens` → * `gen_ai.usage.reasoning.output_tokens` * * Fields that are absent or non-numeric are skipped: the result only ever * contains attributes whose source value was present and a finite number, so * callers can pass the returned record straight to `span.setAttributes()`. */ export declare function providerCostAttributes(usage: unknown): Record; /** * How a requested abort is classified on a span * (`introspection.termination_reason`): `cancelled` for a user/runtime stop, * `awaiting_user` for a turn paused on an interrupt. A non-aborted ending * leaves the attribute unset; the span status carries the outcome. */ export type AbortTerminationReason = "cancelled" | "awaiting_user"; /** Default span name builders for chat / execute_tool / invoke_agent. */ export declare const GenAiSpanName: { chat: (provider: string) => string; executeTool: (toolName: string) => string; invokeAgent: (agentName: string) => string; }; //# sourceMappingURL=genai.d.ts.map