risicare 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frameworks/instructor.cjs +45 -17
- package/dist/frameworks/instructor.cjs.map +1 -1
- package/dist/frameworks/instructor.js +47 -17
- package/dist/frameworks/instructor.js.map +1 -1
- package/dist/frameworks/langchain.cjs +73 -6
- package/dist/frameworks/langchain.cjs.map +1 -1
- package/dist/frameworks/langchain.d.cts +20 -4
- package/dist/frameworks/langchain.d.ts +20 -4
- package/dist/frameworks/langchain.js +75 -6
- package/dist/frameworks/langchain.js.map +1 -1
- package/dist/frameworks/langgraph.cjs +73 -6
- package/dist/frameworks/langgraph.cjs.map +1 -1
- package/dist/frameworks/langgraph.js +75 -6
- package/dist/frameworks/langgraph.js.map +1 -1
- package/dist/frameworks/llamaindex.cjs +41 -14
- package/dist/frameworks/llamaindex.cjs.map +1 -1
- package/dist/frameworks/llamaindex.js +43 -14
- package/dist/frameworks/llamaindex.js.map +1 -1
- package/dist/index.cjs +1494 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +436 -1
- package/dist/index.d.ts +436 -1
- package/dist/index.js +1515 -67
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic/index.cjs +74 -24
- package/dist/providers/anthropic/index.cjs.map +1 -1
- package/dist/providers/anthropic/index.js +76 -24
- package/dist/providers/anthropic/index.js.map +1 -1
- package/dist/providers/bedrock/index.cjs +81 -24
- package/dist/providers/bedrock/index.cjs.map +1 -1
- package/dist/providers/bedrock/index.js +83 -24
- package/dist/providers/bedrock/index.js.map +1 -1
- package/dist/providers/cerebras/index.cjs +78 -25
- package/dist/providers/cerebras/index.cjs.map +1 -1
- package/dist/providers/cerebras/index.js +80 -25
- package/dist/providers/cerebras/index.js.map +1 -1
- package/dist/providers/cohere/index.cjs +95 -25
- package/dist/providers/cohere/index.cjs.map +1 -1
- package/dist/providers/cohere/index.js +97 -25
- package/dist/providers/cohere/index.js.map +1 -1
- package/dist/providers/google/index.cjs +77 -25
- package/dist/providers/google/index.cjs.map +1 -1
- package/dist/providers/google/index.js +79 -25
- package/dist/providers/google/index.js.map +1 -1
- package/dist/providers/groq/index.cjs +80 -25
- package/dist/providers/groq/index.cjs.map +1 -1
- package/dist/providers/groq/index.js +82 -25
- package/dist/providers/groq/index.js.map +1 -1
- package/dist/providers/huggingface/index.cjs +80 -25
- package/dist/providers/huggingface/index.cjs.map +1 -1
- package/dist/providers/huggingface/index.js +82 -25
- package/dist/providers/huggingface/index.js.map +1 -1
- package/dist/providers/mistral/index.cjs +72 -24
- package/dist/providers/mistral/index.cjs.map +1 -1
- package/dist/providers/mistral/index.js +74 -24
- package/dist/providers/mistral/index.js.map +1 -1
- package/dist/providers/ollama/index.cjs +83 -25
- package/dist/providers/ollama/index.cjs.map +1 -1
- package/dist/providers/ollama/index.js +85 -25
- package/dist/providers/ollama/index.js.map +1 -1
- package/dist/providers/openai/index.cjs +1429 -28
- package/dist/providers/openai/index.cjs.map +1 -1
- package/dist/providers/openai/index.js +1447 -28
- package/dist/providers/openai/index.js.map +1 -1
- package/dist/providers/together/index.cjs +80 -25
- package/dist/providers/together/index.cjs.map +1 -1
- package/dist/providers/together/index.js +82 -25
- package/dist/providers/together/index.js.map +1 -1
- package/dist/providers/vercel-ai/index.cjs +45 -17
- package/dist/providers/vercel-ai/index.cjs.map +1 -1
- package/dist/providers/vercel-ai/index.js +47 -17
- package/dist/providers/vercel-ai/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ids.ts","../../../src/noop.ts","../../../src/globals.ts","../../../src/context/storage.ts","../../../src/utils/log.ts","../../../src/client.ts","../../../src/utils/pricing.ts","../../../src/context/dedup.ts","../../../src/providers/openai/patch.ts"],"sourcesContent":["/**\n * ID generation for traces and spans.\n *\n * Trace IDs: 32 lowercase hex characters (16 random bytes)\n * Span IDs: 16 lowercase hex characters (8 random bytes)\n *\n * Uses crypto.randomBytes for cryptographically secure randomness.\n */\n\nimport { randomBytes } from 'node:crypto';\n\nconst HEX_REGEX_32 = /^[0-9a-f]{32}$/;\nconst HEX_REGEX_16 = /^[0-9a-f]{16}$/;\n\nexport function generateTraceId(): string {\n return randomBytes(16).toString('hex');\n}\n\nexport function generateSpanId(): string {\n return randomBytes(8).toString('hex');\n}\n\nexport function generateAgentId(prefix?: string): string {\n const suffix = randomBytes(8).toString('hex');\n return prefix ? `${prefix}-${suffix}` : suffix;\n}\n\nexport function validateTraceId(id: string): boolean {\n return HEX_REGEX_32.test(id);\n}\n\nexport function validateSpanId(id: string): boolean {\n return HEX_REGEX_16.test(id);\n}\n","/**\n * No-op implementations for the disabled path.\n *\n * When tracing is disabled, all operations return these no-op objects\n * to maintain zero overhead. No allocations, no side effects.\n */\n\nimport { SpanKind, SpanStatus, type SpanPayload } from './types.js';\n\n/**\n * A frozen no-op span that silently ignores all operations.\n * Used when SDK is disabled to avoid overhead.\n */\nexport const NOOP_SPAN = Object.freeze({\n traceId: '00000000000000000000000000000000',\n spanId: '0000000000000000',\n parentSpanId: undefined,\n name: 'noop',\n kind: SpanKind.INTERNAL,\n startTime: '',\n startHrtime: 0,\n endTime: undefined,\n status: SpanStatus.UNSET,\n statusMessage: undefined,\n attributes: Object.freeze({}) as Record<string, unknown>,\n events: Object.freeze([]) as readonly [],\n links: Object.freeze([]) as readonly [],\n sessionId: undefined,\n agentId: undefined,\n agentName: undefined,\n semanticPhase: undefined,\n llmProvider: undefined,\n llmModel: undefined,\n llmPromptTokens: undefined,\n llmCompletionTokens: undefined,\n llmTotalTokens: undefined,\n llmCostUsd: undefined,\n toolName: undefined,\n toolSuccess: undefined,\n isEnded: true,\n durationMs: 0,\n\n setAttribute() { return this; },\n setAttributes() { return this; },\n setStatus() { return this; },\n addEvent() { return this; },\n addLink() { return this; },\n recordException() { return this; },\n setLlmFields() { return this; },\n setToolFields() { return this; },\n end() {},\n toPayload(): SpanPayload {\n return {\n traceId: this.traceId,\n spanId: this.spanId,\n name: this.name,\n kind: this.kind,\n startTime: this.startTime,\n status: this.status,\n attributes: {},\n events: [],\n links: [],\n };\n },\n});\n\nexport type NoopSpan = typeof NOOP_SPAN;\n","/**\n * Shared state via globalThis — ensures all entry point bundles share\n * the same singleton instances.\n *\n * Problem: tsup with `splitting: false` gives each entry point (index,\n * openai, anthropic, vercel-ai) its own copy of module-level variables.\n * This means `init()` from 'risicare' sets a tracer that 'risicare/openai'\n * can't see — breaking all provider instrumentation silently.\n *\n * Solution: Store all mutable singletons on globalThis with a namespaced\n * prefix. Every bundle reads/writes the same global slots.\n *\n * This pattern is used by React, OpenTelemetry, and other SDKs that must\n * share state across independently bundled entry points.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst G = globalThis as any;\nconst PREFIX = '__risicare_';\n\n// ─── Client & Tracer ────────────────────────────────────────────────────────\n\nexport function getClient(): unknown {\n return G[PREFIX + 'client'];\n}\n\nexport function setClient(client: unknown): void {\n G[PREFIX + 'client'] = client;\n}\n\nexport function getTracer(): unknown {\n return G[PREFIX + 'tracer'];\n}\n\nexport function setTracer(tracer: unknown): void {\n G[PREFIX + 'tracer'] = tracer;\n}\n\n// ─── Context Storage ────────────────────────────────────────────────────────\n\nexport function getContextStorage(): AsyncLocalStorage<unknown> {\n if (!G[PREFIX + 'ctx']) {\n G[PREFIX + 'ctx'] = new AsyncLocalStorage();\n }\n return G[PREFIX + 'ctx'];\n}\n\n// ─── Span Registry ──────────────────────────────────────────────────────────\n\nexport function getRegistry(): Map<string, unknown> {\n if (!G[PREFIX + 'registry']) {\n G[PREFIX + 'registry'] = new Map();\n }\n return G[PREFIX + 'registry'];\n}\n\nexport function getOpCount(): number {\n return G[PREFIX + 'opcount'] ?? 0;\n}\n\nexport function setOpCount(n: number): void {\n G[PREFIX + 'opcount'] = n;\n}\n\n// ─── Debug Flag ─────────────────────────────────────────────────────────────\n\nexport function getDebug(): boolean {\n return G[PREFIX + 'debug'] ?? false;\n}\n\nexport function setDebugFlag(enabled: boolean): void {\n G[PREFIX + 'debug'] = enabled;\n}\n","/**\n * AsyncLocalStorage-based context propagation.\n *\n * Uses a single AsyncLocalStorage instance with a composite state object.\n * This is simpler and more performant than multiple separate stores.\n *\n * Node.js AsyncLocalStorage automatically propagates through:\n * - Promise / async-await\n * - setTimeout / setImmediate\n * - EventEmitter callbacks\n * - process.nextTick\n * - async generators (unlike Python's contextvars!)\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { Span } from '../span.js';\nimport type { SemanticPhase } from '../types.js';\nimport { getContextStorage } from '../globals.js';\n\n// ─── Context Types ───────────────────────────────────────────────────────────\n\nexport interface SessionContext {\n sessionId: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n parentSessionId?: string;\n turnNumber?: number;\n}\n\nexport interface AgentContext {\n agentId: string;\n agentName?: string;\n agentRole?: string;\n agentType?: string;\n parentAgentId?: string;\n version?: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContextState {\n session?: SessionContext;\n agent?: AgentContext;\n span?: Span;\n phase?: SemanticPhase;\n /** When true, provider instrumentors skip span creation (framework is handling it). */\n _suppressProviderInstrumentation?: boolean;\n}\n\n// ─── Storage Accessor ────────────────────────────────────────────────────────\n\nfunction storage(): AsyncLocalStorage<ContextState> {\n return getContextStorage() as AsyncLocalStorage<ContextState>;\n}\n\n// ─── Core Operations ─────────────────────────────────────────────────────────\n\n/**\n * Get the current context state, or empty object if outside any context.\n */\nexport function getContext(): ContextState {\n return storage().getStore() ?? {};\n}\n\n/**\n * Run a callback within a new context scope.\n * The new scope inherits from the parent, with overrides applied.\n */\nexport function runWithContext<T>(overrides: Partial<ContextState>, fn: () => T): T {\n const parent = getContext();\n const merged: ContextState = { ...parent, ...overrides };\n return storage().run(merged, fn);\n}\n\n/**\n * Run an async callback within a new context scope.\n */\nexport function runWithContextAsync<T>(overrides: Partial<ContextState>, fn: () => Promise<T>): Promise<T> {\n const parent = getContext();\n const merged: ContextState = { ...parent, ...overrides };\n return storage().run(merged, fn);\n}\n\n// ─── Context Accessors ───────────────────────────────────────────────────────\n\nexport function getCurrentSession(): SessionContext | undefined {\n return getContext().session;\n}\n\nexport function getCurrentAgent(): AgentContext | undefined {\n return getContext().agent;\n}\n\nexport function getCurrentSpan(): Span | undefined {\n return getContext().span;\n}\n\nexport function getCurrentPhase(): SemanticPhase | undefined {\n return getContext().phase;\n}\n\nexport function getCurrentSessionId(): string | undefined {\n return getContext().session?.sessionId;\n}\n\nexport function getCurrentAgentId(): string | undefined {\n return getContext().agent?.agentId;\n}\n\nexport function getCurrentTraceId(): string | undefined {\n return getContext().span?.traceId;\n}\n\nexport function getCurrentSpanId(): string | undefined {\n return getContext().span?.spanId;\n}\n\nexport function getCurrentParentSpanId(): string | undefined {\n return getContext().span?.parentSpanId;\n}\n\n/**\n * Get all current context as a plain object (for debugging/serialization).\n */\nexport function getCurrentContext(): Record<string, unknown> {\n const ctx = getContext();\n return {\n session: ctx.session ? {\n sessionId: ctx.session.sessionId,\n userId: ctx.session.userId,\n ...(ctx.session.parentSessionId !== undefined ? { parentSessionId: ctx.session.parentSessionId } : {}),\n ...(ctx.session.turnNumber !== undefined ? { turnNumber: ctx.session.turnNumber } : {}),\n ...(ctx.session.metadata !== undefined ? { metadata: ctx.session.metadata } : {}),\n } : null,\n agent: ctx.agent ? {\n agentId: ctx.agent.agentId,\n agentName: ctx.agent.agentName,\n agentRole: ctx.agent.agentRole,\n agentType: ctx.agent.agentType,\n ...(ctx.agent.parentAgentId !== undefined ? { parentAgentId: ctx.agent.parentAgentId } : {}),\n ...(ctx.agent.version !== undefined ? { version: ctx.agent.version } : {}),\n ...(ctx.agent.metadata !== undefined ? { metadata: ctx.agent.metadata } : {}),\n } : null,\n span: ctx.span ? { spanId: ctx.span.spanId, traceId: ctx.span.traceId } : null,\n phase: ctx.phase ?? null,\n };\n}\n","/**\n * Internal logger for the Risicare SDK.\n *\n * Centralizes all diagnostic output so that:\n * - Debug messages are gated by a single flag (zero-cost when disabled)\n * - Warnings always fire (operational alerts like queue full)\n * - All output goes to stderr with a consistent [risicare] prefix\n * - A future custom logger callback can be added in one place\n */\n\nimport { getDebug, setDebugFlag } from '../globals.js';\n\n/**\n * Enable or disable debug logging. Called once during init().\n * @internal\n */\nexport function setDebug(enabled: boolean): void {\n setDebugFlag(enabled);\n}\n\n/**\n * Log a debug message. Only outputs when debug mode is enabled.\n * @internal\n */\nexport function debug(msg: string): void {\n if (getDebug()) {\n process.stderr.write(`[risicare] ${msg}\\n`);\n }\n}\n\n/**\n * Log a warning. Always outputs regardless of debug mode.\n * Use sparingly — only for operational issues the user should see.\n * @internal\n */\nexport function warn(msg: string): void {\n process.stderr.write(`[risicare] WARNING: ${msg}\\n`);\n}\n","/**\n * RisicareClient — singleton client managing SDK lifecycle.\n *\n * Handles initialization, shutdown, and the connection between\n * the Tracer and the export pipeline (batch processor + HTTP exporter).\n *\n * Usage:\n * import { init, shutdown } from 'risicare';\n * init({ apiKey: 'rsk-...' }); // API key determines project\n * // ... instrument code ...\n * await shutdown(); // flush remaining spans\n */\n\nimport { type RisicareConfig, resolveConfig } from './config.js';\nimport { Tracer } from './tracer.js';\nimport { BatchSpanProcessor } from './exporters/batch.js';\nimport { HttpExporter } from './exporters/http.js';\nimport { ConsoleExporter } from './exporters/console.js';\nimport { SpanKind, SpanStatus } from './types.js';\nimport type { SpanExporter } from './exporters/base.js';\nimport { setDebug, debug } from './utils/log.js';\nimport {\n getClient as getGlobalClient,\n setClient as setGlobalClient,\n getTracer as getGlobalTracer,\n setTracer as setGlobalTracer,\n} from './globals.js';\n\n// ─── Client Class ───────────────────────────────────────────────────────────\n\nclass RisicareClient {\n readonly config: ReturnType<typeof resolveConfig>;\n readonly processor: BatchSpanProcessor;\n readonly tracer: Tracer;\n private _shutdownPromise: Promise<void> | undefined;\n private _shutdownHandlers: { signal: string; handler: () => void }[] = [];\n\n constructor(config?: Partial<RisicareConfig>) {\n this.config = resolveConfig(config);\n\n // API key format validation\n if (this.config.apiKey && !this.config.apiKey.startsWith('rsk-')) {\n debug('Warning: API key should start with \"rsk-\". Got: ' + this.config.apiKey.slice(0, 4) + '...');\n }\n\n // Build exporter chain\n let exporter: SpanExporter;\n if (this.config.debug && !this.config.apiKey) {\n exporter = new ConsoleExporter();\n } else if (this.config.apiKey) {\n exporter = new HttpExporter({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n projectId: this.config.projectId || undefined,\n environment: this.config.environment || undefined,\n compress: this.config.compress,\n });\n } else {\n // No API key and not debug — use console as fallback\n exporter = new ConsoleExporter();\n }\n\n this.processor = new BatchSpanProcessor({\n exporters: [exporter],\n batchSize: this.config.batchSize,\n batchTimeoutMs: this.config.batchTimeoutMs,\n maxQueueSize: this.config.maxQueueSize,\n debug: this.config.debug,\n });\n\n this.tracer = new Tracer({\n onSpanEnd: (span) => this.processor.onSpanEnd(span),\n sampleRate: this.config.sampleRate,\n enabled: this.config.enabled,\n traceContent: this.config.traceContent,\n });\n\n // Start the batch processor (enables span queuing and periodic flushing)\n this.processor.start();\n\n // Register shutdown hooks\n this._registerShutdownHooks();\n\n // Enable internal debug logging if configured\n setDebug(this.config.debug);\n debug(`Initialized: enabled=${this.config.enabled}, endpoint=${this.config.endpoint}`);\n }\n\n get enabled(): boolean {\n return this.tracer.enabled;\n }\n\n set enabled(value: boolean) {\n this.tracer.enabled = value;\n }\n\n // Audit #6: Promise-based shutdown dedup (fixes TOCTOU race condition)\n async shutdown(): Promise<void> {\n if (this._shutdownPromise) return this._shutdownPromise;\n this._shutdownPromise = this._doShutdown();\n return this._shutdownPromise;\n }\n\n private async _doShutdown(): Promise<void> {\n debug('Shutting down...');\n\n // Audit #3: Remove process listeners to prevent leak\n for (const { signal, handler } of this._shutdownHandlers) {\n process.removeListener(signal, handler);\n }\n this._shutdownHandlers = [];\n\n await this.processor.shutdown();\n }\n\n async flush(): Promise<void> {\n await this.processor.flush();\n }\n\n private _registerShutdownHooks(): void {\n const onShutdown = () => {\n // Audit #3: Add 5s timeout to prevent hanging on signal\n const timeout = setTimeout(() => process.exit(1), 5000);\n timeout.unref();\n this.shutdown().catch(() => {}).finally(() => clearTimeout(timeout));\n };\n\n const signals = ['beforeExit', 'SIGTERM', 'SIGINT'];\n for (const signal of signals) {\n process.once(signal, onShutdown);\n this._shutdownHandlers.push({ signal, handler: onShutdown });\n }\n }\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Initialize the Risicare SDK. Call once at application startup.\n *\n * @example\n * import { init } from 'risicare';\n * init({ apiKey: 'rsk-...', serviceName: 'my-agent', environment: 'production' });\n */\nexport function init(config?: Partial<RisicareConfig>): void {\n if (getGlobalClient()) {\n debug('Already initialized. Call shutdown() first to re-initialize.');\n return;\n }\n\n const client = new RisicareClient(config);\n setGlobalClient(client);\n setGlobalTracer(client.tracer);\n}\n\n/**\n * Gracefully shut down the SDK. Flushes pending spans before resolving.\n */\nexport async function shutdown(): Promise<void> {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client) return;\n await client.shutdown();\n setGlobalClient(undefined);\n setGlobalTracer(undefined);\n}\n\n/**\n * Flush all pending spans without shutting down.\n */\nexport async function flush(): Promise<void> {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client) return;\n await client.flush();\n}\n\n/**\n * Enable tracing at runtime.\n */\nexport function enable(): void {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (client) client.enabled = true;\n}\n\n/**\n * Disable tracing at runtime. Spans will not be created or exported.\n */\nexport function disable(): void {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (client) client.enabled = false;\n}\n\n/**\n * Check whether tracing is currently enabled.\n */\nexport function isEnabled(): boolean {\n const client = getGlobalClient() as RisicareClient | undefined;\n return client?.enabled ?? false;\n}\n\n/**\n * Get the global tracer instance. Returns undefined if not initialized.\n */\nexport function getTracer(): Tracer | undefined {\n return getGlobalTracer() as Tracer | undefined;\n}\n\n/**\n * Get the global tracer, or throw if not initialized.\n * @internal Used by decorators and providers that require an active tracer.\n */\nexport function requireTracer(): Tracer {\n const tracer = getGlobalTracer() as Tracer | undefined;\n if (!tracer) {\n throw new Error(\n 'Risicare SDK not initialized. Call init() before using tracing features.',\n );\n }\n return tracer;\n}\n\n/**\n * Check whether content tracing (prompt/completion capture) is enabled.\n */\nexport function getTraceContent(): boolean {\n const tracer = getGlobalTracer() as Tracer | undefined;\n return tracer?.traceContent ?? true;\n}\n\n/**\n * Get SDK metrics: exported spans, dropped spans, failed exports, queue stats.\n * Returns zero-valued metrics if SDK is not initialized.\n */\nexport function getMetrics() {\n const client = getGlobalClient() as RisicareClient | undefined;\n return client?.processor.getMetrics() ?? {\n exportedSpans: 0,\n droppedSpans: 0,\n failedExports: 0,\n queueSize: 0,\n queueCapacity: 0,\n queueUtilization: 0,\n };\n}\n\n// ─── reportError ──────────────────────────────────────────────────────────\n\n/**\n * Report a caught exception to the self-healing pipeline.\n *\n * Creates an error span that triggers diagnosis and fix generation.\n * This function never throws and is non-blocking.\n *\n * @param error - The caught exception (Error object or string)\n * @param options - Optional attributes and context overrides\n */\nexport function reportError(\n error: unknown,\n options?: { name?: string; attributes?: Record<string, unknown> },\n): void {\n try {\n const tracer = getTracer();\n if (!tracer) return;\n\n const err = error instanceof Error ? error : new Error(String(error));\n const spanName = options?.name ?? `error:${err.constructor.name}`;\n\n tracer.startSpan({ name: spanName, kind: SpanKind.INTERNAL }, (span) => {\n span.setStatus(SpanStatus.ERROR, err.message);\n span.setAttribute('error', true);\n span.setAttribute('error.type', err.constructor.name);\n span.setAttribute('error.message', err.message.slice(0, 2000));\n if (err.stack) span.setAttribute('error.stack', err.stack.slice(0, 4000));\n span.setAttribute('risicare.reported_error', true);\n if (options?.attributes) {\n for (const [k, v] of Object.entries(options.attributes)) {\n span.setAttribute(k, v);\n }\n }\n });\n } catch {\n // Never crash the host application\n debug('reportError failed');\n }\n}\n\n// ─── score ─────────────────────────────────────────────────────────────────\n\n/**\n * Record a custom evaluation score on a trace.\n *\n * Sends the score to the server in a fire-and-forget fashion.\n * This function never throws and is non-blocking.\n *\n * @param traceId - The trace to score\n * @param name - Score name (e.g., \"accuracy\", \"user_satisfaction\")\n * @param value - Score value between 0.0 and 1.0 inclusive\n * @param options - Optional span_id and comment\n */\nexport function score(\n traceId: string,\n name: string,\n value: number,\n options?: { spanId?: string; comment?: string },\n): void {\n try {\n if (typeof value !== 'number' || value < 0.0 || value > 1.0) {\n debug(`score: value must be in [0.0, 1.0], got ${value}. Score not sent.`);\n return;\n }\n if (!traceId || !name) {\n debug('score: traceId and name are required');\n return;\n }\n\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client?.enabled || !client.config.apiKey) return;\n\n const endpoint = client.config.endpoint.replace(/\\/$/, '');\n const url = `${endpoint}/api/v1/scores`;\n const body = JSON.stringify({\n trace_id: traceId,\n name,\n score: value,\n source: 'sdk',\n ...(options?.spanId && { span_id: options.spanId }),\n ...(options?.comment && { comment: options.comment }),\n });\n\n // Fire-and-forget — never blocks caller\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${client.config.apiKey}`,\n },\n body,\n }).catch((err) => debug(`score: send failed: ${err}`));\n } catch {\n // Never crash the host application\n debug('score failed');\n }\n}\n","/**\n * Token cost calculation table.\n *\n * Prices are per 1M tokens. Update monthly.\n * Source: provider pricing pages.\n */\n\ninterface ModelPricing {\n input: number; // USD per 1M input tokens\n output: number; // USD per 1M output tokens\n}\n\nconst PRICING: Record<string, ModelPricing> = {\n // OpenAI\n 'gpt-4o': { input: 2.50, output: 10.00 },\n 'gpt-4o-mini': { input: 0.15, output: 0.60 },\n 'gpt-4-turbo': { input: 10.00, output: 30.00 },\n 'gpt-4': { input: 30.00, output: 60.00 },\n 'gpt-3.5-turbo': { input: 0.50, output: 1.50 },\n 'o1': { input: 15.00, output: 60.00 },\n 'o1-mini': { input: 3.00, output: 12.00 },\n 'o3-mini': { input: 1.10, output: 4.40 },\n\n // Anthropic\n 'claude-opus-4-5-20251101': { input: 15.00, output: 75.00 },\n 'claude-sonnet-4-5-20250929': { input: 3.00, output: 15.00 },\n 'claude-haiku-4-5-20251001': { input: 0.80, output: 4.00 },\n 'claude-3-5-sonnet-20241022': { input: 3.00, output: 15.00 },\n 'claude-3-haiku-20240307': { input: 0.25, output: 1.25 },\n 'claude-3-opus-20240229': { input: 15.00, output: 75.00 },\n\n // Google\n 'gemini-2.0-flash': { input: 0.10, output: 0.40 },\n 'gemini-1.5-pro': { input: 1.25, output: 5.00 },\n 'gemini-1.5-flash': { input: 0.075, output: 0.30 },\n\n // Groq\n 'llama-3.3-70b-versatile': { input: 0.59, output: 0.79 },\n 'llama-3.1-8b-instant': { input: 0.05, output: 0.08 },\n 'mixtral-8x7b-32768': { input: 0.24, output: 0.24 },\n\n // DeepSeek\n 'deepseek-chat': { input: 0.14, output: 0.28 },\n 'deepseek-reasoner': { input: 0.55, output: 2.19 },\n\n // Together.ai (open-source models)\n 'meta-llama/llama-3.3-70b-instruct-turbo': { input: 0.88, output: 0.88 },\n 'meta-llama/meta-llama-3.1-8b-instruct-turbo': { input: 0.18, output: 0.18 },\n 'meta-llama/llama-3.2-3b-instruct-turbo': { input: 0.06, output: 0.06 },\n 'qwen/qwen2.5-7b-instruct-turbo': { input: 0.20, output: 0.20 },\n 'mistralai/mistral-small-24b-instruct-2501': { input: 0.20, output: 0.20 },\n 'mistralai/mixtral-8x7b-instruct-v0.1': { input: 0.60, output: 0.60 },\n 'deepseek-ai/deepseek-v3': { input: 0.27, output: 1.10 },\n};\n\n/**\n * Calculate cost in USD for a model's token usage.\n * Returns undefined if model is not in pricing table.\n */\nexport function calculateCost(\n model: string,\n promptTokens: number,\n completionTokens: number,\n): number | undefined {\n const pricing = PRICING[model] ?? PRICING[model.toLowerCase()];\n if (!pricing) return undefined;\n\n const inputCost = (promptTokens / 1_000_000) * pricing.input;\n const outputCost = (completionTokens / 1_000_000) * pricing.output;\n return inputCost + outputCost;\n}\n\n/**\n * Check if a model has pricing data.\n */\nexport function hasPricing(model: string): boolean {\n return model in PRICING || model.toLowerCase() in PRICING;\n}\n","/**\n * Double-tracing prevention for framework integrations.\n *\n * When a framework integration (e.g., LlamaIndex handler) creates its own\n * LLM span, the underlying provider proxy (e.g., patchOpenAI) would also\n * create a duplicate span. This module provides suppression:\n *\n * - Framework integrations SET suppression via suppressProviderInstrumentation()\n * - Provider proxies CHECK via isProviderInstrumentationSuppressed() and skip\n *\n * Scoped to AsyncLocalStorage — concurrent calls are independent.\n */\n\nimport { getContext, runWithContext } from './storage.js';\n\n/**\n * Run a callback with provider instrumentation suppressed.\n *\n * During this callback, all provider instrumentors (patchOpenAI, etc.) will\n * skip span creation. The framework is responsible for creating the span.\n *\n * @param fn - The function to run with suppression active\n * @returns The function's return value\n */\nexport function suppressProviderInstrumentation<T>(fn: () => T): T {\n return runWithContext({ _suppressProviderInstrumentation: true }, fn);\n}\n\n/**\n * Check if provider instrumentation should be suppressed.\n *\n * Called by provider instrumentors as an early-exit guard. When true,\n * the provider calls the original method directly without creating a span.\n */\nexport function isProviderInstrumentationSuppressed(): boolean {\n return getContext()._suppressProviderInstrumentation === true;\n}\n","/**\n * OpenAI SDK Proxy-based instrumentation.\n *\n * Wraps an OpenAI client instance using ES Proxy to intercept:\n * - chat.completions.create (sync + streaming)\n * - embeddings.create\n *\n * The original client is NOT modified — Proxy creates a transparent wrapper\n * that intercepts method calls and creates tracing spans.\n *\n * Usage:\n * import OpenAI from 'openai';\n * import { patchOpenAI } from 'risicare/openai';\n * const openai = patchOpenAI(new OpenAI({ apiKey: '...' }));\n */\n\nimport { requireTracer } from '../../client.js';\nimport { SpanKind } from '../../types.js';\nimport { calculateCost } from '../../utils/pricing.js';\nimport { debug } from '../../utils/log.js';\nimport { isProviderInstrumentationSuppressed } from '../../context/dedup.js';\nimport type { Span } from '../../span.js';\n\n// Known OpenAI-compatible hosts for provider detection.\n// Matches Python SDK's _OPENAI_COMPATIBLE_HOSTS (20 provider identities total).\nconst COMPATIBLE_HOSTS: Record<string, string> = {\n 'api.deepseek.com': 'deepseek',\n 'api.together.xyz': 'together',\n 'api.groq.com': 'groq',\n 'api.x.ai': 'xai',\n 'api.fireworks.ai': 'fireworks',\n 'inference.baseten.co': 'baseten',\n 'api.novita.ai': 'novita',\n 'api.byteplus.com': 'byteplus',\n};\n\nfunction detectProvider(client: unknown): string {\n try {\n const baseURL = (client as Record<string, unknown>).baseURL;\n if (!baseURL || typeof baseURL !== 'string') return 'openai';\n const host = baseURL.split('//').pop()?.split('/')[0]?.split(':')[0]?.toLowerCase();\n return (host && COMPATIBLE_HOSTS[host]) ?? 'openai';\n } catch {\n return 'openai';\n }\n}\n\nfunction enrichSpanFromResponse(span: Span, response: Record<string, unknown>, provider: string): void {\n const model = response.model as string | undefined;\n const usage = response.usage as Record<string, number> | undefined;\n\n if (model) {\n span.setLlmFields({ provider, model });\n }\n\n if (usage) {\n const promptTokens = usage.prompt_tokens ?? 0;\n const completionTokens = usage.completion_tokens ?? 0;\n const totalTokens = usage.total_tokens ?? (promptTokens + completionTokens);\n const cost = model ? calculateCost(model, promptTokens, completionTokens) : undefined;\n\n span.setLlmFields({\n promptTokens,\n completionTokens,\n totalTokens: totalTokens,\n costUsd: cost,\n });\n }\n}\n\nfunction createChatCompletionProxy(originalCreate: Function, provider: string): Function {\n return function patchedCreate(this: unknown, ...args: unknown[]) {\n if (isProviderInstrumentationSuppressed()) {\n return originalCreate.apply(this, args);\n }\n\n let tracer;\n try {\n tracer = requireTracer();\n } catch {\n debug('Tracer not initialized — call init() before using patchOpenAI()');\n return originalCreate.apply(this, args);\n }\n\n const params = (args[0] ?? {}) as Record<string, unknown>;\n const model = (params.model as string) ?? 'unknown';\n const isStream = !!params.stream;\n\n return tracer.startSpan(\n { name: `openai.chat.completions.create`, kind: SpanKind.LLM_CALL, attributes: { 'llm.request.model': model, 'llm.stream': isStream } },\n (span) => {\n span.setLlmFields({ provider, model });\n\n const result = originalCreate.apply(this, args);\n\n if (result && typeof result === 'object' && typeof (result as Promise<unknown>).then === 'function') {\n // Don't auto-end span here — the tracer.startSpan handles it\n // but we need to enrich before it ends. Return a Promise that\n // enriches then resolves.\n return (result as Promise<Record<string, unknown>>).then((response) => {\n if (!isStream && response) {\n enrichSpanFromResponse(span, response, provider);\n }\n return response;\n });\n }\n\n return result;\n },\n );\n };\n}\n\nfunction createEmbeddingsProxy(originalCreate: Function, provider: string): Function {\n return function patchedCreate(this: unknown, ...args: unknown[]) {\n if (isProviderInstrumentationSuppressed()) {\n return originalCreate.apply(this, args);\n }\n\n let tracer;\n try {\n tracer = requireTracer();\n } catch {\n debug('Tracer not initialized — call init() before using patchOpenAI()');\n return originalCreate.apply(this, args);\n }\n\n const params = (args[0] ?? {}) as Record<string, unknown>;\n const model = (params.model as string) ?? 'unknown';\n\n return tracer.startSpan(\n { name: `openai.embeddings.create`, kind: SpanKind.LLM_CALL, attributes: { 'llm.request.model': model } },\n (span) => {\n span.setLlmFields({ provider, model });\n\n const result = originalCreate.apply(this, args);\n\n if (result && typeof result === 'object' && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<Record<string, unknown>>).then((response) => {\n if (response) {\n enrichSpanFromResponse(span, response, provider);\n }\n return response;\n });\n }\n\n return result;\n },\n );\n };\n}\n\n/**\n * Wrap an OpenAI client instance with tracing instrumentation.\n *\n * Returns a Proxy that intercepts chat.completions.create and embeddings.create.\n * The original client is NOT modified.\n *\n * @param client - An OpenAI client instance\n * @returns A proxied client with automatic tracing\n */\nexport function patchOpenAI<T extends object>(client: T): T {\n const provider = detectProvider(client);\n\n // Proxy the top-level client\n return new Proxy(client, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n // Intercept `.chat` access to proxy `.chat.completions`\n if (prop === 'chat' && value && typeof value === 'object') {\n return new Proxy(value as object, {\n get(chatTarget, chatProp, chatReceiver) {\n const chatValue = Reflect.get(chatTarget, chatProp, chatReceiver);\n\n if (chatProp === 'completions' && chatValue && typeof chatValue === 'object') {\n return new Proxy(chatValue as object, {\n get(compTarget, compProp, compReceiver) {\n const compValue = Reflect.get(compTarget, compProp, compReceiver);\n\n if (compProp === 'create' && typeof compValue === 'function') {\n return createChatCompletionProxy(compValue.bind(compTarget), provider);\n }\n\n return compValue;\n },\n });\n }\n\n return chatValue;\n },\n });\n }\n\n // Intercept `.embeddings` access\n if (prop === 'embeddings' && value && typeof value === 'object') {\n return new Proxy(value as object, {\n get(embTarget, embProp, embReceiver) {\n const embValue = Reflect.get(embTarget, embProp, embReceiver);\n\n if (embProp === 'create' && typeof embValue === 'function') {\n return createEmbeddingsProxy(embValue.bind(embTarget), provider);\n }\n\n return embValue;\n },\n });\n }\n\n return value;\n },\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/globals.ts","../../../src/utils/log.ts","../../../src/runtime/config.ts","../../../src/runtime/cache.ts","../../../src/runtime/applier.ts","../../../src/runtime/loader.ts","../../../src/runtime/interceptors.ts","../../../src/runtime/runtime.ts","../../../src/ids.ts","../../../src/noop.ts","../../../src/context/storage.ts","../../../src/exporters/batch.ts","../../../src/exporters/http.ts","../../../src/client.ts","../../../src/utils/pricing.ts","../../../src/providers/openai/patch.ts","../../../src/context/dedup.ts"],"sourcesContent":["/**\n * Shared state via globalThis — ensures all entry point bundles share\n * the same singleton instances.\n *\n * Problem: tsup with `splitting: false` gives each entry point (index,\n * openai, anthropic, vercel-ai) its own copy of module-level variables.\n * This means `init()` from 'risicare' sets a tracer that 'risicare/openai'\n * can't see — breaking all provider instrumentation silently.\n *\n * Solution: Store all mutable singletons on globalThis with a namespaced\n * prefix. Every bundle reads/writes the same global slots.\n *\n * This pattern is used by React, OpenTelemetry, and other SDKs that must\n * share state across independently bundled entry points.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst G = globalThis as any;\nconst PREFIX = '__risicare_';\n\n// ─── Client & Tracer ────────────────────────────────────────────────────────\n\nexport function getClient(): unknown {\n return G[PREFIX + 'client'];\n}\n\nexport function setClient(client: unknown): void {\n G[PREFIX + 'client'] = client;\n}\n\nexport function getTracer(): unknown {\n return G[PREFIX + 'tracer'];\n}\n\nexport function setTracer(tracer: unknown): void {\n G[PREFIX + 'tracer'] = tracer;\n}\n\n// ─── Context Storage ────────────────────────────────────────────────────────\n\nexport function getContextStorage(): AsyncLocalStorage<unknown> {\n if (!G[PREFIX + 'ctx']) {\n G[PREFIX + 'ctx'] = new AsyncLocalStorage();\n }\n return G[PREFIX + 'ctx'];\n}\n\n// ─── Span Registry ──────────────────────────────────────────────────────────\n\nexport function getRegistry(): Map<string, unknown> {\n if (!G[PREFIX + 'registry']) {\n G[PREFIX + 'registry'] = new Map();\n }\n return G[PREFIX + 'registry'];\n}\n\nexport function getOpCount(): number {\n return G[PREFIX + 'opcount'] ?? 0;\n}\n\nexport function setOpCount(n: number): void {\n G[PREFIX + 'opcount'] = n;\n}\n\n// ─── Debug Flag ─────────────────────────────────────────────────────────────\n\nexport function getDebug(): boolean {\n return G[PREFIX + 'debug'] ?? false;\n}\n\nexport function setDebugFlag(enabled: boolean): void {\n G[PREFIX + 'debug'] = enabled;\n}\n\n// ─── Fix Runtime ────────────────────────────────────────────────────────\n\nexport function getGlobalFixRuntime(): unknown {\n return G[PREFIX + 'fix_runtime'];\n}\n\nexport function setGlobalFixRuntime(runtime: unknown): void {\n G[PREFIX + 'fix_runtime'] = runtime;\n}\n","/**\n * Internal logger for the Risicare SDK.\n *\n * Centralizes all diagnostic output so that:\n * - Debug messages are gated by a single flag (zero-cost when disabled)\n * - Warnings always fire (operational alerts like queue full)\n * - All output goes to stderr with a consistent [risicare] prefix\n * - A future custom logger callback can be added in one place\n */\n\nimport { getDebug, setDebugFlag } from '../globals.js';\n\n/**\n * Enable or disable debug logging. Called once during init().\n * @internal\n */\nexport function setDebug(enabled: boolean): void {\n setDebugFlag(enabled);\n}\n\n/**\n * Log a debug message. Only outputs when debug mode is enabled.\n * @internal\n */\nexport function debug(msg: string): void {\n if (getDebug()) {\n process.stderr.write(`[risicare] ${msg}\\n`);\n }\n}\n\n/**\n * Log a warning. Always outputs regardless of debug mode.\n * Use sparingly — only for operational issues the user should see.\n * @internal\n */\nexport function warn(msg: string): void {\n process.stderr.write(`[risicare] WARNING: ${msg}\\n`);\n}\n","/**\n * Fix Runtime Configuration.\n *\n * Settings for the fix runtime including caching, refresh intervals,\n * A/B testing, and fix application behavior.\n *\n * Port of Python SDK's runtime/config.py adapted for Node.js patterns.\n */\n\n// ─── Runtime Configuration ──────────────────────────────────────────────────\n\nexport interface FixRuntimeConfig {\n /** API endpoint URL (e.g., \"https://app.risicare.ai\") */\n apiEndpoint: string;\n\n /** API key for authentication (format: \"rsk-{random}\") */\n apiKey: string;\n\n /** Whether the fix runtime is enabled (default: true) */\n enabled?: boolean;\n\n /** Whether caching is enabled (default: true) */\n cacheEnabled?: boolean;\n\n /** Cache entry TTL in milliseconds (default: 300_000 = 5 min) */\n cacheTtlMs?: number;\n\n /** Maximum number of cache entries (default: 1000) */\n cacheMaxEntries?: number;\n\n /** Whether to auto-refresh fixes in background (default: true) */\n autoRefresh?: boolean;\n\n /** Background refresh interval in milliseconds (default: 60_000 = 1 min) */\n refreshIntervalMs?: number;\n\n /** Log but don't apply fixes (default: false) */\n dryRun?: boolean;\n\n /** Whether A/B testing bucketing is active (default: true) */\n abTestingEnabled?: boolean;\n\n /** Timeout for API requests in milliseconds (default: 1000) */\n timeoutMs?: number;\n\n /** Enable debug logging (default: false) */\n debug?: boolean;\n}\n\n/** Resolve config with defaults applied. */\nexport function resolveFixRuntimeConfig(\n config: FixRuntimeConfig,\n): Required<FixRuntimeConfig> {\n return {\n apiEndpoint: config.apiEndpoint,\n apiKey: config.apiKey,\n enabled: config.enabled ?? true,\n cacheEnabled: config.cacheEnabled ?? true,\n cacheTtlMs: config.cacheTtlMs ?? 300_000,\n cacheMaxEntries: config.cacheMaxEntries ?? 1000,\n autoRefresh: config.autoRefresh ?? true,\n refreshIntervalMs: config.refreshIntervalMs ?? 60_000,\n dryRun: config.dryRun ?? false,\n abTestingEnabled: config.abTestingEnabled ?? true,\n timeoutMs: config.timeoutMs ?? 1000,\n debug: config.debug ?? false,\n };\n}\n\n// ─── Fix Type ───────────────────────────────────────────────────────────────\n\nexport type FixType =\n | 'prompt'\n | 'parameter'\n | 'retry'\n | 'fallback'\n | 'guard'\n | 'routing'\n | 'tool';\n\n// ─── Active Fix ─────────────────────────────────────────────────────────────\n\nexport interface ActiveFix {\n fixId: string;\n deploymentId?: string;\n errorCode: string;\n fixType: FixType;\n config: Record<string, unknown>;\n trafficPercentage: number; // 0–100\n version: number;\n}\n\n/**\n * Check if a fix matches the given error code.\n *\n * Supports exact match and wildcard prefix matching:\n * - \"TOOL.EXECUTION.TIMEOUT\" matches \"TOOL.EXECUTION.TIMEOUT\"\n * - \"TOOL.EXECUTION.*\" matches \"TOOL.EXECUTION.TIMEOUT\", \"TOOL.EXECUTION.FAILURE\", etc.\n * - \"TOOL.*\" matches any TOOL error\n */\nexport function matchesError(fix: ActiveFix, errorCode: string): boolean {\n if (fix.errorCode === errorCode) {\n return true;\n }\n\n // Wildcard matching\n if (fix.errorCode.endsWith('*')) {\n const prefix = fix.errorCode.slice(0, -1);\n return errorCode.startsWith(prefix);\n }\n\n return false;\n}\n\n/**\n * Determine if fix should be applied based on A/B traffic percentage.\n *\n * Uses consistent hashing so the same session always gets the same\n * treatment (fix or no fix).\n */\nexport function shouldApply(fix: ActiveFix, sessionHash: number): boolean {\n if (fix.trafficPercentage >= 100) return true;\n if (fix.trafficPercentage <= 0) return false;\n\n const bucket = sessionHash % 100;\n return bucket < fix.trafficPercentage;\n}\n\n/**\n * Create an ActiveFix from an API response item.\n *\n * Handles both snake_case (server API) and camelCase field names.\n */\nexport function activeFixFromApiResponse(\n item: Record<string, unknown>,\n): ActiveFix {\n return {\n fixId: (item.id ?? item.fix_id ?? item.fixId ?? '') as string,\n deploymentId: (item.deployment_id ?? item.deploymentId ?? '') as string,\n errorCode: (item.error_code ?? item.errorCode ?? '') as string,\n fixType: (item.fix_type ?? item.fixType ?? 'prompt') as FixType,\n config: (item.config ?? {}) as Record<string, unknown>,\n trafficPercentage: (item.traffic_percentage ?? item.trafficPercentage ?? 100) as number,\n version: (item.version ?? 1) as number,\n };\n}\n","/**\n * Fix Cache — Local cache for active fixes with TTL eviction.\n *\n * Provides fast lookup of fixes keyed by error code with exact match\n * and wildcard fallback. No locks needed — JS is single-threaded.\n *\n * Port of Python SDK's runtime/cache.py.\n */\n\nimport type { ActiveFix, FixRuntimeConfig } from './config.js';\nimport { matchesError } from './config.js';\nimport { debug } from '../utils/log.js';\n\n// ─── Cache Entry ────────────────────────────────────────────────────────────\n\ninterface CacheEntry {\n fix: ActiveFix;\n createdAt: number;\n expiresAt: number;\n}\n\n// ─── Cache Stats ────────────────────────────────────────────────────────────\n\nexport interface CacheStats {\n hits: number;\n misses: number;\n evictions: number;\n size: number;\n lastRefresh: number | null;\n}\n\n// ─── Fix Cache ──────────────────────────────────────────────────────────────\n\nexport class FixCache {\n private readonly _ttlMs: number;\n private readonly _maxEntries: number;\n private readonly _enabled: boolean;\n private _cache: Map<string, CacheEntry>;\n private _stats: CacheStats;\n\n constructor(config?: Pick<FixRuntimeConfig, 'cacheEnabled' | 'cacheTtlMs' | 'cacheMaxEntries'>) {\n this._enabled = config?.cacheEnabled ?? true;\n this._ttlMs = config?.cacheTtlMs ?? 300_000;\n this._maxEntries = config?.cacheMaxEntries ?? 1000;\n this._cache = new Map();\n this._stats = {\n hits: 0,\n misses: 0,\n evictions: 0,\n size: 0,\n lastRefresh: null,\n };\n }\n\n /** Whether caching is enabled. */\n get enabled(): boolean {\n return this._enabled;\n }\n\n /**\n * Get a fix by error code.\n *\n * Checks exact match first, then scans for wildcard matches.\n * Expired entries are evicted on access.\n */\n get(errorCode: string): ActiveFix | null {\n try {\n if (!this._enabled) return null;\n\n const now = Date.now();\n\n // Try exact match first (fast path)\n const exactEntry = this._cache.get(errorCode);\n if (exactEntry) {\n if (exactEntry.expiresAt > now) {\n this._stats.hits++;\n return exactEntry.fix;\n }\n // Expired — evict\n this._cache.delete(errorCode);\n this._stats.evictions++;\n }\n\n // Wildcard scan (slower path)\n for (const [key, entry] of this._cache) {\n if (entry.expiresAt <= now) {\n this._cache.delete(key);\n this._stats.evictions++;\n continue;\n }\n\n if (matchesError(entry.fix, errorCode)) {\n this._stats.hits++;\n return entry.fix;\n }\n }\n\n this._stats.misses++;\n return null;\n } catch (e) {\n debug(`FixCache.get error: ${e}`);\n return null;\n }\n }\n\n /**\n * Add a single fix to the cache.\n *\n * Evicts the oldest entry if at capacity.\n */\n set(fix: ActiveFix): void {\n try {\n if (!this._enabled) return;\n\n // Evict oldest if at capacity\n if (this._cache.size >= this._maxEntries) {\n this._evictOldest();\n }\n\n const now = Date.now();\n this._cache.set(fix.errorCode, {\n fix,\n createdAt: now,\n expiresAt: now + this._ttlMs,\n });\n this._stats.size = this._cache.size;\n } catch (e) {\n debug(`FixCache.set error: ${e}`);\n }\n }\n\n /**\n * Replace all cached fixes (bulk refresh).\n *\n * Clears the cache and populates with the given fixes.\n */\n setAll(fixes: ActiveFix[]): void {\n try {\n if (!this._enabled) return;\n\n this._cache.clear();\n const now = Date.now();\n\n for (const fix of fixes) {\n if (this._cache.size >= this._maxEntries) break;\n\n this._cache.set(fix.errorCode, {\n fix,\n createdAt: now,\n expiresAt: now + this._ttlMs,\n });\n }\n\n this._stats.size = this._cache.size;\n this._stats.lastRefresh = now;\n } catch (e) {\n debug(`FixCache.setAll error: ${e}`);\n }\n }\n\n /**\n * Get all non-expired fixes.\n */\n getAll(): ActiveFix[] {\n try {\n const now = Date.now();\n const valid: ActiveFix[] = [];\n const expired: string[] = [];\n\n for (const [key, entry] of this._cache) {\n if (entry.expiresAt > now) {\n valid.push(entry.fix);\n } else {\n expired.push(key);\n }\n }\n\n // Clean up expired entries\n for (const key of expired) {\n this._cache.delete(key);\n this._stats.evictions++;\n }\n\n this._stats.size = this._cache.size;\n return valid;\n } catch (e) {\n debug(`FixCache.getAll error: ${e}`);\n return [];\n }\n }\n\n /** Clear all cache entries. Returns the number of entries cleared. */\n clear(): number {\n const count = this._cache.size;\n this._cache.clear();\n this._stats.size = 0;\n return count;\n }\n\n /** Get cache statistics. */\n get stats(): CacheStats {\n this._stats.size = this._cache.size;\n return { ...this._stats };\n }\n\n /** Evict the oldest cache entry. */\n private _evictOldest(): void {\n if (this._cache.size === 0) return;\n\n let oldestKey: string | null = null;\n let oldestTime = Infinity;\n\n for (const [key, entry] of this._cache) {\n if (entry.createdAt < oldestTime) {\n oldestTime = entry.createdAt;\n oldestKey = key;\n }\n }\n\n if (oldestKey !== null) {\n this._cache.delete(oldestKey);\n this._stats.evictions++;\n }\n }\n}\n","/**\n * Fix Applier — Applies fixes to agent operations.\n *\n * Handles different fix types:\n * - PromptFix: Modify system/user prompts (prepend, append, replace, few_shot)\n * - ParameterFix: Adjust LLM parameters (temperature, model, etc.)\n * - RetryFix: Retry with exponential backoff + jitter\n * - FallbackFix: Switch to fallback model or default response\n * - GuardFix: Input/output validation (content filter, format check, length)\n *\n * Port of Python SDK's runtime/applier.py adapted for Node.js.\n */\n\nimport { createHash } from 'node:crypto';\nimport type { ActiveFix, FixRuntimeConfig } from './config.js';\nimport { shouldApply, resolveFixRuntimeConfig } from './config.js';\nimport type { FixCache } from './cache.js';\nimport { debug, warn } from '../utils/log.js';\n\n/**\n * Maximum length for fix content injected into prompts.\n * Prevents unbounded prompt injection from malicious/corrupted fix configs.\n */\nconst MAX_FIX_CONTENT_LENGTH = 10_000;\n\n// ─── Apply Result ───────────────────────────────────────────────────────────\n\nexport interface ApplyResult {\n applied: boolean;\n fixId?: string;\n deploymentId?: string;\n fixType?: string;\n modifications: Record<string, unknown>;\n error?: string;\n}\n\nfunction emptyResult(fix: ActiveFix, fixType: string): ApplyResult {\n return {\n applied: false,\n fixId: fix.fixId,\n deploymentId: fix.deploymentId,\n fixType,\n modifications: {},\n };\n}\n\n// ─── Fix Applier ────────────────────────────────────────────────────────────\n\nexport class FixApplier {\n private readonly _config: Required<FixRuntimeConfig>;\n private readonly _cache: FixCache;\n private _applicationLog: ApplyResult[] = [];\n\n constructor(config: FixRuntimeConfig, cache: FixCache) {\n this._config = resolveFixRuntimeConfig(config);\n this._cache = cache;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // Fix Lookup\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Get applicable fix for an error code.\n *\n * Considers A/B testing bucket if sessionId is provided. Uses\n * crypto.createHash('md5') for deterministic bucketing across restarts.\n */\n getFixForError(\n errorCode: string,\n sessionId?: string,\n ): ActiveFix | null {\n try {\n const fix = this._cache.get(errorCode);\n if (!fix) return null;\n\n // Check A/B test bucketing\n if (sessionId && this._config.abTestingEnabled) {\n const hashHex = createHash('md5')\n .update(sessionId)\n .digest('hex')\n .substring(0, 8);\n const sessionHash = parseInt(hashHex, 16);\n\n if (!shouldApply(fix, sessionHash)) {\n debug(`Fix ${fix.fixId} not applied (A/B control group)`);\n return null;\n }\n }\n\n return fix;\n } catch (e) {\n debug(`getFixForError error: ${e}`);\n return null;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // 1. Prompt Fix\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Apply a prompt fix to messages.\n *\n * Supports 4 modification types:\n * - prepend: Add content before first system message\n * - append: Add content after first system message\n * - replace: Regex replace across all messages\n * - few_shot: Insert user/assistant example pairs after system message\n */\n applyPromptFix(\n fix: ActiveFix,\n messages: Record<string, unknown>[],\n ): { messages: Record<string, unknown>[]; result: ApplyResult } {\n try {\n const cfg = fix.config;\n const modificationType = (cfg.modification_type ?? cfg.modificationType ?? 'append') as string;\n const target = (cfg.target ?? 'system') as string;\n let content = (cfg.content ?? '') as string;\n\n // Truncate oversized content to prevent prompt injection\n if (content.length > MAX_FIX_CONTENT_LENGTH) {\n warn(\n `Fix ${fix.fixId} content truncated from ${content.length} to ${MAX_FIX_CONTENT_LENGTH} chars`,\n );\n content = content.slice(0, MAX_FIX_CONTENT_LENGTH);\n }\n\n const result = emptyResult(fix, 'prompt');\n\n if (this._config.dryRun) {\n result.modifications = {\n type: modificationType,\n target,\n contentPreview: content.slice(0, 100),\n };\n return { messages, result };\n }\n\n let modified = messages.map((m) => ({ ...m }));\n\n if (modificationType === 'prepend') {\n modified = this._prependToTarget(modified, target, content);\n result.applied = true;\n result.modifications = { type: 'prepend', target };\n } else if (modificationType === 'append') {\n modified = this._appendToTarget(modified, target, content);\n result.applied = true;\n result.modifications = { type: 'append', target };\n } else if (modificationType === 'replace') {\n const pattern = (cfg.pattern ?? '') as string;\n if (pattern) {\n modified = this._replaceInMessages(modified, pattern, content);\n result.applied = true;\n result.modifications = { type: 'replace', pattern };\n }\n } else if (modificationType === 'few_shot') {\n const examples = (cfg.examples ?? []) as Array<Record<string, string>>;\n if (examples.length > 0) {\n modified = this._addFewShotExamples(modified, examples);\n result.applied = true;\n result.modifications = { type: 'few_shot', count: examples.length };\n }\n }\n\n return { messages: modified, result };\n } catch (e) {\n debug(`applyPromptFix error: ${e}`);\n return {\n messages,\n result: {\n applied: false,\n fixId: fix.fixId,\n fixType: 'prompt',\n modifications: {},\n error: String(e),\n },\n };\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // 2. Parameter Fix\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Apply a parameter fix — merge config.parameters into params.\n */\n applyParameterFix(\n fix: ActiveFix,\n params: Record<string, unknown>,\n ): { params: Record<string, unknown>; result: ApplyResult } {\n try {\n const newParams = (fix.config.parameters ?? {}) as Record<string, unknown>;\n const result = emptyResult(fix, 'parameter');\n\n if (this._config.dryRun) {\n result.modifications = { parameters: newParams };\n return { params, result };\n }\n\n const modified = { ...params, ...newParams };\n result.applied = true;\n result.modifications = { parameters: newParams };\n\n return { params: modified, result };\n } catch (e) {\n debug(`applyParameterFix error: ${e}`);\n return {\n params,\n result: {\n applied: false,\n fixId: fix.fixId,\n fixType: 'parameter',\n modifications: {},\n error: String(e),\n },\n };\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // 3. Retry Fix (async — uses setTimeout for sleeping)\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Apply a retry fix to an async operation.\n *\n * Retries with exponential backoff + jitter using\n * `await new Promise(r => setTimeout(r, delay))`.\n */\n async applyRetryFix<T>(\n fix: ActiveFix,\n operation: () => Promise<T>,\n ): Promise<{ value: T; result: ApplyResult }> {\n const cfg = fix.config;\n const maxRetries = (cfg.max_retries ?? cfg.maxRetries ?? 3) as number;\n const initialDelayMs = (cfg.initial_delay_ms ?? cfg.initialDelayMs ?? 1000) as number;\n const maxDelayMs = (cfg.max_delay_ms ?? cfg.maxDelayMs ?? 30_000) as number;\n const exponentialBase = (cfg.exponential_base ?? cfg.exponentialBase ?? 2.0) as number;\n const jitter = (cfg.jitter ?? true) as boolean;\n const retryOn = (cfg.retry_on ?? cfg.retryOn ?? []) as string[];\n\n const result = emptyResult(fix, 'retry');\n\n if (this._config.dryRun) {\n result.modifications = { maxRetries, initialDelayMs };\n const value = await operation();\n return { value, result };\n }\n\n let lastError: Error | null = null;\n let attempts = 0;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n attempts++;\n try {\n const value = await operation();\n result.applied = true;\n result.modifications = { attempts };\n return { value, result };\n } catch (e) {\n lastError = e instanceof Error ? e : new Error(String(e));\n const errorType = lastError.constructor.name;\n\n // Check if we should retry this specific error type\n if (retryOn.length > 0 && !retryOn.includes(errorType)) {\n throw lastError;\n }\n\n if (attempt < maxRetries) {\n // Calculate delay with exponential backoff\n let delayMs = Math.min(\n initialDelayMs * Math.pow(exponentialBase, attempt),\n maxDelayMs,\n );\n\n // Add jitter: multiply by random factor [0.5, 1.5)\n if (jitter) {\n delayMs *= 0.5 + Math.random();\n }\n\n debug(\n `Retry ${attempt + 1}/${maxRetries} after ${Math.round(delayMs)}ms`,\n );\n await new Promise<void>((r) => setTimeout(r, delayMs));\n }\n }\n }\n\n // All retries exhausted\n result.applied = true;\n result.error = lastError?.message;\n result.modifications = { attempts, exhausted: true };\n throw lastError;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // 4. Fallback Fix\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Apply a fallback fix.\n *\n * - 'model': Replace params.model with the fallback model\n * - 'default': Set params._fallbackResponse for the caller to use\n */\n applyFallbackFix(\n fix: ActiveFix,\n params: Record<string, unknown>,\n ): { params: Record<string, unknown>; result: ApplyResult } {\n try {\n const cfg = fix.config;\n const fallbackType = (cfg.fallback_type ?? cfg.fallbackType ?? 'model') as string;\n const fallbackConfig = (cfg.fallback_config ?? cfg.fallbackConfig ?? {}) as Record<string, unknown>;\n const result = emptyResult(fix, 'fallback');\n\n if (this._config.dryRun) {\n result.modifications = { fallbackType, fallbackConfig };\n return { params, result };\n }\n\n const modified = { ...params };\n\n if (fallbackType === 'model') {\n const fallbackModel = fallbackConfig.model as string | undefined;\n if (fallbackModel) {\n modified.model = fallbackModel;\n result.applied = true;\n result.modifications = { model: fallbackModel };\n }\n } else if (fallbackType === 'default') {\n const defaultResponse = fallbackConfig.response;\n if (defaultResponse !== undefined) {\n modified._fallbackResponse = defaultResponse;\n result.applied = true;\n result.modifications = { defaultResponse: true };\n }\n }\n\n return { params: modified, result };\n } catch (e) {\n debug(`applyFallbackFix error: ${e}`);\n return {\n params,\n result: {\n applied: false,\n fixId: fix.fixId,\n fixType: 'fallback',\n modifications: {},\n error: String(e),\n },\n };\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // 5. Guard Fix\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Apply a guard fix (validation).\n *\n * Guard types:\n * - content_filter: Regex-based blocked patterns\n * - format_check: JSON.parse() validity\n * - input_validation / output_validation: min/max length\n */\n applyGuardFix(\n fix: ActiveFix,\n content: string,\n isInput = true,\n ): { content: string; passed: boolean; result: ApplyResult } {\n try {\n const cfg = fix.config;\n const guardType = (cfg.guard_type ?? cfg.guardType ?? 'output_validation') as string;\n const guardConfig = (cfg.guard_config ?? cfg.guardConfig ?? {}) as Record<string, unknown>;\n const result = emptyResult(fix, 'guard');\n\n // Check if guard applies to this direction\n if (isInput && guardType !== 'input_validation' && guardType !== 'content_filter') {\n return { content, passed: true, result };\n }\n if (!isInput && guardType !== 'output_validation' && guardType !== 'format_check') {\n return { content, passed: true, result };\n }\n\n if (this._config.dryRun) {\n result.modifications = { guardType };\n return { content, passed: true, result };\n }\n\n let passed = true;\n\n if (guardType === 'content_filter') {\n const blockedPatterns = (guardConfig.blocked_patterns ?? guardConfig.blockedPatterns ?? []) as string[];\n for (const pattern of blockedPatterns) {\n const regex = this._safeCompileRegex(pattern);\n if (regex && regex.test(content)) {\n passed = false;\n break;\n }\n }\n } else if (guardType === 'format_check') {\n const requiredFormat = guardConfig.format as string | undefined;\n if (requiredFormat === 'json') {\n try {\n JSON.parse(content);\n } catch {\n passed = false;\n }\n }\n } else if (guardType === 'input_validation' || guardType === 'output_validation') {\n const minLength = (guardConfig.min_length ?? guardConfig.minLength ?? 0) as number;\n const maxLength = (guardConfig.max_length ?? guardConfig.maxLength ?? Infinity) as number;\n if (content.length < minLength || content.length > maxLength) {\n passed = false;\n }\n }\n\n result.applied = true;\n result.modifications = { passed, guardType };\n\n return { content, passed, result };\n } catch (e) {\n debug(`applyGuardFix error: ${e}`);\n return {\n content,\n passed: true,\n result: {\n applied: false,\n fixId: fix.fixId,\n fixType: 'guard',\n modifications: {},\n error: String(e),\n },\n };\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // Application Log\n // ═══════════════════════════════════════════════════════════════════════════\n\n /** Log a fix application result. */\n logApplication(result: ApplyResult): void {\n this._applicationLog.push(result);\n\n // Limit log size\n if (this._applicationLog.length > 1000) {\n this._applicationLog = this._applicationLog.slice(-500);\n }\n }\n\n /** Get the application log. */\n getApplicationLog(): ApplyResult[] {\n return [...this._applicationLog];\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // Private Helpers\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Safely compile a regex pattern from untrusted input.\n * Returns null if invalid or too long.\n */\n private _safeCompileRegex(\n pattern: string,\n maxLength = 500,\n ): RegExp | null {\n if (!pattern || pattern.length > maxLength) return null;\n try {\n return new RegExp(pattern, 'i');\n } catch {\n debug(`Invalid regex pattern (length=${pattern.length})`);\n return null;\n }\n }\n\n /** Prepend content to the first message matching the target role. */\n private _prependToTarget(\n messages: Record<string, unknown>[],\n target: string,\n content: string,\n ): Record<string, unknown>[] {\n return messages.map((msg) => {\n if (msg.role === target) {\n return {\n ...msg,\n content: content + '\\n\\n' + ((msg.content as string) ?? ''),\n };\n }\n return msg;\n });\n }\n\n /** Append content to the first message matching the target role. */\n private _appendToTarget(\n messages: Record<string, unknown>[],\n target: string,\n content: string,\n ): Record<string, unknown>[] {\n return messages.map((msg) => {\n if (msg.role === target) {\n return {\n ...msg,\n content: ((msg.content as string) ?? '') + '\\n\\n' + content,\n };\n }\n return msg;\n });\n }\n\n /** Regex replace across all messages. */\n private _replaceInMessages(\n messages: Record<string, unknown>[],\n pattern: string,\n replacement: string,\n ): Record<string, unknown>[] {\n const regex = this._safeCompileRegex(pattern);\n if (!regex) {\n debug('Skipping invalid regex pattern in prompt fix');\n return messages;\n }\n\n return messages.map((msg) => {\n const msgContent = msg.content;\n if (typeof msgContent === 'string') {\n return { ...msg, content: msgContent.replace(regex, replacement) };\n }\n return msg;\n });\n }\n\n /** Add few-shot examples after the first system message. */\n private _addFewShotExamples(\n messages: Record<string, unknown>[],\n examples: Array<Record<string, string>>,\n ): Record<string, unknown>[] {\n const result: Record<string, unknown>[] = [];\n let systemFound = false;\n\n for (const msg of messages) {\n result.push(msg);\n\n if (msg.role === 'system' && !systemFound) {\n systemFound = true;\n for (const example of examples) {\n if (example.user) {\n result.push({ role: 'user', content: example.user });\n }\n if (example.assistant) {\n result.push({ role: 'assistant', content: example.assistant });\n }\n }\n }\n }\n\n return result;\n }\n}\n","/**\n * Fix Loader — Fetches active fixes from the Risicare API.\n *\n * Handles:\n * - Initial loading of fixes on startup\n * - Periodic background refresh via setInterval (unref'd)\n * - Exponential backoff on failure\n * - Circuit breaker: after 3 consecutive failures, stop trying for 30s\n *\n * Uses native fetch (Node.js 18+) with AbortController for timeouts.\n *\n * Port of Python SDK's runtime/loader.py adapted for Node.js.\n */\n\nimport type { ActiveFix } from './config.js';\nimport { activeFixFromApiResponse } from './config.js';\nimport type { FixRuntimeConfig } from './config.js';\nimport { resolveFixRuntimeConfig } from './config.js';\nimport type { FixCache } from './cache.js';\nimport { debug, warn } from '../utils/log.js';\n\nconst SDK_VERSION = '0.1.3';\n\nexport class FixLoader {\n private readonly _config: Required<FixRuntimeConfig>;\n private readonly _cache: FixCache;\n\n private _refreshTimer: ReturnType<typeof setInterval> | null = null;\n private _lastLoadTime: number | null = null;\n private _consecutiveFailures = 0;\n private _circuitOpenUntil = 0;\n private _onLoadCallbacks: Array<(fixes: ActiveFix[]) => void> = [];\n\n // Circuit breaker settings\n private static readonly CIRCUIT_BREAKER_THRESHOLD = 3;\n private static readonly CIRCUIT_BREAKER_COOLDOWN_MS = 30_000;\n\n constructor(config: FixRuntimeConfig, cache: FixCache) {\n this._config = resolveFixRuntimeConfig(config);\n this._cache = cache;\n }\n\n /** Timestamp of last successful load. */\n get lastLoadTime(): number | null {\n return this._lastLoadTime;\n }\n\n /**\n * Start the loader: perform initial load and start background refresh.\n *\n * Never throws — failures are logged and the runtime degrades gracefully.\n */\n start(): void {\n try {\n if (!this._config.enabled) {\n debug('Fix runtime disabled, skipping loader start');\n return;\n }\n\n if (!this._config.apiKey) {\n warn('No API key configured, fixes will not be loaded');\n return;\n }\n\n // Initial load (fire-and-forget — don't block startup)\n this.loadSync().catch((e) => {\n debug(`Initial fix load failed: ${e}`);\n });\n\n // Start background refresh\n if (this._config.autoRefresh) {\n this._startRefreshInterval();\n }\n } catch (e) {\n debug(`FixLoader.start error: ${e}`);\n }\n }\n\n /** Stop the loader: clear the refresh interval. */\n stop(): void {\n try {\n if (this._refreshTimer !== null) {\n clearInterval(this._refreshTimer);\n this._refreshTimer = null;\n }\n } catch (e) {\n debug(`FixLoader.stop error: ${e}`);\n }\n }\n\n /**\n * Register a callback invoked after each successful load.\n */\n onLoad(callback: (fixes: ActiveFix[]) => void): void {\n this._onLoadCallbacks.push(callback);\n }\n\n /**\n * Load fixes from the API.\n *\n * Name kept as \"loadSync\" for parity with the Python SDK, but this\n * returns a Promise in JS (there's no synchronous fetch in Node.js).\n */\n async loadSync(): Promise<ActiveFix[]> {\n if (!this._config.apiKey) {\n return [];\n }\n\n // Circuit breaker: skip if circuit is open\n const now = Date.now();\n if (\n this._consecutiveFailures >= FixLoader.CIRCUIT_BREAKER_THRESHOLD &&\n now < this._circuitOpenUntil\n ) {\n debug('Fix loader circuit breaker open — skipping load');\n return this._cache.getAll();\n }\n\n try {\n // Build URL: /api/v1/ routes to FastAPI via Caddy (NOT /v1/ which is the Rust gateway)\n const endpoint = this._config.apiEndpoint.replace(/\\/+$/, '');\n const url = `${endpoint}/api/v1/fixes/active`;\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this._config.timeoutMs,\n );\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${this._config.apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Risicare-SDK-Version': SDK_VERSION,\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const fixes = this._parseResponse(data);\n this._onLoadSuccess(fixes);\n return fixes;\n } catch (e) {\n this._onLoadFailure(e as Error);\n throw e;\n }\n }\n\n /** Get currently cached fixes without hitting the API. */\n getCached(): ActiveFix[] {\n return this._cache.getAll();\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n private _parseResponse(data: Record<string, unknown>): ActiveFix[] {\n const fixes: ActiveFix[] = [];\n const items =\n (data.fixes as unknown[]) ??\n (data.data as unknown[]) ??\n [];\n\n if (!Array.isArray(items)) return fixes;\n\n for (const item of items) {\n try {\n if (item && typeof item === 'object') {\n fixes.push(activeFixFromApiResponse(item as Record<string, unknown>));\n }\n } catch (e) {\n debug(`Failed to parse fix item: ${e}`);\n }\n }\n\n return fixes;\n }\n\n private _onLoadSuccess(fixes: ActiveFix[]): void {\n this._lastLoadTime = Date.now();\n this._consecutiveFailures = 0;\n\n // Update cache\n this._cache.setAll(fixes);\n\n // Notify callbacks\n for (const callback of this._onLoadCallbacks) {\n try {\n callback(fixes);\n } catch (e) {\n debug(`Load callback error: ${e}`);\n }\n }\n\n debug(`Loaded ${fixes.length} active fixes`);\n }\n\n private _onLoadFailure(error: Error): void {\n this._consecutiveFailures++;\n\n if (this._consecutiveFailures >= FixLoader.CIRCUIT_BREAKER_THRESHOLD) {\n this._circuitOpenUntil = Date.now() + FixLoader.CIRCUIT_BREAKER_COOLDOWN_MS;\n warn(\n `Fix loader circuit breaker opened after ${this._consecutiveFailures} failures. ` +\n `Cooldown: ${FixLoader.CIRCUIT_BREAKER_COOLDOWN_MS / 1000}s`,\n );\n } else {\n debug(\n `Fix load failed (attempt ${this._consecutiveFailures}): ${error.message}`,\n );\n }\n }\n\n private _startRefreshInterval(): void {\n // Use exponential backoff on the refresh interval after failures\n const tick = (): void => {\n this.loadSync().catch((e) => {\n debug(`Background fix refresh failed: ${e}`);\n });\n };\n\n this._refreshTimer = setInterval(\n () => {\n // Skip if circuit breaker is open (loadSync handles this,\n // but we also avoid the async overhead)\n if (\n this._consecutiveFailures >= FixLoader.CIRCUIT_BREAKER_THRESHOLD &&\n Date.now() < this._circuitOpenUntil\n ) {\n return;\n }\n tick();\n },\n this._config.refreshIntervalMs,\n );\n\n // unref() so the interval doesn't prevent Node.js process exit\n this._refreshTimer.unref();\n\n debug('Started fix refresh interval');\n }\n}\n","/**\n * Fix Interceptors — Hook into LLM/tool calls to apply fixes.\n *\n * Interceptors are registered with the runtime and called during agent\n * execution to apply relevant fixes at three interception points:\n * - preCall: Before the LLM/tool call (prompt/parameter/fallback fixes)\n * - postCall: After the call (output guard validation)\n * - onError: When an error occurs (retry/fallback decisions)\n *\n * Port of Python SDK's runtime/interceptors.py adapted for Node.js.\n */\n\nimport type { ApplyResult } from './applier.js';\nimport { FixApplier } from './applier.js';\nimport type { FixCache } from './cache.js';\nimport type { FixRuntimeConfig } from './config.js';\nimport { resolveFixRuntimeConfig } from './config.js';\nimport { debug, warn } from '../utils/log.js';\n\n// ─── Intercept Context ──────────────────────────────────────────────────────\n\nexport interface InterceptContext {\n /** Type of operation: \"llm_call\", \"tool_call\", \"agent_delegate\" */\n operationType: string;\n\n /** Name of the operation: model name, tool name, agent name */\n operationName: string;\n\n /** Session ID for A/B testing bucketing */\n sessionId?: string;\n\n /** Trace ID for correlation */\n traceId?: string;\n\n /** Error code (set when retrying after error) */\n errorCode?: string;\n\n /** Error message (set when retrying after error) */\n errorMessage?: string;\n\n /** Current attempt number (1-based) */\n attempt: number;\n\n /** Fixes applied during this intercept lifecycle */\n appliedFixes: ApplyResult[];\n}\n\n/** Create a fresh InterceptContext. */\nexport function createInterceptContext(\n operationType: string,\n operationName: string,\n options?: {\n sessionId?: string;\n traceId?: string;\n errorCode?: string;\n },\n): InterceptContext {\n return {\n operationType,\n operationName,\n sessionId: options?.sessionId,\n traceId: options?.traceId,\n errorCode: options?.errorCode,\n attempt: 1,\n appliedFixes: [],\n };\n}\n\n// ─── Interceptor Interface ──────────────────────────────────────────────────\n\nexport interface FixInterceptor {\n /**\n * Called before an LLM/tool call.\n * Returns modified messages and params.\n */\n preCall(\n ctx: InterceptContext,\n messages: unknown[] | null,\n params: Record<string, unknown>,\n ): { messages: unknown[] | null; params: Record<string, unknown> };\n\n /**\n * Called after an LLM/tool call.\n * Returns modified response and whether to continue.\n */\n postCall(\n ctx: InterceptContext,\n response: unknown,\n ): { response: unknown; shouldContinue: boolean };\n\n /**\n * Called when an error occurs.\n * Returns whether to retry and optional modified params.\n */\n onError(\n ctx: InterceptContext,\n error: Error,\n ): { shouldRetry: boolean; modifiedParams: Record<string, unknown> | null };\n}\n\n// ─── Default Fix Interceptor ────────────────────────────────────────────────\n\nexport class DefaultFixInterceptor implements FixInterceptor {\n private readonly _config: Required<FixRuntimeConfig>;\n private readonly _cache: FixCache;\n private readonly _applier: FixApplier;\n\n constructor(config: FixRuntimeConfig, cache: FixCache, applier: FixApplier) {\n this._config = resolveFixRuntimeConfig(config);\n this._cache = cache;\n this._applier = applier;\n }\n\n /**\n * Apply pre-call fixes.\n *\n * - If retrying after error: look up fix by error_code, apply\n * prompt/parameter/fallback fixes\n * - Runs input guard fixes on all message content\n */\n preCall(\n ctx: InterceptContext,\n messages: unknown[] | null,\n params: Record<string, unknown>,\n ): { messages: unknown[] | null; params: Record<string, unknown> } {\n try {\n if (!this._config.enabled) {\n return { messages, params };\n }\n\n let modifiedMessages = messages;\n let modifiedParams = { ...params };\n\n // If retrying after error, check for applicable fixes\n if (ctx.errorCode) {\n const fix = this._applier.getFixForError(ctx.errorCode, ctx.sessionId);\n\n if (fix) {\n debug(`Applying fix ${fix.fixId} for ${ctx.errorCode}`);\n\n if (fix.fixType === 'prompt' && messages) {\n const msgRecords = messages as Record<string, unknown>[];\n const { messages: newMessages, result } =\n this._applier.applyPromptFix(fix, msgRecords);\n modifiedMessages = newMessages;\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n } else if (fix.fixType === 'parameter') {\n const { params: newParams, result } =\n this._applier.applyParameterFix(fix, modifiedParams);\n modifiedParams = newParams;\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n } else if (fix.fixType === 'fallback') {\n const { params: newParams, result } =\n this._applier.applyFallbackFix(fix, modifiedParams);\n modifiedParams = newParams;\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n }\n }\n }\n\n // Apply input guard fixes on all message content\n if (modifiedMessages && this._config.enabled) {\n for (const msg of modifiedMessages as Record<string, unknown>[]) {\n const content = msg.content;\n if (typeof content === 'string') {\n for (const fix of this._cache.getAll()) {\n if (fix.fixType === 'guard') {\n const { result } = this._applier.applyGuardFix(\n fix,\n content,\n true,\n );\n if (result.applied) {\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n }\n }\n }\n }\n }\n }\n\n return { messages: modifiedMessages, params: modifiedParams };\n } catch (e) {\n debug(`DefaultFixInterceptor.preCall error: ${e}`);\n return { messages, params };\n }\n }\n\n /**\n * Apply post-call fixes (output validation).\n *\n * Runs output guard fixes on response content.\n */\n postCall(\n ctx: InterceptContext,\n response: unknown,\n ): { response: unknown; shouldContinue: boolean } {\n try {\n if (!this._config.enabled) {\n return { response, shouldContinue: true };\n }\n\n for (const fix of this._cache.getAll()) {\n if (fix.fixType !== 'guard') continue;\n\n const content = this._extractResponseContent(response);\n if (!content) continue;\n\n const { passed, result } = this._applier.applyGuardFix(\n fix,\n content,\n false,\n );\n\n if (result.applied) {\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n }\n\n if (!passed) {\n warn(`Output guard failed for fix ${fix.fixId}`);\n }\n }\n\n return { response, shouldContinue: true };\n } catch (e) {\n debug(`DefaultFixInterceptor.postCall error: ${e}`);\n return { response, shouldContinue: true };\n }\n }\n\n /**\n * Handle errors and decide whether to retry.\n *\n * Classifies the error, looks up retry/fallback fixes, and returns\n * whether the caller should retry.\n */\n onError(\n ctx: InterceptContext,\n error: Error,\n ): { shouldRetry: boolean; modifiedParams: Record<string, unknown> | null } {\n try {\n if (!this._config.enabled) {\n return { shouldRetry: false, modifiedParams: null };\n }\n\n // Classify the error\n const errorCode = classifyError(error);\n ctx.errorCode = errorCode;\n ctx.errorMessage = error.message;\n\n // Check for retry fix\n const fix = this._applier.getFixForError(errorCode, ctx.sessionId);\n if (!fix) {\n return { shouldRetry: false, modifiedParams: null };\n }\n\n if (fix.fixType === 'retry') {\n const maxRetries = (fix.config.max_retries ?? fix.config.maxRetries ?? 3) as number;\n\n if (ctx.attempt <= maxRetries) {\n debug(\n `Retry fix ${fix.fixId}: attempt ${ctx.attempt}/${maxRetries}`,\n );\n\n const result: ApplyResult = {\n applied: true,\n fixId: fix.fixId,\n deploymentId: fix.deploymentId,\n fixType: 'retry',\n modifications: { attempt: ctx.attempt },\n };\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n\n return { shouldRetry: true, modifiedParams: null };\n }\n }\n\n // Check for fallback fix\n if (fix.fixType === 'fallback') {\n const { params: modifiedParams, result } =\n this._applier.applyFallbackFix(fix, {});\n if (result.applied) {\n ctx.appliedFixes.push(result);\n this._applier.logApplication(result);\n return { shouldRetry: true, modifiedParams };\n }\n }\n\n return { shouldRetry: false, modifiedParams: null };\n } catch (e) {\n debug(`DefaultFixInterceptor.onError error: ${e}`);\n return { shouldRetry: false, modifiedParams: null };\n }\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n /** Extract text content from a response object. */\n private _extractResponseContent(response: unknown): string | null {\n if (typeof response === 'string') return response;\n\n if (response && typeof response === 'object') {\n const resp = response as Record<string, unknown>;\n\n // OpenAI-style response: { choices: [{ message: { content: \"...\" } }] }\n const choices = resp.choices as unknown[];\n if (Array.isArray(choices) && choices.length > 0) {\n const first = choices[0] as Record<string, unknown>;\n const message = first?.message as Record<string, unknown>;\n if (typeof message?.content === 'string') {\n return message.content;\n }\n }\n\n // Anthropic-style response: { content: [{ text: \"...\" }] }\n const content = resp.content;\n if (typeof content === 'string') return content;\n if (Array.isArray(content) && content.length > 0) {\n const first = content[0] as Record<string, unknown>;\n if (typeof first?.text === 'string') return first.text;\n }\n }\n\n return null;\n }\n}\n\n// ─── Error Classification ───────────────────────────────────────────────────\n\n/**\n * Classify an error into an error code.\n *\n * Simple heuristic classification. In production, this would use the full\n * taxonomy from risicare-core (10 modules, 35+ categories).\n */\nexport function classifyError(error: Error): string {\n const errorType = error.constructor.name.toLowerCase();\n const errorMsg = error.message.toLowerCase();\n\n // Timeout errors\n if (errorType.includes('timeout') || errorMsg.includes('timeout') || errorMsg.includes('aborted')) {\n return 'TOOL.EXECUTION.TIMEOUT';\n }\n\n // Rate limit errors\n if (errorMsg.includes('rate') && errorMsg.includes('limit')) {\n return 'TOOL.EXECUTION.RATE_LIMIT';\n }\n if (errorMsg.includes('429') || errorMsg.includes('too many requests')) {\n return 'TOOL.EXECUTION.RATE_LIMIT';\n }\n\n // Connection errors\n if (\n errorType.includes('connection') ||\n errorMsg.includes('connection') ||\n errorMsg.includes('econnrefused') ||\n errorMsg.includes('econnreset') ||\n errorMsg.includes('fetch failed')\n ) {\n return 'TOOL.EXECUTION.CONNECTION_ERROR';\n }\n\n // Authentication errors\n if (\n errorMsg.includes('auth') ||\n errorMsg.includes('401') ||\n errorMsg.includes('403') ||\n errorMsg.includes('unauthorized') ||\n errorMsg.includes('forbidden')\n ) {\n return 'TOOL.EXECUTION.AUTH_ERROR';\n }\n\n // JSON parsing errors\n if (\n errorType.includes('syntaxerror') ||\n errorType.includes('json') ||\n errorMsg.includes('json') ||\n errorMsg.includes('unexpected token')\n ) {\n return 'OUTPUT.FORMAT.JSON_INVALID';\n }\n\n // Generic execution error\n return 'TOOL.EXECUTION.FAILURE';\n}\n","/**\n * Fix Runtime — Main orchestrator for the fix application system.\n *\n * Manages:\n * - Loading active fixes from the API (via FixLoader)\n * - Caching fixes locally (via FixCache)\n * - Applying fixes via interceptors (via DefaultFixInterceptor)\n * - Tracking fix effectiveness\n *\n * Singleton management via globalThis (same pattern as the tracer).\n *\n * Port of Python SDK's runtime/runtime.py adapted for Node.js.\n */\n\nimport { FixCache } from './cache.js';\nimport type { ActiveFix, FixRuntimeConfig } from './config.js';\nimport { resolveFixRuntimeConfig } from './config.js';\nimport { FixApplier } from './applier.js';\nimport { FixLoader } from './loader.js';\nimport {\n DefaultFixInterceptor,\n createInterceptContext,\n type FixInterceptor,\n type InterceptContext,\n} from './interceptors.js';\nimport { debug, warn } from '../utils/log.js';\n\n// ─── globalThis singleton key ───────────────────────────────────────────────\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst G = globalThis as any;\nconst RUNTIME_KEY = '__risicare_fix_runtime';\n\n// ─── Fix Runtime ────────────────────────────────────────────────────────────\n\nexport class FixRuntime {\n private readonly _config: Required<FixRuntimeConfig>;\n private readonly _cache: FixCache;\n private readonly _loader: FixLoader;\n private readonly _applier: FixApplier;\n private readonly _interceptor: DefaultFixInterceptor;\n private _started = false;\n\n // Effectiveness tracking\n private _fixApplications = new Map<string, number>();\n private _fixSuccesses = new Map<string, number>();\n\n constructor(config: FixRuntimeConfig) {\n this._config = resolveFixRuntimeConfig(config);\n this._cache = new FixCache(this._config);\n this._loader = new FixLoader(config, this._cache);\n this._applier = new FixApplier(config, this._cache);\n this._interceptor = new DefaultFixInterceptor(\n config,\n this._cache,\n this._applier,\n );\n }\n\n // ─── Accessors ──────────────────────────────────────────────────────────\n\n /** Runtime configuration (with defaults resolved). */\n get config(): Required<FixRuntimeConfig> {\n return this._config;\n }\n\n /** Whether the runtime is enabled and started. */\n get isEnabled(): boolean {\n return this._config.enabled && this._started;\n }\n\n /** The fix cache. */\n get cache(): FixCache {\n return this._cache;\n }\n\n /** The fix loader. */\n get loader(): FixLoader {\n return this._loader;\n }\n\n /** The fix applier. */\n get applier(): FixApplier {\n return this._applier;\n }\n\n /** The interceptor. */\n get interceptor(): FixInterceptor {\n return this._interceptor;\n }\n\n // ─── Lifecycle ──────────────────────────────────────────────────────────\n\n /**\n * Start the runtime.\n *\n * Triggers initial fix load and starts background refresh.\n * Never throws — failures degrade gracefully.\n */\n start(): void {\n try {\n if (this._started) return;\n\n if (!this._config.enabled) {\n debug('Fix runtime disabled');\n return;\n }\n\n debug('Starting fix runtime...');\n this._loader.start();\n this._started = true;\n debug('Fix runtime started');\n } catch (e) {\n warn(`Fix runtime start failed: ${e}`);\n }\n }\n\n /**\n * Stop the runtime.\n *\n * Stops background refresh and clears the cache.\n * Never throws.\n */\n stop(): void {\n try {\n if (!this._started) return;\n\n debug('Stopping fix runtime...');\n this._loader.stop();\n this._cache.clear();\n this._started = false;\n debug('Fix runtime stopped');\n } catch (e) {\n debug(`Fix runtime stop error: ${e}`);\n }\n }\n\n // ─── Intercept API ──────────────────────────────────────────────────────\n\n /**\n * Intercept a call: create context and run preCall fixes.\n *\n * Returns modified messages/params and the InterceptContext for\n * use in subsequent interceptResponse / interceptError calls.\n */\n interceptCall(\n operationType: string,\n operationName: string,\n messages: unknown[] | null,\n params: Record<string, unknown>,\n options?: {\n sessionId?: string;\n traceId?: string;\n errorCode?: string;\n },\n ): {\n messages: unknown[] | null;\n params: Record<string, unknown>;\n ctx: InterceptContext;\n } {\n const ctx = createInterceptContext(operationType, operationName, options);\n\n try {\n if (!this.isEnabled) {\n return { messages, params, ctx };\n }\n\n const result = this._interceptor.preCall(ctx, messages, params);\n return { messages: result.messages, params: result.params, ctx };\n } catch (e) {\n debug(`interceptCall error: ${e}`);\n return { messages, params, ctx };\n }\n }\n\n /**\n * Intercept a response: run postCall fixes (output validation).\n */\n interceptResponse(\n ctx: InterceptContext,\n response: unknown,\n ): { response: unknown; shouldContinue: boolean } {\n try {\n if (!this.isEnabled) {\n return { response, shouldContinue: true };\n }\n\n const result = this._interceptor.postCall(ctx, response);\n\n // Track success for effectiveness\n this._trackSuccess(ctx);\n\n return result;\n } catch (e) {\n debug(`interceptResponse error: ${e}`);\n return { response, shouldContinue: true };\n }\n }\n\n /**\n * Intercept an error: decide on retry/fallback.\n */\n interceptError(\n ctx: InterceptContext,\n error: Error,\n ): { shouldRetry: boolean; modifiedParams: Record<string, unknown> | null } {\n try {\n if (!this.isEnabled) {\n return { shouldRetry: false, modifiedParams: null };\n }\n\n ctx.attempt++;\n const result = this._interceptor.onError(ctx, error);\n\n // If not retrying, track failure for effectiveness\n if (!result.shouldRetry) {\n this._trackFailure(ctx);\n }\n\n return result;\n } catch (e) {\n debug(`interceptError error: ${e}`);\n return { shouldRetry: false, modifiedParams: null };\n }\n }\n\n // ─── Direct Fix Access ──────────────────────────────────────────────────\n\n /**\n * Get applicable fix for an error code.\n */\n getFix(errorCode: string, sessionId?: string): ActiveFix | null {\n try {\n if (!this.isEnabled) return null;\n return this._applier.getFixForError(errorCode, sessionId);\n } catch (e) {\n debug(`getFix error: ${e}`);\n return null;\n }\n }\n\n /**\n * Manually refresh fixes from the API.\n */\n async refreshFixes(): Promise<ActiveFix[]> {\n try {\n return await this._loader.loadSync();\n } catch (e) {\n debug(`refreshFixes error: ${e}`);\n return [];\n }\n }\n\n // ─── Effectiveness ──────────────────────────────────────────────────────\n\n /** Get effectiveness statistics for all fixes. */\n getEffectivenessStats(): Record<\n string,\n { applications: number; successes: number; successRate: number }\n > {\n const stats: Record<\n string,\n { applications: number; successes: number; successRate: number }\n > = {};\n\n for (const [fixId, applications] of this._fixApplications) {\n const successes = this._fixSuccesses.get(fixId) ?? 0;\n stats[fixId] = {\n applications,\n successes,\n successRate: applications > 0 ? successes / applications : 0,\n };\n }\n\n return stats;\n }\n\n // ─── Private ────────────────────────────────────────────────────────────\n\n private _trackSuccess(ctx: InterceptContext): void {\n for (const result of ctx.appliedFixes) {\n if (result.applied && result.fixId) {\n this._fixApplications.set(\n result.fixId,\n (this._fixApplications.get(result.fixId) ?? 0) + 1,\n );\n this._fixSuccesses.set(\n result.fixId,\n (this._fixSuccesses.get(result.fixId) ?? 0) + 1,\n );\n }\n }\n }\n\n private _trackFailure(ctx: InterceptContext): void {\n for (const result of ctx.appliedFixes) {\n if (result.applied && result.fixId) {\n this._fixApplications.set(\n result.fixId,\n (this._fixApplications.get(result.fixId) ?? 0) + 1,\n );\n // Don't increment success count\n }\n }\n }\n}\n\n// ─── Singleton Management ───────────────────────────────────────────────────\n\n/** Get the global FixRuntime instance, if initialized. */\nexport function getFixRuntime(): FixRuntime | undefined {\n return G[RUNTIME_KEY] as FixRuntime | undefined;\n}\n\n/** Set the global FixRuntime instance (for advanced use). */\nexport function setFixRuntime(runtime: FixRuntime): void {\n G[RUNTIME_KEY] = runtime;\n}\n\n/**\n * Initialize and start the global FixRuntime.\n *\n * If already initialized, returns the existing instance.\n * Never throws — initialization failures degrade gracefully.\n */\nexport function initFixRuntime(config: FixRuntimeConfig): FixRuntime {\n try {\n const existing = G[RUNTIME_KEY] as FixRuntime | undefined;\n if (existing) {\n debug('Fix runtime already initialized');\n return existing;\n }\n\n const runtime = new FixRuntime(config);\n runtime.start();\n G[RUNTIME_KEY] = runtime;\n return runtime;\n } catch (e) {\n warn(`initFixRuntime failed: ${e}`);\n // Return a disabled runtime so callers don't need null checks\n const fallback = new FixRuntime({ ...config, enabled: false });\n G[RUNTIME_KEY] = fallback;\n return fallback;\n }\n}\n\n/**\n * Shutdown and remove the global FixRuntime.\n *\n * Never throws.\n */\nexport function shutdownFixRuntime(): void {\n try {\n const runtime = G[RUNTIME_KEY] as FixRuntime | undefined;\n if (runtime) {\n runtime.stop();\n }\n G[RUNTIME_KEY] = undefined;\n } catch (e) {\n debug(`shutdownFixRuntime error: ${e}`);\n G[RUNTIME_KEY] = undefined;\n }\n}\n","/**\n * ID generation for traces and spans.\n *\n * Trace IDs: 32 lowercase hex characters (16 random bytes)\n * Span IDs: 16 lowercase hex characters (8 random bytes)\n *\n * Uses crypto.randomBytes for cryptographically secure randomness.\n */\n\nimport { randomBytes } from 'node:crypto';\n\nconst HEX_REGEX_32 = /^[0-9a-f]{32}$/;\nconst HEX_REGEX_16 = /^[0-9a-f]{16}$/;\n\nexport function generateTraceId(): string {\n return randomBytes(16).toString('hex');\n}\n\nexport function generateSpanId(): string {\n return randomBytes(8).toString('hex');\n}\n\nexport function generateAgentId(prefix?: string): string {\n const suffix = randomBytes(8).toString('hex');\n return prefix ? `${prefix}-${suffix}` : suffix;\n}\n\nexport function validateTraceId(id: string): boolean {\n return HEX_REGEX_32.test(id);\n}\n\nexport function validateSpanId(id: string): boolean {\n return HEX_REGEX_16.test(id);\n}\n","/**\n * No-op implementations for the disabled path.\n *\n * When tracing is disabled, all operations return these no-op objects\n * to maintain zero overhead. No allocations, no side effects.\n */\n\nimport { SpanKind, SpanStatus, type SpanPayload } from './types.js';\n\n/**\n * A frozen no-op span that silently ignores all operations.\n * Used when SDK is disabled to avoid overhead.\n */\nexport const NOOP_SPAN = Object.freeze({\n traceId: '00000000000000000000000000000000',\n spanId: '0000000000000000',\n parentSpanId: undefined,\n name: 'noop',\n kind: SpanKind.INTERNAL,\n startTime: '',\n startHrtime: 0,\n endTime: undefined,\n status: SpanStatus.UNSET,\n statusMessage: undefined,\n attributes: Object.freeze({}) as Record<string, unknown>,\n events: Object.freeze([]) as readonly [],\n links: Object.freeze([]) as readonly [],\n sessionId: undefined,\n agentId: undefined,\n agentName: undefined,\n semanticPhase: undefined,\n llmProvider: undefined,\n llmModel: undefined,\n llmPromptTokens: undefined,\n llmCompletionTokens: undefined,\n llmTotalTokens: undefined,\n llmCostUsd: undefined,\n toolName: undefined,\n toolSuccess: undefined,\n isEnded: true,\n durationMs: 0,\n\n setAttribute() { return this; },\n setAttributes() { return this; },\n setStatus() { return this; },\n addEvent() { return this; },\n addLink() { return this; },\n recordException() { return this; },\n setLlmFields() { return this; },\n setToolFields() { return this; },\n end() {},\n toPayload(): SpanPayload {\n return {\n traceId: this.traceId,\n spanId: this.spanId,\n name: this.name,\n kind: this.kind,\n startTime: this.startTime,\n status: this.status,\n attributes: {},\n events: [],\n links: [],\n };\n },\n});\n\nexport type NoopSpan = typeof NOOP_SPAN;\n","/**\n * AsyncLocalStorage-based context propagation.\n *\n * Uses a single AsyncLocalStorage instance with a composite state object.\n * This is simpler and more performant than multiple separate stores.\n *\n * Node.js AsyncLocalStorage automatically propagates through:\n * - Promise / async-await\n * - setTimeout / setImmediate\n * - EventEmitter callbacks\n * - process.nextTick\n * - async generators (unlike Python's contextvars!)\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { Span } from '../span.js';\nimport type { SemanticPhase } from '../types.js';\nimport { getContextStorage } from '../globals.js';\n\n// ─── Context Types ───────────────────────────────────────────────────────────\n\nexport interface SessionContext {\n sessionId: string;\n userId?: string;\n metadata?: Record<string, unknown>;\n parentSessionId?: string;\n turnNumber?: number;\n}\n\nexport interface AgentContext {\n agentId: string;\n agentName?: string;\n agentRole?: string;\n agentType?: string;\n parentAgentId?: string;\n version?: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ContextState {\n session?: SessionContext;\n agent?: AgentContext;\n span?: Span;\n phase?: SemanticPhase;\n /** When true, provider instrumentors skip span creation (framework is handling it). */\n _suppressProviderInstrumentation?: boolean;\n /**\n * Pre-allocated trace ID from getTraceContext() when no span exists yet.\n * Ensures that getTraceContext().traceId matches the next span created\n * in this context — preventing the \"trace ID mismatch\" bug.\n */\n _rootTraceId?: string;\n}\n\n// ─── Storage Accessor ────────────────────────────────────────────────────────\n\nfunction storage(): AsyncLocalStorage<ContextState> {\n return getContextStorage() as AsyncLocalStorage<ContextState>;\n}\n\n// ─── Core Operations ─────────────────────────────────────────────────────────\n\n/**\n * Get the current context state, or empty object if outside any context.\n */\nexport function getContext(): ContextState {\n return storage().getStore() ?? {};\n}\n\n/**\n * Run a callback within a new context scope.\n * The new scope inherits from the parent, with overrides applied.\n */\nexport function runWithContext<T>(overrides: Partial<ContextState>, fn: () => T): T {\n const parent = getContext();\n const merged: ContextState = { ...parent, ...overrides };\n return storage().run(merged, fn);\n}\n\n/**\n * Run an async callback within a new context scope.\n */\nexport function runWithContextAsync<T>(overrides: Partial<ContextState>, fn: () => Promise<T>): Promise<T> {\n const parent = getContext();\n const merged: ContextState = { ...parent, ...overrides };\n return storage().run(merged, fn);\n}\n\n// ─── Context Accessors ───────────────────────────────────────────────────────\n\nexport function getCurrentSession(): SessionContext | undefined {\n return getContext().session;\n}\n\nexport function getCurrentAgent(): AgentContext | undefined {\n return getContext().agent;\n}\n\nexport function getCurrentSpan(): Span | undefined {\n return getContext().span;\n}\n\nexport function getCurrentPhase(): SemanticPhase | undefined {\n return getContext().phase;\n}\n\nexport function getCurrentSessionId(): string | undefined {\n return getContext().session?.sessionId;\n}\n\nexport function getCurrentAgentId(): string | undefined {\n return getContext().agent?.agentId;\n}\n\nexport function getCurrentTraceId(): string | undefined {\n return getContext().span?.traceId;\n}\n\nexport function getCurrentSpanId(): string | undefined {\n return getContext().span?.spanId;\n}\n\nexport function getCurrentParentSpanId(): string | undefined {\n return getContext().span?.parentSpanId;\n}\n\n/**\n * Get all current context as a plain object (for debugging/serialization).\n */\nexport function getCurrentContext(): Record<string, unknown> {\n const ctx = getContext();\n return {\n session: ctx.session ? {\n sessionId: ctx.session.sessionId,\n userId: ctx.session.userId,\n ...(ctx.session.parentSessionId !== undefined ? { parentSessionId: ctx.session.parentSessionId } : {}),\n ...(ctx.session.turnNumber !== undefined ? { turnNumber: ctx.session.turnNumber } : {}),\n ...(ctx.session.metadata !== undefined ? { metadata: ctx.session.metadata } : {}),\n } : null,\n agent: ctx.agent ? {\n agentId: ctx.agent.agentId,\n agentName: ctx.agent.agentName,\n agentRole: ctx.agent.agentRole,\n agentType: ctx.agent.agentType,\n ...(ctx.agent.parentAgentId !== undefined ? { parentAgentId: ctx.agent.parentAgentId } : {}),\n ...(ctx.agent.version !== undefined ? { version: ctx.agent.version } : {}),\n ...(ctx.agent.metadata !== undefined ? { metadata: ctx.agent.metadata } : {}),\n } : null,\n span: ctx.span ? { spanId: ctx.span.spanId, traceId: ctx.span.traceId } : null,\n phase: ctx.phase ?? null,\n };\n}\n","/**\n * Batch span processor.\n *\n * Collects spans and exports them in batches based on:\n * - Batch size threshold (default: 100 spans)\n * - Time interval (default: 1000ms)\n *\n * Node.js is single-threaded — no locks needed.\n * Timer is unref()'d so it doesn't prevent process exit.\n */\n\nimport type { Span } from '../span.js';\nimport { ExportResult, type SpanExporter } from './base.js';\nimport { debug, warn } from '../utils/log.js';\n\nexport interface BatchProcessorOptions {\n exporters: SpanExporter[];\n batchSize?: number;\n batchTimeoutMs?: number;\n maxQueueSize?: number;\n debug?: boolean;\n}\n\nexport class BatchSpanProcessor {\n private readonly _exporters: SpanExporter[];\n private readonly _batchSize: number;\n private readonly _batchTimeoutMs: number;\n private readonly _maxQueueSize: number;\n private readonly _debug: boolean;\n\n private _queue: Span[] = [];\n private _timer: ReturnType<typeof setInterval> | null = null;\n private _started = false;\n private _flushing = false;\n private _beforeExitHandler: (() => void) | null = null;\n\n // Retry tracking for failed batches (Audit #5)\n private _retryCounts = new Map<string, number>();\n private static readonly MAX_RETRIES = 3;\n\n // Metrics\n droppedSpans = 0;\n exportedSpans = 0;\n failedExports = 0;\n\n constructor(options: BatchProcessorOptions) {\n this._exporters = [...options.exporters];\n this._batchSize = options.batchSize ?? 100;\n this._batchTimeoutMs = options.batchTimeoutMs ?? 1000;\n this._maxQueueSize = options.maxQueueSize ?? 10000;\n this._debug = options.debug ?? false;\n }\n\n start(): void {\n if (this._started) return;\n this._started = true;\n\n // Periodic flush timer — unref so it doesn't keep process alive\n this._timer = setInterval(() => {\n void this._exportBatch();\n }, this._batchTimeoutMs);\n this._timer.unref();\n\n // Flush on process exit (Audit #3: use .once, not .on; await, not void)\n this._beforeExitHandler = () => {\n void this.shutdown();\n };\n process.once('beforeExit', this._beforeExitHandler);\n }\n\n async shutdown(timeoutMs = 5000): Promise<void> {\n if (!this._started) return;\n this._started = false;\n\n if (this._timer) {\n clearInterval(this._timer);\n this._timer = null;\n }\n\n // Remove process listener to prevent leak (Audit #3)\n if (this._beforeExitHandler) {\n process.removeListener('beforeExit', this._beforeExitHandler);\n this._beforeExitHandler = null;\n }\n\n // Final flush with timeout\n const flushPromise = this._exportBatch();\n const timeoutPromise = new Promise<void>((resolve) => setTimeout(resolve, timeoutMs));\n await Promise.race([flushPromise, timeoutPromise]);\n\n // Shutdown exporters\n for (const exporter of this._exporters) {\n try {\n await exporter.shutdown();\n } catch (e) {\n debug(`Error shutting down ${exporter.name}: ${e}`);\n }\n }\n\n // Clean up retry tracking\n this._retryCounts.clear();\n\n debug(\n `BatchSpanProcessor shutdown. Exported: ${this.exportedSpans}, ` +\n `Dropped: ${this.droppedSpans}, Failed: ${this.failedExports}`\n );\n }\n\n onSpanEnd(span: Span): void {\n if (!this._started) return;\n\n // Check queue capacity\n if (this._queue.length >= this._maxQueueSize) {\n this.droppedSpans++;\n if (this.droppedSpans === 1 || this.droppedSpans % 1000 === 0) {\n warn(`Span queue full (${this._maxQueueSize}). ${this.droppedSpans} spans dropped so far.`);\n }\n return;\n }\n\n this._queue.push(span);\n\n // Trigger immediate flush if batch size reached\n if (this._queue.length >= this._batchSize) {\n void this._exportBatch();\n }\n }\n\n async flush(timeoutMs = 5000): Promise<boolean> {\n if (!this._started) return true;\n\n const start = Date.now();\n\n // Wait for in-flight exports to complete AND queue to drain\n while (this._queue.length > 0 || this._flushing) {\n if (!this._flushing && this._queue.length > 0) {\n await this._exportBatch();\n } else {\n // Wait a tick for the in-flight export to finish\n await new Promise((r) => setTimeout(r, 1));\n }\n if (Date.now() - start > timeoutMs) return false;\n }\n\n return true;\n }\n\n getMetrics() {\n return {\n exportedSpans: this.exportedSpans,\n droppedSpans: this.droppedSpans,\n failedExports: this.failedExports,\n queueSize: this._queue.length,\n queueCapacity: this._maxQueueSize,\n queueUtilization: this._queue.length / this._maxQueueSize,\n };\n }\n\n private async _exportBatch(): Promise<void> {\n if (this._flushing || this._queue.length === 0) return;\n this._flushing = true;\n\n try {\n // Take up to batchSize spans\n const batch = this._queue.splice(0, this._batchSize);\n if (batch.length === 0) return;\n\n debug(`Exporting batch of ${batch.length} spans`);\n\n // Export to all exporters — count once, not per exporter\n let batchExported = false;\n for (const exporter of this._exporters) {\n try {\n const result = await exporter.export(batch);\n if (result === ExportResult.SUCCESS) {\n if (!batchExported) {\n this.exportedSpans += batch.length;\n batchExported = true;\n // Clear retry counts for successfully exported spans\n for (const span of batch) {\n this._retryCounts.delete(span.spanId);\n }\n }\n } else {\n this.failedExports++;\n }\n } catch (e) {\n this.failedExports++;\n debug(`Export to ${exporter.name} failed: ${e}`);\n }\n }\n\n // Audit #5: Re-queue failed batches with retry limit\n if (!batchExported) {\n const retryable = batch.filter(span => {\n const count = (this._retryCounts.get(span.spanId) ?? 0) + 1;\n if (count > BatchSpanProcessor.MAX_RETRIES) {\n this._retryCounts.delete(span.spanId);\n this.droppedSpans++;\n return false;\n }\n this._retryCounts.set(span.spanId, count);\n return true;\n });\n if (retryable.length > 0) {\n this._queue.unshift(...retryable);\n debug(`Re-queued ${retryable.length} spans for retry (${batch.length - retryable.length} dropped after max retries)`);\n }\n }\n } finally {\n this._flushing = false;\n }\n }\n}\n","/**\n * HTTP exporter for sending spans to the Risicare gateway.\n *\n * Uses native fetch (Node.js 18+), with:\n * - Automatic retry with exponential backoff\n * - Circuit breaker with half-open probe state\n * - Gzip compression for large payloads\n * - Bearer token authentication\n */\n\nimport type { Span } from '../span.js';\nimport type { IngestRequest } from '../types.js';\nimport { ExportResult, type SpanExporter } from './base.js';\nimport { debug, warn } from '../utils/log.js';\n\nconst SDK_VERSION = '0.1.1';\n\nexport interface HttpExporterOptions {\n endpoint: string;\n apiKey?: string;\n projectId?: string;\n environment?: string;\n timeoutMs?: number;\n maxRetries?: number;\n compress?: boolean;\n}\n\nexport class HttpExporter implements SpanExporter {\n readonly name = 'http';\n\n private readonly _endpoint: string;\n private readonly _apiKey: string | undefined;\n private readonly _projectId: string | undefined;\n private readonly _environment: string | undefined;\n private readonly _timeoutMs: number;\n private readonly _maxRetries: number;\n private readonly _compress: boolean;\n\n // Circuit breaker\n private _consecutiveFailures = 0;\n private _circuitOpenUntil = 0;\n private readonly _circuitBreakerThreshold = 3;\n private readonly _circuitBreakerCooldownMs = 30_000;\n\n constructor(options: HttpExporterOptions) {\n this._endpoint = options.endpoint.replace(/\\/+$/, '');\n this._apiKey = options.apiKey;\n this._projectId = options.projectId;\n this._environment = options.environment;\n this._timeoutMs = options.timeoutMs ?? 5000;\n this._maxRetries = options.maxRetries ?? 3;\n this._compress = options.compress ?? false;\n }\n\n async export(spans: Span[]): Promise<ExportResult> {\n if (spans.length === 0) return ExportResult.SUCCESS;\n\n // Circuit breaker: skip if open\n const now = Date.now();\n let isHalfOpen = false;\n if (this._consecutiveFailures >= this._circuitBreakerThreshold) {\n if (now < this._circuitOpenUntil) {\n return ExportResult.FAILURE;\n }\n // Cooldown expired — probe with single request (Audit #7: half-open state)\n isHalfOpen = true;\n }\n\n const body: IngestRequest = {\n spans: spans.map((s) => s.toPayload()),\n };\n if (this._projectId) body.projectId = this._projectId;\n if (this._environment) body.environment = this._environment;\n\n // Half-open: single probe request. Normal: full retry loop.\n const maxAttempts = isHalfOpen ? 1 : this._maxRetries;\n\n // Retry loop with exponential backoff\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const result = await this._sendRequest(body);\n\n if (result === ExportResult.SUCCESS) {\n this._consecutiveFailures = 0;\n return result;\n }\n\n // Backoff: 100ms, 200ms, 400ms\n if (attempt < maxAttempts - 1) {\n await sleep(100 * Math.pow(2, attempt));\n }\n }\n\n // All retries failed — update circuit breaker\n this._consecutiveFailures++;\n if (this._consecutiveFailures >= this._circuitBreakerThreshold) {\n this._circuitOpenUntil = Date.now() + this._circuitBreakerCooldownMs;\n warn(\n `HTTP exporter circuit breaker opened after ${this._consecutiveFailures} failures. ` +\n `Cooldown: ${this._circuitBreakerCooldownMs / 1000}s`\n );\n }\n\n return ExportResult.FAILURE;\n }\n\n private async _sendRequest(body: IngestRequest): Promise<ExportResult> {\n const url = `${this._endpoint}/v1/spans`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'User-Agent': `risicare-js/${SDK_VERSION} node/${process.version}`,\n };\n if (this._apiKey) {\n headers['Authorization'] = `Bearer ${this._apiKey}`;\n }\n\n let payload: string | Uint8Array = JSON.stringify(body);\n\n if (this._compress && payload.length > 1024) {\n try {\n const { gzipSync } = await import('node:zlib');\n payload = gzipSync(Buffer.from(payload));\n headers['Content-Encoding'] = 'gzip';\n } catch (e) {\n // Audit #16: log compression failures instead of silently swallowing\n debug(`Gzip compression failed, sending uncompressed: ${e}`);\n }\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this._timeoutMs);\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: payload,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.status < 300) {\n return ExportResult.SUCCESS;\n } else if (response.status === 408 || response.status === 504) {\n debug(`HTTP export timeout: ${response.status}`);\n return ExportResult.TIMEOUT;\n }\n debug(`HTTP export failed: ${response.status}`);\n return ExportResult.FAILURE;\n } catch (e) {\n debug(`HTTP export error: ${e}`);\n return ExportResult.FAILURE;\n }\n }\n\n shutdown(): void {\n // Native fetch doesn't need cleanup\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * RisicareClient — singleton client managing SDK lifecycle.\n *\n * Handles initialization, shutdown, and the connection between\n * the Tracer and the export pipeline (batch processor + HTTP exporter).\n *\n * Usage:\n * import { init, shutdown } from 'risicare';\n * init({ apiKey: 'rsk-...' }); // API key determines project\n * // ... instrument code ...\n * await shutdown(); // flush remaining spans\n */\n\nimport { type RisicareConfig, resolveConfig } from './config.js';\nimport { Tracer } from './tracer.js';\nimport { BatchSpanProcessor } from './exporters/batch.js';\nimport { HttpExporter } from './exporters/http.js';\nimport { ConsoleExporter } from './exporters/console.js';\nimport { SpanKind, SpanStatus } from './types.js';\nimport type { SpanExporter } from './exporters/base.js';\nimport { setDebug, debug } from './utils/log.js';\nimport {\n getClient as getGlobalClient,\n setClient as setGlobalClient,\n getTracer as getGlobalTracer,\n setTracer as setGlobalTracer,\n} from './globals.js';\n\n// ─── Client Class ───────────────────────────────────────────────────────────\n\nclass RisicareClient {\n readonly config: ReturnType<typeof resolveConfig>;\n readonly processor: BatchSpanProcessor;\n readonly tracer: Tracer;\n private _shutdownPromise: Promise<void> | undefined;\n private _shutdownHandlers: { signal: string; handler: () => void }[] = [];\n\n constructor(config?: Partial<RisicareConfig>) {\n this.config = resolveConfig(config);\n\n // API key format validation\n if (this.config.apiKey && !this.config.apiKey.startsWith('rsk-')) {\n debug('Warning: API key should start with \"rsk-\". Got: ' + this.config.apiKey.slice(0, 4) + '...');\n }\n\n // Build exporter chain\n let exporter: SpanExporter;\n if (this.config.debug && !this.config.apiKey) {\n exporter = new ConsoleExporter();\n } else if (this.config.apiKey) {\n exporter = new HttpExporter({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n projectId: this.config.projectId || undefined,\n environment: this.config.environment || undefined,\n compress: this.config.compress,\n });\n } else {\n // No API key and not debug — use console as fallback\n exporter = new ConsoleExporter();\n }\n\n this.processor = new BatchSpanProcessor({\n exporters: [exporter],\n batchSize: this.config.batchSize,\n batchTimeoutMs: this.config.batchTimeoutMs,\n maxQueueSize: this.config.maxQueueSize,\n debug: this.config.debug,\n });\n\n this.tracer = new Tracer({\n onSpanEnd: (span) => this.processor.onSpanEnd(span),\n sampleRate: this.config.sampleRate,\n enabled: this.config.enabled,\n traceContent: this.config.traceContent,\n });\n\n // Start the batch processor (enables span queuing and periodic flushing)\n this.processor.start();\n\n // Start FixRuntime for self-healing fix application.\n // Loads active fixes from /api/v1/fixes/active, caches with TTL,\n // background-refreshes every 60s. Provider patches call interceptCall()\n // to apply fixes before LLM calls.\n if (this.config.apiKey && this.config.enabled) {\n try {\n const { initFixRuntime } = require('./runtime/runtime.js') as typeof import('./runtime/runtime.js');\n initFixRuntime({\n apiEndpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n enabled: true,\n debug: this.config.debug,\n });\n } catch {\n // FixRuntime failure is non-fatal — tracing still works\n }\n }\n\n // Register shutdown hooks\n this._registerShutdownHooks();\n\n // Enable internal debug logging if configured\n setDebug(this.config.debug);\n debug(`Initialized: enabled=${this.config.enabled}, endpoint=${this.config.endpoint}`);\n }\n\n get enabled(): boolean {\n return this.tracer.enabled;\n }\n\n set enabled(value: boolean) {\n this.tracer.enabled = value;\n }\n\n // Audit #6: Promise-based shutdown dedup (fixes TOCTOU race condition)\n async shutdown(): Promise<void> {\n if (this._shutdownPromise) return this._shutdownPromise;\n this._shutdownPromise = this._doShutdown();\n return this._shutdownPromise;\n }\n\n private async _doShutdown(): Promise<void> {\n debug('Shutting down...');\n\n // Audit #3: Remove process listeners to prevent leak\n for (const { signal, handler } of this._shutdownHandlers) {\n process.removeListener(signal, handler);\n }\n this._shutdownHandlers = [];\n\n await this.processor.shutdown();\n }\n\n async flush(): Promise<void> {\n await this.processor.flush();\n }\n\n private _registerShutdownHooks(): void {\n const onShutdown = () => {\n // Audit #3: Add 5s timeout to prevent hanging on signal\n const timeout = setTimeout(() => process.exit(1), 5000);\n timeout.unref();\n this.shutdown().catch(() => {}).finally(() => clearTimeout(timeout));\n };\n\n const signals = ['beforeExit', 'SIGTERM', 'SIGINT'];\n for (const signal of signals) {\n process.once(signal, onShutdown);\n this._shutdownHandlers.push({ signal, handler: onShutdown });\n }\n }\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Initialize the Risicare SDK. Call once at application startup.\n *\n * @example\n * import { init } from 'risicare';\n * init({ apiKey: 'rsk-...', serviceName: 'my-agent', environment: 'production' });\n */\nexport function init(config?: Partial<RisicareConfig>): void {\n if (getGlobalClient()) {\n debug('Already initialized. Call shutdown() first to re-initialize.');\n return;\n }\n\n const client = new RisicareClient(config);\n setGlobalClient(client);\n setGlobalTracer(client.tracer);\n}\n\n/**\n * Gracefully shut down the SDK. Flushes pending spans before resolving.\n */\nexport async function shutdown(): Promise<void> {\n // Stop FixRuntime first (stops background refresh)\n try {\n const { shutdownFixRuntime } = require('./runtime/runtime.js') as typeof import('./runtime/runtime.js');\n shutdownFixRuntime();\n } catch {\n // FixRuntime may not be initialized\n }\n\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client) return;\n await client.shutdown();\n setGlobalClient(undefined);\n setGlobalTracer(undefined);\n}\n\n/**\n * Flush all pending spans without shutting down.\n */\nexport async function flush(): Promise<void> {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client) return;\n await client.flush();\n}\n\n/**\n * Enable tracing at runtime.\n */\nexport function enable(): void {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (client) client.enabled = true;\n}\n\n/**\n * Disable tracing at runtime. Spans will not be created or exported.\n */\nexport function disable(): void {\n const client = getGlobalClient() as RisicareClient | undefined;\n if (client) client.enabled = false;\n}\n\n/**\n * Check whether tracing is currently enabled.\n */\nexport function isEnabled(): boolean {\n const client = getGlobalClient() as RisicareClient | undefined;\n return client?.enabled ?? false;\n}\n\n/**\n * Get the global tracer instance. Returns undefined if not initialized.\n */\nexport function getTracer(): Tracer | undefined {\n return getGlobalTracer() as Tracer | undefined;\n}\n\n/**\n * Get the global tracer, or throw if not initialized.\n * @internal Used by decorators and providers that require an active tracer.\n */\nexport function requireTracer(): Tracer {\n const tracer = getGlobalTracer() as Tracer | undefined;\n if (!tracer) {\n throw new Error(\n 'Risicare SDK not initialized. Call init() before using tracing features.',\n );\n }\n return tracer;\n}\n\n/**\n * Check whether content tracing (prompt/completion capture) is enabled.\n */\nexport function getTraceContent(): boolean {\n const tracer = getGlobalTracer() as Tracer | undefined;\n return tracer?.traceContent ?? true;\n}\n\n/**\n * Get SDK metrics: exported spans, dropped spans, failed exports, queue stats.\n * Returns zero-valued metrics if SDK is not initialized.\n */\nexport function getMetrics() {\n const client = getGlobalClient() as RisicareClient | undefined;\n return client?.processor.getMetrics() ?? {\n exportedSpans: 0,\n droppedSpans: 0,\n failedExports: 0,\n queueSize: 0,\n queueCapacity: 0,\n queueUtilization: 0,\n };\n}\n\n// ─── reportError ──────────────────────────────────────────────────────────\n\n// Error dedup: SHA256 fingerprint → timestamp. Prevents retry loops from\n// creating N duplicate diagnoses. Matches Python SDK's 5-minute TTL.\nconst _ERROR_DEDUP_TTL_MS = 5 * 60 * 1000; // 5 minutes\nconst _ERROR_DEDUP_MAX = 1000;\nconst _recentErrors = new Map<string, number>(); // fingerprint → Date.now()\n\nfunction _errorFingerprint(err: Error): string {\n const raw = `${err.constructor?.name ?? 'Error'}:${String(err.message ?? '').slice(0, 200)}`;\n const { createHash } = require('node:crypto') as typeof import('node:crypto');\n return createHash('sha256').update(raw).digest('hex').slice(0, 16);\n}\n\nfunction _isDuplicateError(fingerprint: string): boolean {\n const now = Date.now();\n // Evict expired entries\n for (const [fp, ts] of _recentErrors) {\n if (now - ts > _ERROR_DEDUP_TTL_MS) _recentErrors.delete(fp);\n else break; // Map iterates in insertion order\n }\n if (_recentErrors.has(fingerprint)) return true;\n // Enforce max size\n if (_recentErrors.size >= _ERROR_DEDUP_MAX) {\n const oldest = _recentErrors.keys().next().value;\n if (oldest !== undefined) _recentErrors.delete(oldest);\n }\n _recentErrors.set(fingerprint, now);\n return false;\n}\n\n/**\n * Report a caught exception to the self-healing pipeline.\n *\n * Creates an error span that triggers diagnosis and fix generation.\n * Deduplicates identical errors within a 5-minute window (SHA256 fingerprint).\n * This function never throws and is non-blocking.\n *\n * @param error - The caught exception (Error object or string)\n * @param options - Optional attributes and context overrides\n */\nexport function reportError(\n error: unknown,\n options?: { name?: string; attributes?: Record<string, unknown> },\n): void {\n try {\n const tracer = getTracer();\n if (!tracer) return;\n\n const err = error instanceof Error ? error : new Error(String(error ?? 'unknown'));\n const spanName = options?.name ?? `error:${err.constructor.name}`;\n\n // Dedup: suppress identical errors within TTL (matches Python SDK)\n const fp = _errorFingerprint(err);\n if (_isDuplicateError(fp)) {\n debug(`reportError: duplicate suppressed (fp=${fp.slice(0, 8)})`);\n return;\n }\n\n tracer.startSpan({ name: spanName, kind: SpanKind.INTERNAL }, (span) => {\n span.setStatus(SpanStatus.ERROR, err.message);\n span.setAttribute('error', true);\n span.setAttribute('error.type', err.constructor.name);\n span.setAttribute('error.message', err.message.slice(0, 2000));\n if (err.stack) span.setAttribute('error.stack', err.stack.slice(0, 4000));\n span.setAttribute('risicare.reported_error', true);\n if (options?.attributes) {\n for (const [k, v] of Object.entries(options.attributes)) {\n span.setAttribute(k, v);\n }\n }\n });\n } catch {\n // Never crash the host application\n debug('reportError failed');\n }\n}\n\n// ─── score ─────────────────────────────────────────────────────────────────\n\n/**\n * Record a custom evaluation score on a trace.\n *\n * Sends the score to the server in a fire-and-forget fashion.\n * This function never throws and is non-blocking.\n *\n * @param traceId - The trace to score\n * @param name - Score name (e.g., \"accuracy\", \"user_satisfaction\")\n * @param value - Score value between 0.0 and 1.0 inclusive\n * @param options - Optional span_id and comment\n */\nexport function score(\n traceId: string,\n name: string,\n value: number,\n options?: { spanId?: string; comment?: string },\n): void {\n try {\n if (typeof value !== 'number' || value < 0.0 || value > 1.0) {\n debug(`score: value must be in [0.0, 1.0], got ${value}. Score not sent.`);\n return;\n }\n if (!traceId || !name) {\n debug('score: traceId and name are required');\n return;\n }\n\n const client = getGlobalClient() as RisicareClient | undefined;\n if (!client?.enabled || !client.config.apiKey) return;\n\n const endpoint = client.config.endpoint.replace(/\\/$/, '');\n const url = `${endpoint}/api/v1/scores`;\n const body = JSON.stringify({\n trace_id: traceId,\n name,\n score: value,\n source: 'sdk',\n ...(options?.spanId && { span_id: options.spanId }),\n ...(options?.comment && { comment: options.comment }),\n });\n\n // Fire-and-forget — never blocks caller\n fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${client.config.apiKey}`,\n },\n body,\n }).catch((err) => debug(`score: send failed: ${err}`));\n } catch {\n // Never crash the host application\n debug('score failed');\n }\n}\n","/**\n * Token cost calculation table.\n *\n * Prices are per 1M tokens. Update monthly.\n * Source: provider pricing pages.\n */\n\ninterface ModelPricing {\n input: number; // USD per 1M input tokens\n output: number; // USD per 1M output tokens\n}\n\nconst PRICING: Record<string, ModelPricing> = {\n // OpenAI\n 'gpt-4o': { input: 2.50, output: 10.00 },\n 'gpt-4o-mini': { input: 0.15, output: 0.60 },\n 'gpt-4-turbo': { input: 10.00, output: 30.00 },\n 'gpt-4': { input: 30.00, output: 60.00 },\n 'gpt-3.5-turbo': { input: 0.50, output: 1.50 },\n 'o1': { input: 15.00, output: 60.00 },\n 'o1-mini': { input: 3.00, output: 12.00 },\n 'o3-mini': { input: 1.10, output: 4.40 },\n\n // Anthropic\n 'claude-opus-4-5-20251101': { input: 15.00, output: 75.00 },\n 'claude-sonnet-4-5-20250929': { input: 3.00, output: 15.00 },\n 'claude-haiku-4-5-20251001': { input: 0.80, output: 4.00 },\n 'claude-3-5-sonnet-20241022': { input: 3.00, output: 15.00 },\n 'claude-3-haiku-20240307': { input: 0.25, output: 1.25 },\n 'claude-3-opus-20240229': { input: 15.00, output: 75.00 },\n\n // Google\n 'gemini-2.0-flash': { input: 0.10, output: 0.40 },\n 'gemini-1.5-pro': { input: 1.25, output: 5.00 },\n 'gemini-1.5-flash': { input: 0.075, output: 0.30 },\n\n // Groq\n 'llama-3.3-70b-versatile': { input: 0.59, output: 0.79 },\n 'llama-3.1-8b-instant': { input: 0.05, output: 0.08 },\n 'mixtral-8x7b-32768': { input: 0.24, output: 0.24 },\n\n // DeepSeek\n 'deepseek-chat': { input: 0.14, output: 0.28 },\n 'deepseek-reasoner': { input: 0.55, output: 2.19 },\n\n // Together.ai (open-source models)\n 'meta-llama/llama-3.3-70b-instruct-turbo': { input: 0.88, output: 0.88 },\n 'meta-llama/meta-llama-3.1-8b-instruct-turbo': { input: 0.18, output: 0.18 },\n 'meta-llama/llama-3.2-3b-instruct-turbo': { input: 0.06, output: 0.06 },\n 'qwen/qwen2.5-7b-instruct-turbo': { input: 0.20, output: 0.20 },\n 'mistralai/mistral-small-24b-instruct-2501': { input: 0.20, output: 0.20 },\n 'mistralai/mixtral-8x7b-instruct-v0.1': { input: 0.60, output: 0.60 },\n 'deepseek-ai/deepseek-v3': { input: 0.27, output: 1.10 },\n};\n\n/**\n * Calculate cost in USD for a model's token usage.\n * Returns undefined if model is not in pricing table.\n */\nexport function calculateCost(\n model: string,\n promptTokens: number,\n completionTokens: number,\n): number | undefined {\n const pricing = PRICING[model] ?? PRICING[model.toLowerCase()];\n if (!pricing) return undefined;\n\n const inputCost = (promptTokens / 1_000_000) * pricing.input;\n const outputCost = (completionTokens / 1_000_000) * pricing.output;\n return inputCost + outputCost;\n}\n\n/**\n * Check if a model has pricing data.\n */\nexport function hasPricing(model: string): boolean {\n return model in PRICING || model.toLowerCase() in PRICING;\n}\n","/**\n * OpenAI SDK Proxy-based instrumentation.\n *\n * Wraps an OpenAI client instance using ES Proxy to intercept:\n * - chat.completions.create (sync + streaming)\n * - embeddings.create\n *\n * The original client is NOT modified — Proxy creates a transparent wrapper\n * that intercepts method calls and creates tracing spans.\n *\n * Usage:\n * import OpenAI from 'openai';\n * import { patchOpenAI } from 'risicare/openai';\n * const openai = patchOpenAI(new OpenAI({ apiKey: '...' }));\n */\n\nimport { requireTracer } from '../../client.js';\nimport { SpanKind } from '../../types.js';\nimport { calculateCost } from '../../utils/pricing.js';\nimport { debug } from '../../utils/log.js';\nimport { isProviderInstrumentationSuppressed } from '../../context/dedup.js';\nimport type { Span } from '../../span.js';\n\n// Known OpenAI-compatible hosts for provider detection.\n// Matches Python SDK's _OPENAI_COMPATIBLE_HOSTS (20 provider identities total).\nconst COMPATIBLE_HOSTS: Record<string, string> = {\n 'api.deepseek.com': 'deepseek',\n 'api.together.xyz': 'together',\n 'api.groq.com': 'groq',\n 'api.x.ai': 'xai',\n 'api.fireworks.ai': 'fireworks',\n 'inference.baseten.co': 'baseten',\n 'api.novita.ai': 'novita',\n 'api.byteplus.com': 'byteplus',\n};\n\nfunction detectProvider(client: unknown): string {\n try {\n const baseURL = (client as Record<string, unknown>).baseURL;\n if (!baseURL || typeof baseURL !== 'string') return 'openai';\n const host = baseURL.split('//').pop()?.split('/')[0]?.split(':')[0]?.toLowerCase();\n return (host && COMPATIBLE_HOSTS[host]) ?? 'openai';\n } catch {\n return 'openai';\n }\n}\n\n/**\n * Extract request-time attributes from the API call parameters.\n * These capture the developer's intent (model, temperature, etc.).\n */\nfunction enrichSpanFromRequest(span: Span, params: Record<string, unknown>, provider: string): void {\n const model = params.model as string | undefined;\n if (model) {\n span.setAttribute('gen_ai.system', provider);\n span.setAttribute('gen_ai.request.model', model);\n }\n if (params.temperature !== undefined) span.setAttribute('gen_ai.request.temperature', params.temperature);\n if (params.max_tokens !== undefined) span.setAttribute('gen_ai.request.max_tokens', params.max_tokens);\n if (params.top_p !== undefined) span.setAttribute('gen_ai.request.top_p', params.top_p);\n if (params.frequency_penalty !== undefined) span.setAttribute('gen_ai.request.frequency_penalty', params.frequency_penalty);\n if (params.presence_penalty !== undefined) span.setAttribute('gen_ai.request.presence_penalty', params.presence_penalty);\n if (params.stream !== undefined) span.setAttribute('llm.stream', !!params.stream);\n\n // Tool/function calls\n const tools = params.tools;\n if (Array.isArray(tools) && tools.length > 0) {\n span.setAttribute('gen_ai.request.has_tools', true);\n span.setAttribute('gen_ai.request.tool_count', tools.length);\n }\n}\n\n/**\n * Extract response-time attributes from the API response.\n * These capture what the LLM actually did (tokens, finish reason, etc.).\n */\nfunction enrichSpanFromResponse(span: Span, response: Record<string, unknown>, provider: string): void {\n const model = response.model as string | undefined;\n const usage = response.usage as Record<string, number> | undefined;\n\n if (model) {\n span.setLlmFields({ provider, model });\n span.setAttribute('gen_ai.response.model', model);\n }\n\n // Response ID\n if (response.id) span.setAttribute('gen_ai.response.id', response.id);\n\n // Finish reasons\n const choices = response.choices as Array<Record<string, unknown>> | undefined;\n if (Array.isArray(choices) && choices.length > 0) {\n const reasons = choices.map(c => c.finish_reason).filter(Boolean);\n if (reasons.length > 0) span.setAttribute('gen_ai.response.finish_reasons', reasons);\n\n // Tool calls in response\n const firstChoice = choices[0];\n const msg = firstChoice?.message as Record<string, unknown> | undefined;\n if (msg?.tool_calls && Array.isArray(msg.tool_calls)) {\n span.setAttribute('gen_ai.response.tool_call_count', msg.tool_calls.length);\n }\n }\n\n // Token usage (CRITICAL — this is what shows in the dashboard)\n if (usage) {\n const promptTokens = usage.prompt_tokens ?? 0;\n const completionTokens = usage.completion_tokens ?? 0;\n const totalTokens = usage.total_tokens ?? (promptTokens + completionTokens);\n const cost = model ? calculateCost(model, promptTokens, completionTokens) : undefined;\n\n span.setLlmFields({\n promptTokens,\n completionTokens,\n totalTokens: totalTokens,\n costUsd: cost,\n });\n\n // Also set as gen_ai attributes for worker column promotion\n span.setAttribute('gen_ai.usage.prompt_tokens', promptTokens);\n span.setAttribute('gen_ai.usage.completion_tokens', completionTokens);\n span.setAttribute('gen_ai.usage.total_tokens', totalTokens);\n if (cost !== undefined) span.setAttribute('llm.cost.total_usd', cost);\n }\n}\n\nfunction createChatCompletionProxy(originalCreate: Function, provider: string): Function {\n return function patchedCreate(this: unknown, ...args: unknown[]) {\n if (isProviderInstrumentationSuppressed()) {\n return originalCreate.apply(this, args);\n }\n\n let tracer;\n try {\n tracer = requireTracer();\n } catch {\n debug('Tracer not initialized — call init() before using patchOpenAI()');\n return originalCreate.apply(this, args);\n }\n\n let params = (args[0] ?? {}) as Record<string, unknown>;\n let model = (params.model as string) ?? 'unknown';\n const isStream = !!params.stream;\n\n // FixRuntime: apply active fixes before the LLM call\n try {\n const { getFixRuntime } = require('../../runtime/runtime.js') as typeof import('../../runtime/runtime.js');\n const rt = getFixRuntime();\n if (rt?.isEnabled) {\n const result = rt.interceptCall('llm_call', model, params.messages as unknown[] ?? null, params);\n if (result.messages) params = { ...params, messages: result.messages };\n if (result.params) params = { ...params, ...result.params };\n model = (params.model as string) ?? model;\n args[0] = params;\n }\n } catch {\n // FixRuntime failure must never block the LLM call\n }\n\n return tracer.startSpan(\n { name: `openai.chat.completions.create`, kind: SpanKind.LLM_CALL },\n (span) => {\n span.setLlmFields({ provider, model });\n enrichSpanFromRequest(span, params, provider);\n\n const result = originalCreate.apply(this, args);\n\n if (result && typeof result === 'object' && typeof (result as Promise<unknown>).then === 'function') {\n // Don't auto-end span here — the tracer.startSpan handles it\n // but we need to enrich before it ends. Return a Promise that\n // enriches then resolves.\n return (result as Promise<Record<string, unknown>>).then((response) => {\n if (!isStream && response) {\n enrichSpanFromResponse(span, response, provider);\n }\n return response;\n });\n }\n\n return result;\n },\n );\n };\n}\n\nfunction createEmbeddingsProxy(originalCreate: Function, provider: string): Function {\n return function patchedCreate(this: unknown, ...args: unknown[]) {\n if (isProviderInstrumentationSuppressed()) {\n return originalCreate.apply(this, args);\n }\n\n let tracer;\n try {\n tracer = requireTracer();\n } catch {\n debug('Tracer not initialized — call init() before using patchOpenAI()');\n return originalCreate.apply(this, args);\n }\n\n const params = (args[0] ?? {}) as Record<string, unknown>;\n const model = (params.model as string) ?? 'unknown';\n\n return tracer.startSpan(\n { name: `openai.embeddings.create`, kind: SpanKind.LLM_CALL },\n (span) => {\n span.setLlmFields({ provider, model });\n enrichSpanFromRequest(span, params, provider);\n\n const result = originalCreate.apply(this, args);\n\n if (result && typeof result === 'object' && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<Record<string, unknown>>).then((response) => {\n if (response) {\n enrichSpanFromResponse(span, response, provider);\n }\n return response;\n });\n }\n\n return result;\n },\n );\n };\n}\n\n/**\n * Wrap an OpenAI client instance with tracing instrumentation.\n *\n * Returns a Proxy that intercepts chat.completions.create and embeddings.create.\n * The original client is NOT modified.\n *\n * @param client - An OpenAI client instance\n * @returns A proxied client with automatic tracing\n */\nexport function patchOpenAI<T extends object>(client: T): T {\n const provider = detectProvider(client);\n\n // Proxy the top-level client\n return new Proxy(client, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n // Intercept `.chat` access to proxy `.chat.completions`\n if (prop === 'chat' && value && typeof value === 'object') {\n return new Proxy(value as object, {\n get(chatTarget, chatProp, chatReceiver) {\n const chatValue = Reflect.get(chatTarget, chatProp, chatReceiver);\n\n if (chatProp === 'completions' && chatValue && typeof chatValue === 'object') {\n return new Proxy(chatValue as object, {\n get(compTarget, compProp, compReceiver) {\n const compValue = Reflect.get(compTarget, compProp, compReceiver);\n\n if (compProp === 'create' && typeof compValue === 'function') {\n return createChatCompletionProxy(compValue.bind(compTarget), provider);\n }\n\n return compValue;\n },\n });\n }\n\n return chatValue;\n },\n });\n }\n\n // Intercept `.embeddings` access\n if (prop === 'embeddings' && value && typeof value === 'object') {\n return new Proxy(value as object, {\n get(embTarget, embProp, embReceiver) {\n const embValue = Reflect.get(embTarget, embProp, embReceiver);\n\n if (embProp === 'create' && typeof embValue === 'function') {\n return createEmbeddingsProxy(embValue.bind(embTarget), provider);\n }\n\n return embValue;\n },\n });\n }\n\n return value;\n },\n });\n}\n","/**\n * Double-tracing prevention for framework integrations.\n *\n * When a framework integration (e.g., LlamaIndex handler) creates its own\n * LLM span, the underlying provider proxy (e.g., patchOpenAI) would also\n * create a duplicate span. This module provides suppression:\n *\n * - Framework integrations SET suppression via suppressProviderInstrumentation()\n * - Provider proxies CHECK via isProviderInstrumentationSuppressed() and skip\n *\n * Scoped to AsyncLocalStorage — concurrent calls are independent.\n */\n\nimport { getContext, runWithContext } from './storage.js';\n\n/**\n * Run a callback with provider instrumentation suppressed.\n *\n * During this callback, all provider instrumentors (patchOpenAI, etc.) will\n * skip span creation. The framework is responsible for creating the span.\n *\n * @param fn - The function to run with suppression active\n * @returns The function's return value\n */\nexport function suppressProviderInstrumentation<T>(fn: () => T): T {\n return runWithContext({ _suppressProviderInstrumentation: true }, fn);\n}\n\n/**\n * Check if provider instrumentation should be suppressed.\n *\n * Called by provider instrumentors as an early-exit guard. When true,\n * the provider calls the original method directly without creating a span.\n */\nexport function isProviderInstrumentationSuppressed(): boolean {\n return getContext()._suppressProviderInstrumentation === true;\n}\n"],"mappings":"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","names":["G","getFixRuntime"]}
|