@crevanta/stelvara-sdk 0.1.0-alpha.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/buffer.ts","../src/client.ts","../src/index.ts","../src/auto.ts"],"sourcesContent":["/**\n * Async trace buffer with batched delivery and retry logic.\n *\n * Uses setInterval for periodic flushing (JS equivalent of Python's\n * background thread). Never blocks the caller.\n */\n\nimport type { TraceEnvelope, IngestionResponse } from './types';\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport type FlushSuccessCallback = (\n batch: TraceEnvelope[],\n traceIds: string[],\n) => void;\n\nexport interface BufferConfig {\n endpoint: string;\n apiKey: string;\n maxSize: number;\n batchSize: number;\n flushIntervalMs: number;\n maxRetries: number;\n onFlushSuccess?: FlushSuccessCallback;\n}\n\nexport class TraceBuffer {\n private queue: TraceEnvelope[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n private running = true;\n private readonly config: BufferConfig;\n private shutdownHook: (() => void) | null = null;\n\n constructor(config: BufferConfig) {\n this.config = config;\n this.start();\n }\n\n /**\n * Add a trace to the buffer.\n * Returns false if the buffer is shut down.\n * Drops oldest trace if buffer is full.\n */\n enqueue(trace: TraceEnvelope): boolean {\n if (!this.running) return false;\n\n if (this.queue.length >= this.config.maxSize) {\n this.queue.shift(); // drop oldest\n }\n this.queue.push(trace);\n return true;\n }\n\n /** Number of traces waiting to be flushed. */\n get pendingCount(): number {\n return this.queue.length;\n }\n\n /**\n * Flush all pending traces to the API.\n * Sends in batches of batchSize.\n */\n async flush(): Promise<void> {\n if (this.flushing || this.queue.length === 0) return;\n this.flushing = true;\n\n try {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, this.config.batchSize);\n await this.sendBatch(batch);\n }\n } finally {\n this.flushing = false;\n }\n }\n\n /**\n * Flush remaining traces and stop the buffer.\n * Resolves when done or after timeoutMs.\n */\n async shutdown(timeoutMs = 5000): Promise<void> {\n if (!this.running) return;\n this.running = false;\n\n // Stop periodic flush\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n // Remove shutdown hooks\n this.removeShutdownHook();\n\n // Final flush with timeout\n const flushPromise = this.flush();\n const timeoutPromise = delay(timeoutMs);\n\n await Promise.race([flushPromise, timeoutPromise]);\n }\n\n /**\n * Send a single batch to the ingestion API with retry logic.\n */\n private async sendBatch(batch: TraceEnvelope[]): Promise<void> {\n const url = `${this.config.endpoint}/traces`;\n\n // Strip _localKey from envelopes for the API call\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const cleanBatch = batch.map(({ _localKey, ...clean }) => clean);\n\n for (let attempt = 0; attempt < this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(cleanBatch),\n });\n\n if (response.status === 201) {\n const data = (await response.json()) as IngestionResponse;\n const traceIds = data.trace_ids ?? [];\n this.config.onFlushSuccess?.(batch, traceIds);\n return;\n }\n\n if (response.status === 429) {\n const retryAfterHeader = response.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : 2 ** attempt;\n await delay(retryAfterSec * 1000);\n continue;\n }\n\n // Non-retryable HTTP error (400, 401, 403, etc.) — drop batch\n return;\n } catch {\n // Network error — exponential backoff\n const backoffMs = 2 ** attempt * 1000;\n await delay(backoffMs);\n }\n }\n\n // Exhausted retries — batch is dropped\n }\n\n private start(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n this.installShutdownHook();\n }\n\n private installShutdownHook(): void {\n const handler = (): void => {\n void this.shutdown();\n };\n\n // Browser: use beforeunload if available\n const g = globalThis as Record<string, unknown>;\n if (\n typeof g.window !== 'undefined' &&\n typeof (g.window as Record<string, unknown>).addEventListener ===\n 'function'\n ) {\n const win = g.window as {\n addEventListener: (e: string, fn: () => void) => void;\n removeEventListener: (e: string, fn: () => void) => void;\n };\n win.addEventListener('beforeunload', handler);\n this.shutdownHook = () => win.removeEventListener('beforeunload', handler);\n } else if (\n typeof process !== 'undefined' &&\n typeof process.on === 'function'\n ) {\n // Node.js: use beforeExit\n process.on('beforeExit', handler);\n this.shutdownHook = () => process.removeListener('beforeExit', handler);\n }\n }\n\n private removeShutdownHook(): void {\n this.shutdownHook?.();\n this.shutdownHook = null;\n }\n}\n","/**\n * StelvaraClient — manages trace capture, buffering, and outcome tagging.\n *\n * Port of the Python SDK's client.py adapted for TypeScript/fetch.\n */\n\nimport { TraceBuffer } from './buffer';\nimport type {\n StelvaraConfig,\n TracePayload,\n CaptureTraceOptions,\n TraceEnvelope,\n OutcomeBatchEntry,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\nconst DEFAULT_ENDPOINT =\n 'https://auinkdnurzlaitpwhknm.supabase.co/functions/v1';\n\ninterface ResolvedConfig {\n apiKey: string;\n agentId: string;\n endpoint: string;\n bufferSize: number;\n batchSize: number;\n flushIntervalMs: number;\n maxRetries: number;\n enabled: boolean;\n}\n\nfunction resolveConfig(config: StelvaraConfig): ResolvedConfig {\n if (!config.apiKey) throw new Error('apiKey is required');\n if (!config.agentId) throw new Error('agentId is required');\n\n return {\n apiKey: config.apiKey,\n agentId: config.agentId,\n endpoint: (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/+$/, ''),\n bufferSize: config.bufferSize ?? 100,\n batchSize: config.batchSize ?? 50,\n flushIntervalMs: config.flushIntervalMs ?? 5000,\n maxRetries: config.maxRetries ?? 3,\n enabled: config.enabled ?? true,\n };\n}\n\nexport class StelvaraClient {\n private readonly config: ResolvedConfig;\n private readonly buffer: TraceBuffer;\n private readonly traceIdMap: Map<string, string> = new Map();\n private traceCounter = 0;\n\n constructor(config: StelvaraConfig) {\n this.config = resolveConfig(config);\n\n this.buffer = new TraceBuffer({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n maxSize: this.config.bufferSize,\n batchSize: this.config.batchSize,\n flushIntervalMs: this.config.flushIntervalMs,\n maxRetries: this.config.maxRetries,\n onFlushSuccess: (batch, traceIds) =>\n this.registerTraceIds(batch, traceIds),\n });\n }\n\n /**\n * Capture a trace payload and enqueue for delivery.\n * Returns a local trace key for use with tagOutcome().\n * Returns null if the client is disabled.\n */\n captureTrace(\n payload: TracePayload,\n options?: CaptureTraceOptions,\n ): string | null {\n if (!this.config.enabled) return null;\n\n const localKey = `stv_local_${++this.traceCounter}`;\n\n const envelope: TraceEnvelope = {\n agent_id: this.config.agentId,\n payload,\n timestamp: new Date().toISOString(),\n _localKey: localKey,\n };\n\n if (options?.sessionId != null) {\n envelope.session_id = options.sessionId;\n }\n if (options?.parentTraceId != null) {\n envelope.parent_trace_id = options.parentTraceId;\n }\n if (options?.traceType != null) {\n envelope.trace_type = options.traceType;\n }\n\n this.buffer.enqueue(envelope);\n return localKey;\n }\n\n /**\n * Tag a trace with business outcomes.\n * Resolves local trace keys to server UUIDs automatically.\n * Fire-and-forget — catches errors internally.\n */\n async tagOutcome(\n traceId: string,\n outcomes: Record<string, unknown>,\n ): Promise<void> {\n if (!this.config.enabled) return;\n\n let resolvedId = traceId;\n if (traceId.startsWith('stv_local_')) {\n const serverId = this.traceIdMap.get(traceId);\n if (serverId) {\n resolvedId = serverId;\n } else {\n console.warn(\n `[stelvara] Trace ${traceId} not yet flushed — outcome may fail`,\n );\n }\n }\n\n const url = `${this.config.endpoint}/outcomes`;\n try {\n await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ trace_id: resolvedId, outcomes }),\n });\n } catch {\n console.warn(`[stelvara] Failed to tag outcome for trace ${resolvedId}`);\n }\n }\n\n /**\n * Tag multiple traces with business outcomes in a single API call.\n *\n * @param entries - Array of { trace_id, outcomes } objects (max 100).\n * @returns Response with inserted count, failed count, and per-entry results.\n * @throws {Error} If entries is empty or exceeds 100 items.\n *\n * @example\n * const result = await client.tagOutcomesBatch([\n * { trace_id: 'uuid-1', outcomes: { revenue_impact: 45 } },\n * { trace_id: 'uuid-2', outcomes: { customer_satisfied: 1 } },\n * ]);\n * console.log(`Tagged ${result.inserted} outcomes`);\n */\n async tagOutcomesBatch(\n entries: OutcomeBatchEntry[],\n ): Promise<OutcomeBatchResponse | null> {\n if (!this.config.enabled) return null;\n\n if (entries.length === 0) {\n throw new Error('entries must not be empty');\n }\n if (entries.length > 100) {\n throw new Error('entries must not exceed 100 items');\n }\n\n // Resolve local trace keys to server UUIDs\n const resolvedEntries = entries.map((entry) => {\n let resolvedId = entry.trace_id;\n if (entry.trace_id.startsWith('stv_local_')) {\n const serverId = this.traceIdMap.get(entry.trace_id);\n if (serverId) {\n resolvedId = serverId;\n } else {\n console.warn(\n `[stelvara] Trace ${entry.trace_id} not yet flushed — batch entry may fail`,\n );\n }\n }\n return { trace_id: resolvedId, outcomes: entry.outcomes };\n });\n\n const url = `${this.config.endpoint}/outcomes-batch`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ entries: resolvedEntries }),\n });\n\n return (await response.json()) as OutcomeBatchResponse;\n }\n\n /**\n * Tag all traces in a session with business outcomes.\n * The server resolves trace IDs by session_id.\n *\n * @param sessionId - Session identifier.\n * @param outcomes - Dict of outcome metrics applied to every trace in the session.\n * @returns Response with traces_found, inserted count, and per-trace results.\n *\n * @example\n * const result = await client.tagSessionOutcome('session-uuid', {\n * revenue_impact: 150,\n * customer_satisfied: 1,\n * });\n * console.log(`Tagged ${result.traces_found} traces`);\n */\n async tagSessionOutcome(\n sessionId: string,\n outcomes: Record<string, unknown>,\n ): Promise<SessionOutcomeResponse | null> {\n if (!this.config.enabled) return null;\n\n const url = `${this.config.endpoint}/outcomes-batch/session`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ session_id: sessionId, outcomes }),\n });\n\n return (await response.json()) as SessionOutcomeResponse;\n }\n\n /**\n * Flush pending traces and shut down the client.\n */\n async shutdown(timeoutMs?: number): Promise<void> {\n await this.buffer.shutdown(timeoutMs);\n }\n\n /** Number of traces waiting to be flushed. */\n get pendingCount(): number {\n return this.buffer.pendingCount;\n }\n\n /**\n * Map local trace keys to server-assigned trace IDs after flush.\n */\n private registerTraceIds(\n batch: TraceEnvelope[],\n traceIds: string[],\n ): void {\n for (let i = 0; i < batch.length; i++) {\n const localKey = batch[i]._localKey;\n if (localKey && traceIds[i]) {\n this.traceIdMap.set(localKey, traceIds[i]);\n }\n }\n }\n}\n","/**\n * Stelvara TypeScript SDK — AI Behavior Control Plane.\n *\n * Usage:\n * import { init, captureTrace, tagOutcome, shutdown } from '@crevanta/stelvara-sdk';\n *\n * init({ apiKey: 'stv_live_...', agentId: 'uuid' });\n * const traceKey = captureTrace({ input: { user_message: 'Hello' } });\n * await shutdown();\n */\n\nexport { StelvaraClient } from './client';\nexport type {\n TracePayload,\n TraceEnvelope,\n StelvaraConfig,\n OutcomeRequest,\n TraceType,\n CaptureTraceOptions,\n TraceInput,\n TracePrompt,\n TraceModel,\n TraceResponse,\n ToolCall,\n TraceDecision,\n TracePerformance,\n IngestionResponse,\n OutcomeBatchEntry,\n OutcomeBatchResult,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\nimport { StelvaraClient } from './client';\nimport type {\n StelvaraConfig,\n TracePayload,\n CaptureTraceOptions,\n OutcomeBatchEntry,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\n// Module-level singleton\nlet _client: StelvaraClient | null = null;\n\n/**\n * Initialize the Stelvara SDK.\n * Must be called before captureTrace() or tagOutcome().\n *\n * Calling init() again will shut down the previous client.\n */\nexport function init(config: StelvaraConfig): void {\n if (_client !== null) {\n void _client.shutdown();\n }\n _client = new StelvaraClient(config);\n}\n\n/**\n * Capture a trace payload using the module-level client.\n * Returns a local trace key for use with tagOutcome().\n *\n * @throws {Error} If init() has not been called.\n */\nexport function captureTrace(payload: TracePayload, options?: CaptureTraceOptions): string | null {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.captureTrace(payload, options);\n}\n\n/**\n * Tag a trace with business outcomes.\n *\n * @throws {Error} If init() has not been called.\n */\nexport async function tagOutcome(\n traceId: string,\n outcomes: Record<string, unknown>\n): Promise<void> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagOutcome(traceId, outcomes);\n}\n\n/**\n * Tag multiple traces with business outcomes in a single API call.\n *\n * @param entries - Array of { trace_id, outcomes } objects (max 100).\n * @returns Response with inserted count, failed count, and per-entry results.\n * Returns null if SDK is disabled.\n * @throws {Error} If init() has not been called.\n * @throws {Error} If entries is empty or exceeds 100 items.\n *\n * @example\n * const result = await tagOutcomesBatch([\n * { trace_id: 'uuid-1', outcomes: { revenue_impact: 45 } },\n * { trace_id: 'uuid-2', outcomes: { customer_satisfied: 1 } },\n * ]);\n * console.log(`Tagged ${result.inserted} outcomes`);\n */\nexport async function tagOutcomesBatch(\n entries: OutcomeBatchEntry[]\n): Promise<OutcomeBatchResponse | null> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagOutcomesBatch(entries);\n}\n\n/**\n * Tag all traces in a session with business outcomes.\n * The server resolves trace IDs by session_id.\n *\n * @param sessionId - Session identifier.\n * @param outcomes - Dict of outcome metrics applied to every trace in the session.\n * @returns Response with traces_found, inserted count, and per-trace results.\n * Returns null if SDK is disabled.\n * @throws {Error} If init() has not been called.\n *\n * @example\n * const result = await tagSessionOutcome('session-uuid', {\n * revenue_impact: 150,\n * customer_satisfied: 1,\n * });\n * console.log(`Tagged ${result.traces_found} traces`);\n */\nexport async function tagSessionOutcome(\n sessionId: string,\n outcomes: Record<string, unknown>\n): Promise<SessionOutcomeResponse | null> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagSessionOutcome(sessionId, outcomes);\n}\n\n/**\n * Flush pending traces and shut down the SDK.\n * Safe to call multiple times. After shutdown, init() must be called again.\n */\nexport async function shutdown(): Promise<void> {\n if (_client !== null) {\n await _client.shutdown();\n _client = null;\n }\n}\n\n/**\n * Check if the SDK has been initialized.\n */\nexport function isInitialized(): boolean {\n return _client !== null;\n}\n\n/** @internal — exposed for testing only */\nexport function _resetForTesting(): void {\n _client = null;\n}\n","/**\n * Stelvara Auto-Instrumentation — patch globalThis.fetch to capture LLM traces.\n *\n * Usage:\n * import '@crevanta/stelvara-sdk/auto';\n *\n * Set STELVARA_API_KEY and STELVARA_AGENT_ID as environment variables.\n * Optionally call setSessionId() for conversation tracking.\n */\n\nimport { init, captureTrace, isInitialized } from './index';\nimport type { TracePayload, TraceType, ToolCall } from './types';\n\n// ── Provider URL patterns ──\n\nconst ANTHROPIC_PATTERN = 'api.anthropic.com/v1/messages';\nconst OPENAI_PATTERN = 'api.openai.com/v1/chat/completions';\n\ntype Provider = 'anthropic' | 'openai';\n\n// ── Module state ──\n\nlet _originalFetch: typeof globalThis.fetch | null = null;\nlet _installed = false;\nlet _sessionId: string | null = null;\nlet _inFlight = false;\n\n// ── Environment variable reader (Node + Deno compatible) ──\n\nfunction readEnvVar(name: string): string | undefined {\n /* eslint-disable @typescript-eslint/no-explicit-any */\n const g = globalThis as any;\n if (typeof g.Deno !== 'undefined' && g.Deno.env?.get) {\n return g.Deno.env.get(name) as string | undefined;\n }\n if (typeof g.process !== 'undefined' && g.process.env) {\n return g.process.env[name] as string | undefined;\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n return undefined;\n}\n\n// ── Provider detection ──\n\nfunction detectProvider(url: string): Provider | null {\n if (url.includes(ANTHROPIC_PATTERN)) return 'anthropic';\n if (url.includes(OPENAI_PATTERN)) return 'openai';\n return null;\n}\n\n// ── URL extraction from fetch input ──\n\nfunction resolveUrl(input: string | URL | Request): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\n// ── Request body parsing ──\n\nfunction parseBodySync(init: RequestInit | undefined): Record<string, unknown> | null {\n if (!init?.body || typeof init.body !== 'string') return null;\n try {\n return JSON.parse(init.body) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n// ── Anthropic extraction helpers ──\n\nfunction extractLastUserMessage(messages: unknown[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i] as Record<string, unknown>;\n if (msg?.role !== 'user') continue;\n const content = msg.content;\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n for (const block of content) {\n const b = block as Record<string, unknown>;\n if (b?.type === 'text' && typeof b.text === 'string') return b.text;\n }\n }\n }\n return '';\n}\n\nfunction extractAnthropicTrace(\n reqBody: Record<string, unknown>,\n resBody: Record<string, unknown>,\n durationMs: number\n): TracePayload {\n const messages = (reqBody.messages ?? []) as unknown[];\n const userMsg = extractLastUserMessage(messages);\n const systemMsg = typeof reqBody.system === 'string' ? reqBody.system : '';\n\n const payload: TracePayload = {\n input: { user_message: userMsg },\n model: {\n name: (resBody.model as string) ?? (reqBody.model as string) ?? 'unknown',\n provider: 'anthropic',\n },\n performance: { duration_ms: durationMs },\n };\n\n // Prompt\n const prompt: TracePayload['prompt'] = {};\n if (systemMsg) prompt.system = systemMsg;\n if (userMsg) prompt.user = userMsg;\n if (prompt.system || prompt.user) payload.prompt = prompt;\n\n // Response content blocks\n const contentBlocks = (resBody.content ?? []) as Array<Record<string, unknown>>;\n const toolCalls: ToolCall[] = [];\n\n for (const block of contentBlocks) {\n if (block.type === 'text' && typeof block.text === 'string' && !payload.response?.text) {\n payload.response = { ...payload.response, text: block.text };\n }\n if (block.type === 'tool_use') {\n toolCalls.push({\n name: (block.name as string) ?? 'unknown',\n arguments: (block.input as Record<string, unknown>) ?? undefined,\n });\n }\n }\n\n if (toolCalls.length > 0) payload.tool_calls = toolCalls;\n\n // Finish reason\n if (typeof resBody.stop_reason === 'string') {\n payload.response = { ...payload.response, finish_reason: resBody.stop_reason };\n }\n\n // Token usage\n const usage = resBody.usage as Record<string, number> | undefined;\n if (usage) {\n const inputTokens = usage.input_tokens ?? 0;\n const outputTokens = usage.output_tokens ?? 0;\n const total = inputTokens + outputTokens;\n if (total > 0) {\n payload.response = { ...payload.response, tokens_used: total };\n }\n payload.performance = { duration_ms: durationMs };\n if (inputTokens) payload.performance.tokens_input = inputTokens;\n if (outputTokens) payload.performance.tokens_output = outputTokens;\n }\n\n return payload;\n}\n\n// ── OpenAI extraction helpers ──\n\nfunction extractOpenAITrace(\n reqBody: Record<string, unknown>,\n resBody: Record<string, unknown>,\n durationMs: number\n): TracePayload {\n const messages = (reqBody.messages ?? []) as Array<Record<string, unknown>>;\n\n // Extract system and user messages\n let systemMsg = '';\n let userMsg = '';\n for (const msg of messages) {\n if (msg.role === 'system' && typeof msg.content === 'string') {\n systemMsg = msg.content;\n }\n }\n userMsg = extractLastUserMessage(messages);\n\n const payload: TracePayload = {\n input: { user_message: userMsg },\n model: {\n name: (resBody.model as string) ?? (reqBody.model as string) ?? 'unknown',\n provider: 'openai',\n },\n performance: { duration_ms: durationMs },\n };\n\n // Prompt\n const prompt: TracePayload['prompt'] = {};\n if (systemMsg) prompt.system = systemMsg;\n if (userMsg) prompt.user = userMsg;\n if (prompt.system || prompt.user) payload.prompt = prompt;\n\n // Response\n const choices = (resBody.choices ?? []) as Array<Record<string, unknown>>;\n if (choices.length > 0) {\n const choice = choices[0];\n const message = choice.message as Record<string, unknown> | undefined;\n if (message) {\n if (typeof message.content === 'string') {\n payload.response = { ...payload.response, text: message.content };\n }\n\n // Tool calls\n const rawToolCalls = message.tool_calls as Array<Record<string, unknown>> | undefined;\n if (rawToolCalls && rawToolCalls.length > 0) {\n payload.tool_calls = rawToolCalls.map((tc) => {\n const fn = tc.function as Record<string, unknown> | undefined;\n const entry: ToolCall = { name: (fn?.name as string) ?? 'unknown' };\n if (typeof fn?.arguments === 'string') {\n try {\n entry.arguments = JSON.parse(fn.arguments);\n } catch {\n entry.arguments = { raw: fn.arguments };\n }\n }\n return entry;\n });\n }\n }\n\n if (typeof choice.finish_reason === 'string') {\n payload.response = { ...payload.response, finish_reason: choice.finish_reason };\n }\n }\n\n // Token usage\n const usage = resBody.usage as Record<string, number> | undefined;\n if (usage) {\n const promptTokens = usage.prompt_tokens ?? 0;\n const completionTokens = usage.completion_tokens ?? 0;\n const total = usage.total_tokens ?? promptTokens + completionTokens;\n if (total > 0) {\n payload.response = { ...payload.response, tokens_used: total };\n }\n payload.performance = { duration_ms: durationMs };\n if (promptTokens) payload.performance.tokens_input = promptTokens;\n if (completionTokens) payload.performance.tokens_output = completionTokens;\n }\n\n return payload;\n}\n\n// ── SSE Streaming state ──\n\ninterface AnthropicSSEState {\n model: string;\n inputTokens: number;\n outputTokens: number;\n stopReason: string;\n textContent: string;\n toolCalls: ToolCall[];\n currentToolName: string;\n currentToolArgs: string;\n done: boolean;\n}\n\ninterface OpenAISSEState {\n model: string;\n textContent: string;\n toolCallMap: Map<number, { name: string; argumentsRaw: string }>;\n finishReason: string;\n done: boolean;\n}\n\nfunction makeAnthropicState(): AnthropicSSEState {\n return {\n model: '',\n inputTokens: 0,\n outputTokens: 0,\n stopReason: '',\n textContent: '',\n toolCalls: [],\n currentToolName: '',\n currentToolArgs: '',\n done: false,\n };\n}\n\nfunction makeOpenAIState(): OpenAISSEState {\n return {\n model: '',\n textContent: '',\n toolCallMap: new Map(),\n finishReason: '',\n done: false,\n };\n}\n\n// ── SSE line processors ──\n\nfunction processAnthropicSSE(line: string, state: AnthropicSSEState): void {\n if (!line.startsWith('data: ')) return;\n const json = line.slice(6);\n try {\n const event = JSON.parse(json) as Record<string, unknown>;\n switch (event.type) {\n case 'message_start': {\n const msg = event.message as Record<string, unknown> | undefined;\n if (msg) {\n if (typeof msg.model === 'string') state.model = msg.model;\n const usage = msg.usage as Record<string, number> | undefined;\n if (usage?.input_tokens) state.inputTokens = usage.input_tokens;\n }\n break;\n }\n case 'content_block_start': {\n const block = event.content_block as Record<string, unknown> | undefined;\n if (block?.type === 'tool_use') {\n state.currentToolName = (block.name as string) ?? 'unknown';\n state.currentToolArgs = '';\n }\n break;\n }\n case 'content_block_delta': {\n const delta = event.delta as Record<string, unknown> | undefined;\n if (delta?.type === 'text_delta' && typeof delta.text === 'string') {\n state.textContent += delta.text;\n }\n if (delta?.type === 'input_json_delta' && typeof delta.partial_json === 'string') {\n state.currentToolArgs += delta.partial_json;\n }\n break;\n }\n case 'content_block_stop': {\n if (state.currentToolName) {\n const tc: ToolCall = { name: state.currentToolName };\n if (state.currentToolArgs) {\n try {\n tc.arguments = JSON.parse(state.currentToolArgs);\n } catch {\n tc.arguments = { raw: state.currentToolArgs };\n }\n }\n state.toolCalls.push(tc);\n state.currentToolName = '';\n state.currentToolArgs = '';\n }\n break;\n }\n case 'message_delta': {\n const delta = event.delta as Record<string, unknown> | undefined;\n if (typeof delta?.stop_reason === 'string') state.stopReason = delta.stop_reason;\n const usage = event.usage as Record<string, number> | undefined;\n if (usage?.output_tokens) state.outputTokens = usage.output_tokens;\n break;\n }\n case 'message_stop':\n state.done = true;\n break;\n }\n } catch {\n // Ignore malformed SSE lines\n }\n}\n\nfunction processOpenAISSE(line: string, state: OpenAISSEState): void {\n if (!line.startsWith('data: ')) return;\n const json = line.slice(6).trim();\n if (json === '[DONE]') {\n state.done = true;\n return;\n }\n try {\n const event = JSON.parse(json) as Record<string, unknown>;\n if (typeof event.model === 'string' && !state.model) {\n state.model = event.model;\n }\n const choices = (event.choices ?? []) as Array<Record<string, unknown>>;\n if (choices.length > 0) {\n const choice = choices[0];\n const delta = choice.delta as Record<string, unknown> | undefined;\n if (delta) {\n if (typeof delta.content === 'string') {\n state.textContent += delta.content;\n }\n if (typeof choice.finish_reason === 'string') {\n state.finishReason = choice.finish_reason;\n }\n // Tool call deltas\n const toolCallDeltas = delta.tool_calls as Array<Record<string, unknown>> | undefined;\n if (toolCallDeltas) {\n for (const tcd of toolCallDeltas) {\n const idx = (tcd.index as number) ?? 0;\n const existing = state.toolCallMap.get(idx);\n const fn = tcd.function as Record<string, unknown> | undefined;\n if (!existing) {\n state.toolCallMap.set(idx, {\n name: (fn?.name as string) ?? '',\n argumentsRaw: (fn?.arguments as string) ?? '',\n });\n } else {\n if (fn?.name) existing.name += fn.name as string;\n if (fn?.arguments) existing.argumentsRaw += fn.arguments as string;\n }\n }\n }\n }\n }\n } catch {\n // Ignore malformed SSE chunks\n }\n}\n\n// ── Build trace from streaming state ──\n\nfunction buildAnthropicStreamTrace(\n reqBody: Record<string, unknown>,\n state: AnthropicSSEState,\n durationMs: number\n): TracePayload {\n const messages = (reqBody.messages ?? []) as unknown[];\n const userMsg = extractLastUserMessage(messages);\n const systemMsg = typeof reqBody.system === 'string' ? reqBody.system : '';\n const total = state.inputTokens + state.outputTokens;\n\n const payload: TracePayload = {\n input: { user_message: userMsg },\n model: { name: state.model || (reqBody.model as string) || 'unknown', provider: 'anthropic' },\n response: {\n text: state.textContent,\n finish_reason: state.stopReason || undefined,\n tokens_used: total > 0 ? total : undefined,\n },\n performance: {\n duration_ms: durationMs,\n tokens_input: state.inputTokens || undefined,\n tokens_output: state.outputTokens || undefined,\n },\n };\n\n const prompt: TracePayload['prompt'] = {};\n if (systemMsg) prompt.system = systemMsg;\n if (userMsg) prompt.user = userMsg;\n if (prompt.system || prompt.user) payload.prompt = prompt;\n\n if (state.toolCalls.length > 0) payload.tool_calls = state.toolCalls;\n\n return payload;\n}\n\nfunction buildOpenAIStreamTrace(\n reqBody: Record<string, unknown>,\n state: OpenAISSEState,\n durationMs: number\n): TracePayload {\n const messages = (reqBody.messages ?? []) as Array<Record<string, unknown>>;\n let systemMsg = '';\n for (const msg of messages) {\n if (msg.role === 'system' && typeof msg.content === 'string') {\n systemMsg = msg.content;\n break;\n }\n }\n const userMsg = extractLastUserMessage(messages);\n\n const payload: TracePayload = {\n input: { user_message: userMsg },\n model: { name: state.model || (reqBody.model as string) || 'unknown', provider: 'openai' },\n response: {\n text: state.textContent || undefined,\n finish_reason: state.finishReason || undefined,\n },\n performance: { duration_ms: durationMs },\n };\n\n const prompt: TracePayload['prompt'] = {};\n if (systemMsg) prompt.system = systemMsg;\n if (userMsg) prompt.user = userMsg;\n if (prompt.system || prompt.user) payload.prompt = prompt;\n\n // Assemble tool calls\n if (state.toolCallMap.size > 0) {\n payload.tool_calls = Array.from(state.toolCallMap.values()).map((tc) => {\n const entry: ToolCall = { name: tc.name };\n if (tc.argumentsRaw) {\n try {\n entry.arguments = JSON.parse(tc.argumentsRaw);\n } catch {\n entry.arguments = { raw: tc.argumentsRaw };\n }\n }\n return entry;\n });\n }\n\n return payload;\n}\n\n// ── Stream wrapping ──\n\nfunction wrapStreamingResponse(\n response: Response,\n provider: Provider,\n reqBody: Record<string, unknown>,\n startTime: number\n): Response {\n const body = response.body;\n if (!body) return response;\n\n const decoder = new TextDecoder();\n const state = provider === 'anthropic' ? makeAnthropicState() : makeOpenAIState();\n let buffer = '';\n\n const transformedStream = new ReadableStream<Uint8Array>({\n async start(controller) {\n const reader = body.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n\n // Pass through unchanged\n controller.enqueue(value);\n\n // Parse SSE lines\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (provider === 'anthropic') {\n processAnthropicSSE(trimmed, state as AnthropicSSEState);\n } else {\n processOpenAISSE(trimmed, state as OpenAISSEState);\n }\n }\n }\n\n // Process any remaining buffer\n if (buffer.trim()) {\n if (provider === 'anthropic') {\n processAnthropicSSE(buffer.trim(), state as AnthropicSSEState);\n } else {\n processOpenAISSE(buffer.trim(), state as OpenAISSEState);\n }\n }\n\n // Fire trace on stream end\n state.done = true;\n try {\n const durationMs = Date.now() - startTime;\n const tracePayload =\n provider === 'anthropic'\n ? buildAnthropicStreamTrace(reqBody, state as AnthropicSSEState, durationMs)\n : buildOpenAIStreamTrace(reqBody, state as OpenAISSEState, durationMs);\n\n const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;\n const traceType: TraceType = hasToolCalls ? 'tool_use' : 'chat';\n\n if (isInitialized()) {\n captureTrace(tracePayload, {\n sessionId: _sessionId ?? undefined,\n traceType,\n });\n }\n } catch {\n // Never let trace capture break the stream\n }\n\n controller.close();\n } catch (err) {\n controller.error(err);\n } finally {\n reader.releaseLock();\n }\n },\n });\n\n return new Response(transformedStream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n}\n\n// ── Patched fetch ──\n\nasync function patchedFetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {\n // Prevent recursion when TraceBuffer flushes\n if (_inFlight) {\n return _originalFetch!(input, init);\n }\n\n const url = resolveUrl(input);\n const provider = detectProvider(url);\n\n // Pass through non-LLM calls\n if (!provider) {\n return _originalFetch!(input, init);\n }\n\n _inFlight = true;\n const startTime = Date.now();\n let reqBody: Record<string, unknown> | null = null;\n\n try {\n reqBody = parseBodySync(init);\n } catch {\n // Can't parse request — still make the call\n }\n\n try {\n const response = await _originalFetch!(input, init);\n\n // Check if streaming\n const isStreaming = reqBody?.stream === true;\n\n if (isStreaming && reqBody) {\n try {\n return wrapStreamingResponse(response, provider, reqBody, startTime);\n } catch {\n return response;\n }\n }\n\n // Non-streaming: clone and parse\n if (reqBody) {\n try {\n const clone = response.clone();\n const resBody = (await clone.json()) as Record<string, unknown>;\n const durationMs = Date.now() - startTime;\n\n const tracePayload =\n provider === 'anthropic'\n ? extractAnthropicTrace(reqBody, resBody, durationMs)\n : extractOpenAITrace(reqBody, resBody, durationMs);\n\n const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;\n const traceType: TraceType = hasToolCalls ? 'tool_use' : 'chat';\n\n if (isInitialized()) {\n captureTrace(tracePayload, {\n sessionId: _sessionId ?? undefined,\n traceType,\n });\n }\n } catch {\n // Never let trace capture fail the request\n }\n }\n\n return response;\n } finally {\n _inFlight = false;\n }\n}\n\n// ── Public API ──\n\n/**\n * Install the fetch auto-instrumentation.\n * Reads STELVARA_API_KEY and STELVARA_AGENT_ID from environment variables.\n * Safe to call multiple times — idempotent.\n */\nexport function install(options?: { apiKey?: string; agentId?: string; endpoint?: string }): void {\n if (_installed) return;\n\n const apiKey = options?.apiKey ?? readEnvVar('STELVARA_API_KEY');\n const agentId = options?.agentId ?? readEnvVar('STELVARA_AGENT_ID');\n\n if (!isInitialized() && apiKey && agentId) {\n init({ apiKey, agentId, endpoint: options?.endpoint });\n }\n\n _originalFetch = globalThis.fetch;\n globalThis.fetch = patchedFetch as typeof globalThis.fetch;\n _installed = true;\n}\n\n/**\n * Remove the fetch patch and restore original fetch.\n */\nexport function uninstall(): void {\n if (!_installed || !_originalFetch) return;\n globalThis.fetch = _originalFetch;\n _originalFetch = null;\n _installed = false;\n}\n\n/**\n * Set a session ID for all auto-captured traces.\n * Call with null to clear.\n */\nexport function setSessionId(id: string | null): void {\n _sessionId = id;\n}\n\n/** @internal — exposed for testing only */\nexport function _resetForTesting(): void {\n if (_installed) uninstall();\n _sessionId = null;\n}\n\n// ── Side-effect: auto-install on import ──\ninstall();\n"],"mappings":"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","names":["init"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,403 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ StelvaraClient: () => StelvaraClient,
24
+ _resetForTesting: () => _resetForTesting,
25
+ captureTrace: () => captureTrace,
26
+ init: () => init,
27
+ isInitialized: () => isInitialized,
28
+ shutdown: () => shutdown,
29
+ tagOutcome: () => tagOutcome,
30
+ tagOutcomesBatch: () => tagOutcomesBatch,
31
+ tagSessionOutcome: () => tagSessionOutcome
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // src/buffer.ts
36
+ var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
37
+ var TraceBuffer = class {
38
+ queue = [];
39
+ timer = null;
40
+ flushing = false;
41
+ running = true;
42
+ config;
43
+ shutdownHook = null;
44
+ constructor(config) {
45
+ this.config = config;
46
+ this.start();
47
+ }
48
+ /**
49
+ * Add a trace to the buffer.
50
+ * Returns false if the buffer is shut down.
51
+ * Drops oldest trace if buffer is full.
52
+ */
53
+ enqueue(trace) {
54
+ if (!this.running) return false;
55
+ if (this.queue.length >= this.config.maxSize) {
56
+ this.queue.shift();
57
+ }
58
+ this.queue.push(trace);
59
+ return true;
60
+ }
61
+ /** Number of traces waiting to be flushed. */
62
+ get pendingCount() {
63
+ return this.queue.length;
64
+ }
65
+ /**
66
+ * Flush all pending traces to the API.
67
+ * Sends in batches of batchSize.
68
+ */
69
+ async flush() {
70
+ if (this.flushing || this.queue.length === 0) return;
71
+ this.flushing = true;
72
+ try {
73
+ while (this.queue.length > 0) {
74
+ const batch = this.queue.splice(0, this.config.batchSize);
75
+ await this.sendBatch(batch);
76
+ }
77
+ } finally {
78
+ this.flushing = false;
79
+ }
80
+ }
81
+ /**
82
+ * Flush remaining traces and stop the buffer.
83
+ * Resolves when done or after timeoutMs.
84
+ */
85
+ async shutdown(timeoutMs = 5e3) {
86
+ if (!this.running) return;
87
+ this.running = false;
88
+ if (this.timer !== null) {
89
+ clearInterval(this.timer);
90
+ this.timer = null;
91
+ }
92
+ this.removeShutdownHook();
93
+ const flushPromise = this.flush();
94
+ const timeoutPromise = delay(timeoutMs);
95
+ await Promise.race([flushPromise, timeoutPromise]);
96
+ }
97
+ /**
98
+ * Send a single batch to the ingestion API with retry logic.
99
+ */
100
+ async sendBatch(batch) {
101
+ const url = `${this.config.endpoint}/traces`;
102
+ const cleanBatch = batch.map(({ _localKey, ...clean }) => clean);
103
+ for (let attempt = 0; attempt < this.config.maxRetries; attempt++) {
104
+ try {
105
+ const response = await fetch(url, {
106
+ method: "POST",
107
+ headers: {
108
+ Authorization: `Bearer ${this.config.apiKey}`,
109
+ "Content-Type": "application/json"
110
+ },
111
+ body: JSON.stringify(cleanBatch)
112
+ });
113
+ if (response.status === 201) {
114
+ const data = await response.json();
115
+ const traceIds = data.trace_ids ?? [];
116
+ this.config.onFlushSuccess?.(batch, traceIds);
117
+ return;
118
+ }
119
+ if (response.status === 429) {
120
+ const retryAfterHeader = response.headers.get("Retry-After");
121
+ const retryAfterSec = retryAfterHeader ? parseInt(retryAfterHeader, 10) : 2 ** attempt;
122
+ await delay(retryAfterSec * 1e3);
123
+ continue;
124
+ }
125
+ return;
126
+ } catch {
127
+ const backoffMs = 2 ** attempt * 1e3;
128
+ await delay(backoffMs);
129
+ }
130
+ }
131
+ }
132
+ start() {
133
+ this.timer = setInterval(() => {
134
+ void this.flush();
135
+ }, this.config.flushIntervalMs);
136
+ this.installShutdownHook();
137
+ }
138
+ installShutdownHook() {
139
+ const handler = () => {
140
+ void this.shutdown();
141
+ };
142
+ const g = globalThis;
143
+ if (typeof g.window !== "undefined" && typeof g.window.addEventListener === "function") {
144
+ const win = g.window;
145
+ win.addEventListener("beforeunload", handler);
146
+ this.shutdownHook = () => win.removeEventListener("beforeunload", handler);
147
+ } else if (typeof process !== "undefined" && typeof process.on === "function") {
148
+ process.on("beforeExit", handler);
149
+ this.shutdownHook = () => process.removeListener("beforeExit", handler);
150
+ }
151
+ }
152
+ removeShutdownHook() {
153
+ this.shutdownHook?.();
154
+ this.shutdownHook = null;
155
+ }
156
+ };
157
+
158
+ // src/client.ts
159
+ var DEFAULT_ENDPOINT = "https://auinkdnurzlaitpwhknm.supabase.co/functions/v1";
160
+ function resolveConfig(config) {
161
+ if (!config.apiKey) throw new Error("apiKey is required");
162
+ if (!config.agentId) throw new Error("agentId is required");
163
+ return {
164
+ apiKey: config.apiKey,
165
+ agentId: config.agentId,
166
+ endpoint: (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, ""),
167
+ bufferSize: config.bufferSize ?? 100,
168
+ batchSize: config.batchSize ?? 50,
169
+ flushIntervalMs: config.flushIntervalMs ?? 5e3,
170
+ maxRetries: config.maxRetries ?? 3,
171
+ enabled: config.enabled ?? true
172
+ };
173
+ }
174
+ var StelvaraClient = class {
175
+ config;
176
+ buffer;
177
+ traceIdMap = /* @__PURE__ */ new Map();
178
+ traceCounter = 0;
179
+ constructor(config) {
180
+ this.config = resolveConfig(config);
181
+ this.buffer = new TraceBuffer({
182
+ endpoint: this.config.endpoint,
183
+ apiKey: this.config.apiKey,
184
+ maxSize: this.config.bufferSize,
185
+ batchSize: this.config.batchSize,
186
+ flushIntervalMs: this.config.flushIntervalMs,
187
+ maxRetries: this.config.maxRetries,
188
+ onFlushSuccess: (batch, traceIds) => this.registerTraceIds(batch, traceIds)
189
+ });
190
+ }
191
+ /**
192
+ * Capture a trace payload and enqueue for delivery.
193
+ * Returns a local trace key for use with tagOutcome().
194
+ * Returns null if the client is disabled.
195
+ */
196
+ captureTrace(payload, options) {
197
+ if (!this.config.enabled) return null;
198
+ const localKey = `stv_local_${++this.traceCounter}`;
199
+ const envelope = {
200
+ agent_id: this.config.agentId,
201
+ payload,
202
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
203
+ _localKey: localKey
204
+ };
205
+ if (options?.sessionId != null) {
206
+ envelope.session_id = options.sessionId;
207
+ }
208
+ if (options?.parentTraceId != null) {
209
+ envelope.parent_trace_id = options.parentTraceId;
210
+ }
211
+ if (options?.traceType != null) {
212
+ envelope.trace_type = options.traceType;
213
+ }
214
+ this.buffer.enqueue(envelope);
215
+ return localKey;
216
+ }
217
+ /**
218
+ * Tag a trace with business outcomes.
219
+ * Resolves local trace keys to server UUIDs automatically.
220
+ * Fire-and-forget — catches errors internally.
221
+ */
222
+ async tagOutcome(traceId, outcomes) {
223
+ if (!this.config.enabled) return;
224
+ let resolvedId = traceId;
225
+ if (traceId.startsWith("stv_local_")) {
226
+ const serverId = this.traceIdMap.get(traceId);
227
+ if (serverId) {
228
+ resolvedId = serverId;
229
+ } else {
230
+ console.warn(
231
+ `[stelvara] Trace ${traceId} not yet flushed \u2014 outcome may fail`
232
+ );
233
+ }
234
+ }
235
+ const url = `${this.config.endpoint}/outcomes`;
236
+ try {
237
+ await fetch(url, {
238
+ method: "POST",
239
+ headers: {
240
+ Authorization: `Bearer ${this.config.apiKey}`,
241
+ "Content-Type": "application/json"
242
+ },
243
+ body: JSON.stringify({ trace_id: resolvedId, outcomes })
244
+ });
245
+ } catch {
246
+ console.warn(`[stelvara] Failed to tag outcome for trace ${resolvedId}`);
247
+ }
248
+ }
249
+ /**
250
+ * Tag multiple traces with business outcomes in a single API call.
251
+ *
252
+ * @param entries - Array of { trace_id, outcomes } objects (max 100).
253
+ * @returns Response with inserted count, failed count, and per-entry results.
254
+ * @throws {Error} If entries is empty or exceeds 100 items.
255
+ *
256
+ * @example
257
+ * const result = await client.tagOutcomesBatch([
258
+ * { trace_id: 'uuid-1', outcomes: { revenue_impact: 45 } },
259
+ * { trace_id: 'uuid-2', outcomes: { customer_satisfied: 1 } },
260
+ * ]);
261
+ * console.log(`Tagged ${result.inserted} outcomes`);
262
+ */
263
+ async tagOutcomesBatch(entries) {
264
+ if (!this.config.enabled) return null;
265
+ if (entries.length === 0) {
266
+ throw new Error("entries must not be empty");
267
+ }
268
+ if (entries.length > 100) {
269
+ throw new Error("entries must not exceed 100 items");
270
+ }
271
+ const resolvedEntries = entries.map((entry) => {
272
+ let resolvedId = entry.trace_id;
273
+ if (entry.trace_id.startsWith("stv_local_")) {
274
+ const serverId = this.traceIdMap.get(entry.trace_id);
275
+ if (serverId) {
276
+ resolvedId = serverId;
277
+ } else {
278
+ console.warn(
279
+ `[stelvara] Trace ${entry.trace_id} not yet flushed \u2014 batch entry may fail`
280
+ );
281
+ }
282
+ }
283
+ return { trace_id: resolvedId, outcomes: entry.outcomes };
284
+ });
285
+ const url = `${this.config.endpoint}/outcomes-batch`;
286
+ const response = await fetch(url, {
287
+ method: "POST",
288
+ headers: {
289
+ Authorization: `Bearer ${this.config.apiKey}`,
290
+ "Content-Type": "application/json"
291
+ },
292
+ body: JSON.stringify({ entries: resolvedEntries })
293
+ });
294
+ return await response.json();
295
+ }
296
+ /**
297
+ * Tag all traces in a session with business outcomes.
298
+ * The server resolves trace IDs by session_id.
299
+ *
300
+ * @param sessionId - Session identifier.
301
+ * @param outcomes - Dict of outcome metrics applied to every trace in the session.
302
+ * @returns Response with traces_found, inserted count, and per-trace results.
303
+ *
304
+ * @example
305
+ * const result = await client.tagSessionOutcome('session-uuid', {
306
+ * revenue_impact: 150,
307
+ * customer_satisfied: 1,
308
+ * });
309
+ * console.log(`Tagged ${result.traces_found} traces`);
310
+ */
311
+ async tagSessionOutcome(sessionId, outcomes) {
312
+ if (!this.config.enabled) return null;
313
+ const url = `${this.config.endpoint}/outcomes-batch/session`;
314
+ const response = await fetch(url, {
315
+ method: "POST",
316
+ headers: {
317
+ Authorization: `Bearer ${this.config.apiKey}`,
318
+ "Content-Type": "application/json"
319
+ },
320
+ body: JSON.stringify({ session_id: sessionId, outcomes })
321
+ });
322
+ return await response.json();
323
+ }
324
+ /**
325
+ * Flush pending traces and shut down the client.
326
+ */
327
+ async shutdown(timeoutMs) {
328
+ await this.buffer.shutdown(timeoutMs);
329
+ }
330
+ /** Number of traces waiting to be flushed. */
331
+ get pendingCount() {
332
+ return this.buffer.pendingCount;
333
+ }
334
+ /**
335
+ * Map local trace keys to server-assigned trace IDs after flush.
336
+ */
337
+ registerTraceIds(batch, traceIds) {
338
+ for (let i = 0; i < batch.length; i++) {
339
+ const localKey = batch[i]._localKey;
340
+ if (localKey && traceIds[i]) {
341
+ this.traceIdMap.set(localKey, traceIds[i]);
342
+ }
343
+ }
344
+ }
345
+ };
346
+
347
+ // src/index.ts
348
+ var _client = null;
349
+ function init(config) {
350
+ if (_client !== null) {
351
+ void _client.shutdown();
352
+ }
353
+ _client = new StelvaraClient(config);
354
+ }
355
+ function captureTrace(payload, options) {
356
+ if (_client === null) {
357
+ throw new Error("Stelvara not initialized. Call init() first.");
358
+ }
359
+ return _client.captureTrace(payload, options);
360
+ }
361
+ async function tagOutcome(traceId, outcomes) {
362
+ if (_client === null) {
363
+ throw new Error("Stelvara not initialized. Call init() first.");
364
+ }
365
+ return _client.tagOutcome(traceId, outcomes);
366
+ }
367
+ async function tagOutcomesBatch(entries) {
368
+ if (_client === null) {
369
+ throw new Error("Stelvara not initialized. Call init() first.");
370
+ }
371
+ return _client.tagOutcomesBatch(entries);
372
+ }
373
+ async function tagSessionOutcome(sessionId, outcomes) {
374
+ if (_client === null) {
375
+ throw new Error("Stelvara not initialized. Call init() first.");
376
+ }
377
+ return _client.tagSessionOutcome(sessionId, outcomes);
378
+ }
379
+ async function shutdown() {
380
+ if (_client !== null) {
381
+ await _client.shutdown();
382
+ _client = null;
383
+ }
384
+ }
385
+ function isInitialized() {
386
+ return _client !== null;
387
+ }
388
+ function _resetForTesting() {
389
+ _client = null;
390
+ }
391
+ // Annotate the CommonJS export names for ESM import in node:
392
+ 0 && (module.exports = {
393
+ StelvaraClient,
394
+ _resetForTesting,
395
+ captureTrace,
396
+ init,
397
+ isInitialized,
398
+ shutdown,
399
+ tagOutcome,
400
+ tagOutcomesBatch,
401
+ tagSessionOutcome
402
+ });
403
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/buffer.ts","../src/client.ts"],"sourcesContent":["/**\n * Stelvara TypeScript SDK — AI Behavior Control Plane.\n *\n * Usage:\n * import { init, captureTrace, tagOutcome, shutdown } from '@crevanta/stelvara-sdk';\n *\n * init({ apiKey: 'stv_live_...', agentId: 'uuid' });\n * const traceKey = captureTrace({ input: { user_message: 'Hello' } });\n * await shutdown();\n */\n\nexport { StelvaraClient } from './client';\nexport type {\n TracePayload,\n TraceEnvelope,\n StelvaraConfig,\n OutcomeRequest,\n TraceType,\n CaptureTraceOptions,\n TraceInput,\n TracePrompt,\n TraceModel,\n TraceResponse,\n ToolCall,\n TraceDecision,\n TracePerformance,\n IngestionResponse,\n OutcomeBatchEntry,\n OutcomeBatchResult,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\nimport { StelvaraClient } from './client';\nimport type {\n StelvaraConfig,\n TracePayload,\n CaptureTraceOptions,\n OutcomeBatchEntry,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\n// Module-level singleton\nlet _client: StelvaraClient | null = null;\n\n/**\n * Initialize the Stelvara SDK.\n * Must be called before captureTrace() or tagOutcome().\n *\n * Calling init() again will shut down the previous client.\n */\nexport function init(config: StelvaraConfig): void {\n if (_client !== null) {\n void _client.shutdown();\n }\n _client = new StelvaraClient(config);\n}\n\n/**\n * Capture a trace payload using the module-level client.\n * Returns a local trace key for use with tagOutcome().\n *\n * @throws {Error} If init() has not been called.\n */\nexport function captureTrace(payload: TracePayload, options?: CaptureTraceOptions): string | null {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.captureTrace(payload, options);\n}\n\n/**\n * Tag a trace with business outcomes.\n *\n * @throws {Error} If init() has not been called.\n */\nexport async function tagOutcome(\n traceId: string,\n outcomes: Record<string, unknown>\n): Promise<void> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagOutcome(traceId, outcomes);\n}\n\n/**\n * Tag multiple traces with business outcomes in a single API call.\n *\n * @param entries - Array of { trace_id, outcomes } objects (max 100).\n * @returns Response with inserted count, failed count, and per-entry results.\n * Returns null if SDK is disabled.\n * @throws {Error} If init() has not been called.\n * @throws {Error} If entries is empty or exceeds 100 items.\n *\n * @example\n * const result = await tagOutcomesBatch([\n * { trace_id: 'uuid-1', outcomes: { revenue_impact: 45 } },\n * { trace_id: 'uuid-2', outcomes: { customer_satisfied: 1 } },\n * ]);\n * console.log(`Tagged ${result.inserted} outcomes`);\n */\nexport async function tagOutcomesBatch(\n entries: OutcomeBatchEntry[]\n): Promise<OutcomeBatchResponse | null> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagOutcomesBatch(entries);\n}\n\n/**\n * Tag all traces in a session with business outcomes.\n * The server resolves trace IDs by session_id.\n *\n * @param sessionId - Session identifier.\n * @param outcomes - Dict of outcome metrics applied to every trace in the session.\n * @returns Response with traces_found, inserted count, and per-trace results.\n * Returns null if SDK is disabled.\n * @throws {Error} If init() has not been called.\n *\n * @example\n * const result = await tagSessionOutcome('session-uuid', {\n * revenue_impact: 150,\n * customer_satisfied: 1,\n * });\n * console.log(`Tagged ${result.traces_found} traces`);\n */\nexport async function tagSessionOutcome(\n sessionId: string,\n outcomes: Record<string, unknown>\n): Promise<SessionOutcomeResponse | null> {\n if (_client === null) {\n throw new Error('Stelvara not initialized. Call init() first.');\n }\n return _client.tagSessionOutcome(sessionId, outcomes);\n}\n\n/**\n * Flush pending traces and shut down the SDK.\n * Safe to call multiple times. After shutdown, init() must be called again.\n */\nexport async function shutdown(): Promise<void> {\n if (_client !== null) {\n await _client.shutdown();\n _client = null;\n }\n}\n\n/**\n * Check if the SDK has been initialized.\n */\nexport function isInitialized(): boolean {\n return _client !== null;\n}\n\n/** @internal — exposed for testing only */\nexport function _resetForTesting(): void {\n _client = null;\n}\n","/**\n * Async trace buffer with batched delivery and retry logic.\n *\n * Uses setInterval for periodic flushing (JS equivalent of Python's\n * background thread). Never blocks the caller.\n */\n\nimport type { TraceEnvelope, IngestionResponse } from './types';\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport type FlushSuccessCallback = (\n batch: TraceEnvelope[],\n traceIds: string[],\n) => void;\n\nexport interface BufferConfig {\n endpoint: string;\n apiKey: string;\n maxSize: number;\n batchSize: number;\n flushIntervalMs: number;\n maxRetries: number;\n onFlushSuccess?: FlushSuccessCallback;\n}\n\nexport class TraceBuffer {\n private queue: TraceEnvelope[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private flushing = false;\n private running = true;\n private readonly config: BufferConfig;\n private shutdownHook: (() => void) | null = null;\n\n constructor(config: BufferConfig) {\n this.config = config;\n this.start();\n }\n\n /**\n * Add a trace to the buffer.\n * Returns false if the buffer is shut down.\n * Drops oldest trace if buffer is full.\n */\n enqueue(trace: TraceEnvelope): boolean {\n if (!this.running) return false;\n\n if (this.queue.length >= this.config.maxSize) {\n this.queue.shift(); // drop oldest\n }\n this.queue.push(trace);\n return true;\n }\n\n /** Number of traces waiting to be flushed. */\n get pendingCount(): number {\n return this.queue.length;\n }\n\n /**\n * Flush all pending traces to the API.\n * Sends in batches of batchSize.\n */\n async flush(): Promise<void> {\n if (this.flushing || this.queue.length === 0) return;\n this.flushing = true;\n\n try {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, this.config.batchSize);\n await this.sendBatch(batch);\n }\n } finally {\n this.flushing = false;\n }\n }\n\n /**\n * Flush remaining traces and stop the buffer.\n * Resolves when done or after timeoutMs.\n */\n async shutdown(timeoutMs = 5000): Promise<void> {\n if (!this.running) return;\n this.running = false;\n\n // Stop periodic flush\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n\n // Remove shutdown hooks\n this.removeShutdownHook();\n\n // Final flush with timeout\n const flushPromise = this.flush();\n const timeoutPromise = delay(timeoutMs);\n\n await Promise.race([flushPromise, timeoutPromise]);\n }\n\n /**\n * Send a single batch to the ingestion API with retry logic.\n */\n private async sendBatch(batch: TraceEnvelope[]): Promise<void> {\n const url = `${this.config.endpoint}/traces`;\n\n // Strip _localKey from envelopes for the API call\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const cleanBatch = batch.map(({ _localKey, ...clean }) => clean);\n\n for (let attempt = 0; attempt < this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(cleanBatch),\n });\n\n if (response.status === 201) {\n const data = (await response.json()) as IngestionResponse;\n const traceIds = data.trace_ids ?? [];\n this.config.onFlushSuccess?.(batch, traceIds);\n return;\n }\n\n if (response.status === 429) {\n const retryAfterHeader = response.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : 2 ** attempt;\n await delay(retryAfterSec * 1000);\n continue;\n }\n\n // Non-retryable HTTP error (400, 401, 403, etc.) — drop batch\n return;\n } catch {\n // Network error — exponential backoff\n const backoffMs = 2 ** attempt * 1000;\n await delay(backoffMs);\n }\n }\n\n // Exhausted retries — batch is dropped\n }\n\n private start(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n this.installShutdownHook();\n }\n\n private installShutdownHook(): void {\n const handler = (): void => {\n void this.shutdown();\n };\n\n // Browser: use beforeunload if available\n const g = globalThis as Record<string, unknown>;\n if (\n typeof g.window !== 'undefined' &&\n typeof (g.window as Record<string, unknown>).addEventListener ===\n 'function'\n ) {\n const win = g.window as {\n addEventListener: (e: string, fn: () => void) => void;\n removeEventListener: (e: string, fn: () => void) => void;\n };\n win.addEventListener('beforeunload', handler);\n this.shutdownHook = () => win.removeEventListener('beforeunload', handler);\n } else if (\n typeof process !== 'undefined' &&\n typeof process.on === 'function'\n ) {\n // Node.js: use beforeExit\n process.on('beforeExit', handler);\n this.shutdownHook = () => process.removeListener('beforeExit', handler);\n }\n }\n\n private removeShutdownHook(): void {\n this.shutdownHook?.();\n this.shutdownHook = null;\n }\n}\n","/**\n * StelvaraClient — manages trace capture, buffering, and outcome tagging.\n *\n * Port of the Python SDK's client.py adapted for TypeScript/fetch.\n */\n\nimport { TraceBuffer } from './buffer';\nimport type {\n StelvaraConfig,\n TracePayload,\n CaptureTraceOptions,\n TraceEnvelope,\n OutcomeBatchEntry,\n OutcomeBatchResponse,\n SessionOutcomeResponse,\n} from './types';\n\nconst DEFAULT_ENDPOINT =\n 'https://auinkdnurzlaitpwhknm.supabase.co/functions/v1';\n\ninterface ResolvedConfig {\n apiKey: string;\n agentId: string;\n endpoint: string;\n bufferSize: number;\n batchSize: number;\n flushIntervalMs: number;\n maxRetries: number;\n enabled: boolean;\n}\n\nfunction resolveConfig(config: StelvaraConfig): ResolvedConfig {\n if (!config.apiKey) throw new Error('apiKey is required');\n if (!config.agentId) throw new Error('agentId is required');\n\n return {\n apiKey: config.apiKey,\n agentId: config.agentId,\n endpoint: (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/+$/, ''),\n bufferSize: config.bufferSize ?? 100,\n batchSize: config.batchSize ?? 50,\n flushIntervalMs: config.flushIntervalMs ?? 5000,\n maxRetries: config.maxRetries ?? 3,\n enabled: config.enabled ?? true,\n };\n}\n\nexport class StelvaraClient {\n private readonly config: ResolvedConfig;\n private readonly buffer: TraceBuffer;\n private readonly traceIdMap: Map<string, string> = new Map();\n private traceCounter = 0;\n\n constructor(config: StelvaraConfig) {\n this.config = resolveConfig(config);\n\n this.buffer = new TraceBuffer({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n maxSize: this.config.bufferSize,\n batchSize: this.config.batchSize,\n flushIntervalMs: this.config.flushIntervalMs,\n maxRetries: this.config.maxRetries,\n onFlushSuccess: (batch, traceIds) =>\n this.registerTraceIds(batch, traceIds),\n });\n }\n\n /**\n * Capture a trace payload and enqueue for delivery.\n * Returns a local trace key for use with tagOutcome().\n * Returns null if the client is disabled.\n */\n captureTrace(\n payload: TracePayload,\n options?: CaptureTraceOptions,\n ): string | null {\n if (!this.config.enabled) return null;\n\n const localKey = `stv_local_${++this.traceCounter}`;\n\n const envelope: TraceEnvelope = {\n agent_id: this.config.agentId,\n payload,\n timestamp: new Date().toISOString(),\n _localKey: localKey,\n };\n\n if (options?.sessionId != null) {\n envelope.session_id = options.sessionId;\n }\n if (options?.parentTraceId != null) {\n envelope.parent_trace_id = options.parentTraceId;\n }\n if (options?.traceType != null) {\n envelope.trace_type = options.traceType;\n }\n\n this.buffer.enqueue(envelope);\n return localKey;\n }\n\n /**\n * Tag a trace with business outcomes.\n * Resolves local trace keys to server UUIDs automatically.\n * Fire-and-forget — catches errors internally.\n */\n async tagOutcome(\n traceId: string,\n outcomes: Record<string, unknown>,\n ): Promise<void> {\n if (!this.config.enabled) return;\n\n let resolvedId = traceId;\n if (traceId.startsWith('stv_local_')) {\n const serverId = this.traceIdMap.get(traceId);\n if (serverId) {\n resolvedId = serverId;\n } else {\n console.warn(\n `[stelvara] Trace ${traceId} not yet flushed — outcome may fail`,\n );\n }\n }\n\n const url = `${this.config.endpoint}/outcomes`;\n try {\n await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ trace_id: resolvedId, outcomes }),\n });\n } catch {\n console.warn(`[stelvara] Failed to tag outcome for trace ${resolvedId}`);\n }\n }\n\n /**\n * Tag multiple traces with business outcomes in a single API call.\n *\n * @param entries - Array of { trace_id, outcomes } objects (max 100).\n * @returns Response with inserted count, failed count, and per-entry results.\n * @throws {Error} If entries is empty or exceeds 100 items.\n *\n * @example\n * const result = await client.tagOutcomesBatch([\n * { trace_id: 'uuid-1', outcomes: { revenue_impact: 45 } },\n * { trace_id: 'uuid-2', outcomes: { customer_satisfied: 1 } },\n * ]);\n * console.log(`Tagged ${result.inserted} outcomes`);\n */\n async tagOutcomesBatch(\n entries: OutcomeBatchEntry[],\n ): Promise<OutcomeBatchResponse | null> {\n if (!this.config.enabled) return null;\n\n if (entries.length === 0) {\n throw new Error('entries must not be empty');\n }\n if (entries.length > 100) {\n throw new Error('entries must not exceed 100 items');\n }\n\n // Resolve local trace keys to server UUIDs\n const resolvedEntries = entries.map((entry) => {\n let resolvedId = entry.trace_id;\n if (entry.trace_id.startsWith('stv_local_')) {\n const serverId = this.traceIdMap.get(entry.trace_id);\n if (serverId) {\n resolvedId = serverId;\n } else {\n console.warn(\n `[stelvara] Trace ${entry.trace_id} not yet flushed — batch entry may fail`,\n );\n }\n }\n return { trace_id: resolvedId, outcomes: entry.outcomes };\n });\n\n const url = `${this.config.endpoint}/outcomes-batch`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ entries: resolvedEntries }),\n });\n\n return (await response.json()) as OutcomeBatchResponse;\n }\n\n /**\n * Tag all traces in a session with business outcomes.\n * The server resolves trace IDs by session_id.\n *\n * @param sessionId - Session identifier.\n * @param outcomes - Dict of outcome metrics applied to every trace in the session.\n * @returns Response with traces_found, inserted count, and per-trace results.\n *\n * @example\n * const result = await client.tagSessionOutcome('session-uuid', {\n * revenue_impact: 150,\n * customer_satisfied: 1,\n * });\n * console.log(`Tagged ${result.traces_found} traces`);\n */\n async tagSessionOutcome(\n sessionId: string,\n outcomes: Record<string, unknown>,\n ): Promise<SessionOutcomeResponse | null> {\n if (!this.config.enabled) return null;\n\n const url = `${this.config.endpoint}/outcomes-batch/session`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ session_id: sessionId, outcomes }),\n });\n\n return (await response.json()) as SessionOutcomeResponse;\n }\n\n /**\n * Flush pending traces and shut down the client.\n */\n async shutdown(timeoutMs?: number): Promise<void> {\n await this.buffer.shutdown(timeoutMs);\n }\n\n /** Number of traces waiting to be flushed. */\n get pendingCount(): number {\n return this.buffer.pendingCount;\n }\n\n /**\n * Map local trace keys to server-assigned trace IDs after flush.\n */\n private registerTraceIds(\n batch: TraceEnvelope[],\n traceIds: string[],\n ): void {\n for (let i = 0; i < batch.length; i++) {\n const localKey = batch[i]._localKey;\n if (localKey && traceIds[i]) {\n this.traceIdMap.set(localKey, traceIds[i]);\n }\n }\n }\n}\n"],"mappings":"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","names":[]}