@crevanta/stelvara-sdk 0.1.0-alpha.1 → 0.1.0-alpha.2
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/auto.cjs +76 -25
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +76 -25
- package/dist/auto.js.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/package.json +1 -1
package/dist/auto.cjs
CHANGED
|
@@ -360,6 +360,20 @@ function isInitialized() {
|
|
|
360
360
|
// src/auto.ts
|
|
361
361
|
var ANTHROPIC_PATTERN = "api.anthropic.com/v1/messages";
|
|
362
362
|
var OPENAI_PATTERN = "api.openai.com/v1/chat/completions";
|
|
363
|
+
var OPENAI_COMPAT_PATTERNS = [
|
|
364
|
+
{ pattern: "api.groq.com/", providerName: "groq" },
|
|
365
|
+
{ pattern: "api.together.xyz/", providerName: "together" },
|
|
366
|
+
{ pattern: "api.mistral.ai/", providerName: "mistral" },
|
|
367
|
+
{ pattern: "api.fireworks.ai/", providerName: "fireworks" },
|
|
368
|
+
{ pattern: "api.perplexity.ai/", providerName: "perplexity" },
|
|
369
|
+
{ pattern: "api.deepseek.com/", providerName: "deepseek" },
|
|
370
|
+
{ pattern: "openrouter.ai/api/", providerName: "openrouter" },
|
|
371
|
+
// Azure OpenAI: https://{resource}.openai.azure.com/openai/deployments/{model}/chat/completions
|
|
372
|
+
{ pattern: "openai.azure.com/openai/deployments/", providerName: "azure_openai" },
|
|
373
|
+
// Local Ollama (OpenAI-compatible mode)
|
|
374
|
+
{ pattern: "localhost:11434/", providerName: "ollama" },
|
|
375
|
+
{ pattern: "127.0.0.1:11434/", providerName: "ollama" }
|
|
376
|
+
];
|
|
363
377
|
var _originalFetch = null;
|
|
364
378
|
var _installed = false;
|
|
365
379
|
var _sessionId = null;
|
|
@@ -375,8 +389,11 @@ function readEnvVar(name) {
|
|
|
375
389
|
return void 0;
|
|
376
390
|
}
|
|
377
391
|
function detectProvider(url) {
|
|
378
|
-
if (url.includes(ANTHROPIC_PATTERN)) return "anthropic";
|
|
379
|
-
if (url.includes(OPENAI_PATTERN)) return "openai";
|
|
392
|
+
if (url.includes(ANTHROPIC_PATTERN)) return { format: "anthropic", name: "anthropic" };
|
|
393
|
+
if (url.includes(OPENAI_PATTERN)) return { format: "openai", name: "openai" };
|
|
394
|
+
for (const { pattern, providerName } of OPENAI_COMPAT_PATTERNS) {
|
|
395
|
+
if (url.includes(pattern)) return { format: "openai", name: providerName };
|
|
396
|
+
}
|
|
380
397
|
return null;
|
|
381
398
|
}
|
|
382
399
|
function resolveUrl(input) {
|
|
@@ -407,7 +424,7 @@ function extractLastUserMessage(messages) {
|
|
|
407
424
|
}
|
|
408
425
|
return "";
|
|
409
426
|
}
|
|
410
|
-
function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
427
|
+
function extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, providerName = "anthropic") {
|
|
411
428
|
const messages = reqBody.messages ?? [];
|
|
412
429
|
const userMsg = extractLastUserMessage(messages);
|
|
413
430
|
const systemMsg = typeof reqBody.system === "string" ? reqBody.system : "";
|
|
@@ -415,9 +432,9 @@ function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
|
415
432
|
input: { user_message: userMsg },
|
|
416
433
|
model: {
|
|
417
434
|
name: resBody.model ?? reqBody.model ?? "unknown",
|
|
418
|
-
provider:
|
|
435
|
+
provider: providerName
|
|
419
436
|
},
|
|
420
|
-
performance: { duration_ms: durationMs }
|
|
437
|
+
performance: { duration_ms: durationMs, ttfb_ms: ttfbMs }
|
|
421
438
|
};
|
|
422
439
|
const prompt = {};
|
|
423
440
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -448,13 +465,13 @@ function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
|
448
465
|
if (total > 0) {
|
|
449
466
|
payload.response = { ...payload.response, tokens_used: total };
|
|
450
467
|
}
|
|
451
|
-
payload.performance = { duration_ms: durationMs };
|
|
468
|
+
payload.performance = { ...payload.performance, duration_ms: durationMs };
|
|
452
469
|
if (inputTokens) payload.performance.tokens_input = inputTokens;
|
|
453
470
|
if (outputTokens) payload.performance.tokens_output = outputTokens;
|
|
454
471
|
}
|
|
455
472
|
return payload;
|
|
456
473
|
}
|
|
457
|
-
function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
474
|
+
function extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, providerName = "openai") {
|
|
458
475
|
const messages = reqBody.messages ?? [];
|
|
459
476
|
let systemMsg = "";
|
|
460
477
|
let userMsg = "";
|
|
@@ -468,9 +485,9 @@ function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
|
468
485
|
input: { user_message: userMsg },
|
|
469
486
|
model: {
|
|
470
487
|
name: resBody.model ?? reqBody.model ?? "unknown",
|
|
471
|
-
provider:
|
|
488
|
+
provider: providerName
|
|
472
489
|
},
|
|
473
|
-
performance: { duration_ms: durationMs }
|
|
490
|
+
performance: { duration_ms: durationMs, ttfb_ms: ttfbMs }
|
|
474
491
|
};
|
|
475
492
|
const prompt = {};
|
|
476
493
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -512,7 +529,7 @@ function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
|
512
529
|
if (total > 0) {
|
|
513
530
|
payload.response = { ...payload.response, tokens_used: total };
|
|
514
531
|
}
|
|
515
|
-
payload.performance = { duration_ms: durationMs };
|
|
532
|
+
payload.performance = { ...payload.performance, duration_ms: durationMs };
|
|
516
533
|
if (promptTokens) payload.performance.tokens_input = promptTokens;
|
|
517
534
|
if (completionTokens) payload.performance.tokens_output = completionTokens;
|
|
518
535
|
}
|
|
@@ -528,7 +545,8 @@ function makeAnthropicState() {
|
|
|
528
545
|
toolCalls: [],
|
|
529
546
|
currentToolName: "",
|
|
530
547
|
currentToolArgs: "",
|
|
531
|
-
done: false
|
|
548
|
+
done: false,
|
|
549
|
+
firstTokenAt: null
|
|
532
550
|
};
|
|
533
551
|
}
|
|
534
552
|
function makeOpenAIState() {
|
|
@@ -537,7 +555,8 @@ function makeOpenAIState() {
|
|
|
537
555
|
textContent: "",
|
|
538
556
|
toolCallMap: /* @__PURE__ */ new Map(),
|
|
539
557
|
finishReason: "",
|
|
540
|
-
done: false
|
|
558
|
+
done: false,
|
|
559
|
+
firstTokenAt: null
|
|
541
560
|
};
|
|
542
561
|
}
|
|
543
562
|
function processAnthropicSSE(line, state) {
|
|
@@ -566,6 +585,7 @@ function processAnthropicSSE(line, state) {
|
|
|
566
585
|
case "content_block_delta": {
|
|
567
586
|
const delta = event.delta;
|
|
568
587
|
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
588
|
+
if (state.firstTokenAt === null) state.firstTokenAt = Date.now();
|
|
569
589
|
state.textContent += delta.text;
|
|
570
590
|
}
|
|
571
591
|
if (delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
@@ -621,6 +641,8 @@ function processOpenAISSE(line, state) {
|
|
|
621
641
|
const delta = choice.delta;
|
|
622
642
|
if (delta) {
|
|
623
643
|
if (typeof delta.content === "string") {
|
|
644
|
+
if (state.firstTokenAt === null && delta.content.length > 0)
|
|
645
|
+
state.firstTokenAt = Date.now();
|
|
624
646
|
state.textContent += delta.content;
|
|
625
647
|
}
|
|
626
648
|
if (typeof choice.finish_reason === "string") {
|
|
@@ -648,14 +670,14 @@ function processOpenAISSE(line, state) {
|
|
|
648
670
|
} catch {
|
|
649
671
|
}
|
|
650
672
|
}
|
|
651
|
-
function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
673
|
+
function buildAnthropicStreamTrace(reqBody, state, durationMs, ttfbMs, timeToFirstTokenMs, streamingDurationMs, providerName = "anthropic") {
|
|
652
674
|
const messages = reqBody.messages ?? [];
|
|
653
675
|
const userMsg = extractLastUserMessage(messages);
|
|
654
676
|
const systemMsg = typeof reqBody.system === "string" ? reqBody.system : "";
|
|
655
677
|
const total = state.inputTokens + state.outputTokens;
|
|
656
678
|
const payload = {
|
|
657
679
|
input: { user_message: userMsg },
|
|
658
|
-
model: { name: state.model || reqBody.model || "unknown", provider:
|
|
680
|
+
model: { name: state.model || reqBody.model || "unknown", provider: providerName },
|
|
659
681
|
response: {
|
|
660
682
|
text: state.textContent,
|
|
661
683
|
finish_reason: state.stopReason || void 0,
|
|
@@ -663,6 +685,9 @@ function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
|
663
685
|
},
|
|
664
686
|
performance: {
|
|
665
687
|
duration_ms: durationMs,
|
|
688
|
+
ttfb_ms: ttfbMs,
|
|
689
|
+
time_to_first_token_ms: timeToFirstTokenMs,
|
|
690
|
+
streaming_duration_ms: streamingDurationMs,
|
|
666
691
|
tokens_input: state.inputTokens || void 0,
|
|
667
692
|
tokens_output: state.outputTokens || void 0
|
|
668
693
|
}
|
|
@@ -674,7 +699,7 @@ function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
|
674
699
|
if (state.toolCalls.length > 0) payload.tool_calls = state.toolCalls;
|
|
675
700
|
return payload;
|
|
676
701
|
}
|
|
677
|
-
function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
702
|
+
function buildOpenAIStreamTrace(reqBody, state, durationMs, ttfbMs, timeToFirstTokenMs, streamingDurationMs, providerName = "openai") {
|
|
678
703
|
const messages = reqBody.messages ?? [];
|
|
679
704
|
let systemMsg = "";
|
|
680
705
|
for (const msg of messages) {
|
|
@@ -686,12 +711,17 @@ function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
|
686
711
|
const userMsg = extractLastUserMessage(messages);
|
|
687
712
|
const payload = {
|
|
688
713
|
input: { user_message: userMsg },
|
|
689
|
-
model: { name: state.model || reqBody.model || "unknown", provider:
|
|
714
|
+
model: { name: state.model || reqBody.model || "unknown", provider: providerName },
|
|
690
715
|
response: {
|
|
691
716
|
text: state.textContent || void 0,
|
|
692
717
|
finish_reason: state.finishReason || void 0
|
|
693
718
|
},
|
|
694
|
-
performance: {
|
|
719
|
+
performance: {
|
|
720
|
+
duration_ms: durationMs,
|
|
721
|
+
ttfb_ms: ttfbMs,
|
|
722
|
+
time_to_first_token_ms: timeToFirstTokenMs,
|
|
723
|
+
streaming_duration_ms: streamingDurationMs
|
|
724
|
+
}
|
|
695
725
|
};
|
|
696
726
|
const prompt = {};
|
|
697
727
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -712,11 +742,11 @@ function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
|
712
742
|
}
|
|
713
743
|
return payload;
|
|
714
744
|
}
|
|
715
|
-
function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
745
|
+
function wrapStreamingResponse(response, provider, reqBody, startTime, ttfbMs) {
|
|
716
746
|
const body = response.body;
|
|
717
747
|
if (!body) return response;
|
|
718
748
|
const decoder = new TextDecoder();
|
|
719
|
-
const state = provider === "anthropic" ? makeAnthropicState() : makeOpenAIState();
|
|
749
|
+
const state = provider.format === "anthropic" ? makeAnthropicState() : makeOpenAIState();
|
|
720
750
|
let buffer = "";
|
|
721
751
|
const transformedStream = new ReadableStream({
|
|
722
752
|
async start(controller) {
|
|
@@ -732,7 +762,7 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
732
762
|
for (const line of lines) {
|
|
733
763
|
const trimmed = line.trim();
|
|
734
764
|
if (!trimmed) continue;
|
|
735
|
-
if (provider === "anthropic") {
|
|
765
|
+
if (provider.format === "anthropic") {
|
|
736
766
|
processAnthropicSSE(trimmed, state);
|
|
737
767
|
} else {
|
|
738
768
|
processOpenAISSE(trimmed, state);
|
|
@@ -740,7 +770,7 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
740
770
|
}
|
|
741
771
|
}
|
|
742
772
|
if (buffer.trim()) {
|
|
743
|
-
if (provider === "anthropic") {
|
|
773
|
+
if (provider.format === "anthropic") {
|
|
744
774
|
processAnthropicSSE(buffer.trim(), state);
|
|
745
775
|
} else {
|
|
746
776
|
processOpenAISSE(buffer.trim(), state);
|
|
@@ -748,8 +778,28 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
748
778
|
}
|
|
749
779
|
state.done = true;
|
|
750
780
|
try {
|
|
751
|
-
const
|
|
752
|
-
const
|
|
781
|
+
const endTime = Date.now();
|
|
782
|
+
const durationMs = endTime - startTime;
|
|
783
|
+
const firstTokenAt = state.firstTokenAt;
|
|
784
|
+
const timeToFirstTokenMs = firstTokenAt ? firstTokenAt - startTime : void 0;
|
|
785
|
+
const streamingDurationMs = firstTokenAt ? endTime - firstTokenAt : void 0;
|
|
786
|
+
const tracePayload = provider.format === "anthropic" ? buildAnthropicStreamTrace(
|
|
787
|
+
reqBody,
|
|
788
|
+
state,
|
|
789
|
+
durationMs,
|
|
790
|
+
ttfbMs,
|
|
791
|
+
timeToFirstTokenMs,
|
|
792
|
+
streamingDurationMs,
|
|
793
|
+
provider.name
|
|
794
|
+
) : buildOpenAIStreamTrace(
|
|
795
|
+
reqBody,
|
|
796
|
+
state,
|
|
797
|
+
durationMs,
|
|
798
|
+
ttfbMs,
|
|
799
|
+
timeToFirstTokenMs,
|
|
800
|
+
streamingDurationMs,
|
|
801
|
+
provider.name
|
|
802
|
+
);
|
|
753
803
|
const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;
|
|
754
804
|
const traceType = hasToolCalls ? "tool_use" : "chat";
|
|
755
805
|
if (isInitialized()) {
|
|
@@ -792,10 +842,11 @@ async function patchedFetch(input, init2) {
|
|
|
792
842
|
}
|
|
793
843
|
try {
|
|
794
844
|
const response = await _originalFetch(input, init2);
|
|
845
|
+
const ttfbMs = Date.now() - startTime;
|
|
795
846
|
const isStreaming = reqBody?.stream === true;
|
|
796
847
|
if (isStreaming && reqBody) {
|
|
797
848
|
try {
|
|
798
|
-
return wrapStreamingResponse(response, provider, reqBody, startTime);
|
|
849
|
+
return wrapStreamingResponse(response, provider, reqBody, startTime, ttfbMs);
|
|
799
850
|
} catch {
|
|
800
851
|
return response;
|
|
801
852
|
}
|
|
@@ -805,7 +856,7 @@ async function patchedFetch(input, init2) {
|
|
|
805
856
|
const clone = response.clone();
|
|
806
857
|
const resBody = await clone.json();
|
|
807
858
|
const durationMs = Date.now() - startTime;
|
|
808
|
-
const tracePayload = provider === "anthropic" ? extractAnthropicTrace(reqBody, resBody, durationMs) : extractOpenAITrace(reqBody, resBody, durationMs);
|
|
859
|
+
const tracePayload = provider.format === "anthropic" ? extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, provider.name) : extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, provider.name);
|
|
809
860
|
const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;
|
|
810
861
|
const traceType = hasToolCalls ? "tool_use" : "chat";
|
|
811
862
|
if (isInitialized()) {
|
package/dist/auto.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auto.ts","../src/buffer.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\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","/**\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"],"mappings":"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","names":["init"]}
|
|
1
|
+
{"version":3,"sources":["../src/auto.ts","../src/buffer.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\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\n/**\n * OpenAI-compatible providers that use the same SSE / response format.\n * Each entry maps a URL substring to the provider label stored in the trace.\n */\nconst OPENAI_COMPAT_PATTERNS: Array<{ pattern: string; providerName: string }> = [\n { pattern: 'api.groq.com/', providerName: 'groq' },\n { pattern: 'api.together.xyz/', providerName: 'together' },\n { pattern: 'api.mistral.ai/', providerName: 'mistral' },\n { pattern: 'api.fireworks.ai/', providerName: 'fireworks' },\n { pattern: 'api.perplexity.ai/', providerName: 'perplexity' },\n { pattern: 'api.deepseek.com/', providerName: 'deepseek' },\n { pattern: 'openrouter.ai/api/', providerName: 'openrouter' },\n // Azure OpenAI: https://{resource}.openai.azure.com/openai/deployments/{model}/chat/completions\n { pattern: 'openai.azure.com/openai/deployments/', providerName: 'azure_openai' },\n // Local Ollama (OpenAI-compatible mode)\n { pattern: 'localhost:11434/', providerName: 'ollama' },\n { pattern: '127.0.0.1:11434/', providerName: 'ollama' },\n];\n\n/** Protocol-level format: Anthropic Messages vs OpenAI Chat Completions. */\ntype ProviderFormat = 'anthropic' | 'openai';\n\n/** Detected provider info: wire format + label for the trace. */\ninterface DetectedProvider {\n format: ProviderFormat;\n name: string;\n}\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): DetectedProvider | null {\n if (url.includes(ANTHROPIC_PATTERN)) return { format: 'anthropic', name: 'anthropic' };\n if (url.includes(OPENAI_PATTERN)) return { format: 'openai', name: 'openai' };\n // OpenAI-compatible providers (Groq, Together, Mistral, Azure, Ollama, etc.)\n for (const { pattern, providerName } of OPENAI_COMPAT_PATTERNS) {\n if (url.includes(pattern)) return { format: 'openai', name: providerName };\n }\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 ttfbMs?: number,\n providerName: string = 'anthropic'\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: providerName,\n },\n performance: { duration_ms: durationMs, ttfb_ms: ttfbMs },\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 = { ...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 ttfbMs?: number,\n providerName: string = 'openai'\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: providerName,\n },\n performance: { duration_ms: durationMs, ttfb_ms: ttfbMs },\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 = { ...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 /** Timestamp when the first content token was received (streaming). */\n firstTokenAt: number | null;\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 /** Timestamp when the first content token was received (streaming). */\n firstTokenAt: number | null;\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 firstTokenAt: null,\n };\n}\n\nfunction makeOpenAIState(): OpenAISSEState {\n return {\n model: '',\n textContent: '',\n toolCallMap: new Map(),\n finishReason: '',\n done: false,\n firstTokenAt: null,\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 if (state.firstTokenAt === null) state.firstTokenAt = Date.now();\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 if (state.firstTokenAt === null && delta.content.length > 0)\n state.firstTokenAt = Date.now();\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 ttfbMs?: number,\n timeToFirstTokenMs?: number,\n streamingDurationMs?: number,\n providerName: string = 'anthropic'\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: providerName },\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 ttfb_ms: ttfbMs,\n time_to_first_token_ms: timeToFirstTokenMs,\n streaming_duration_ms: streamingDurationMs,\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 ttfbMs?: number,\n timeToFirstTokenMs?: number,\n streamingDurationMs?: number,\n providerName: string = 'openai'\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: providerName },\n response: {\n text: state.textContent || undefined,\n finish_reason: state.finishReason || undefined,\n },\n performance: {\n duration_ms: durationMs,\n ttfb_ms: ttfbMs,\n time_to_first_token_ms: timeToFirstTokenMs,\n streaming_duration_ms: streamingDurationMs,\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 // 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: DetectedProvider,\n reqBody: Record<string, unknown>,\n startTime: number,\n ttfbMs: number\n): Response {\n const body = response.body;\n if (!body) return response;\n\n const decoder = new TextDecoder();\n const state = provider.format === '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.format === '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.format === '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 endTime = Date.now();\n const durationMs = endTime - startTime;\n const firstTokenAt = state.firstTokenAt;\n const timeToFirstTokenMs = firstTokenAt ? firstTokenAt - startTime : undefined;\n const streamingDurationMs = firstTokenAt ? endTime - firstTokenAt : undefined;\n\n const tracePayload =\n provider.format === 'anthropic'\n ? buildAnthropicStreamTrace(\n reqBody,\n state as AnthropicSSEState,\n durationMs,\n ttfbMs,\n timeToFirstTokenMs,\n streamingDurationMs,\n provider.name\n )\n : buildOpenAIStreamTrace(\n reqBody,\n state as OpenAISSEState,\n durationMs,\n ttfbMs,\n timeToFirstTokenMs,\n streamingDurationMs,\n provider.name\n );\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 const ttfbMs = Date.now() - startTime;\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, ttfbMs);\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.format === 'anthropic'\n ? extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, provider.name)\n : extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, provider.name);\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","/**\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"],"mappings":"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","names":["init"]}
|
package/dist/auto.js
CHANGED
|
@@ -331,6 +331,20 @@ function isInitialized() {
|
|
|
331
331
|
// src/auto.ts
|
|
332
332
|
var ANTHROPIC_PATTERN = "api.anthropic.com/v1/messages";
|
|
333
333
|
var OPENAI_PATTERN = "api.openai.com/v1/chat/completions";
|
|
334
|
+
var OPENAI_COMPAT_PATTERNS = [
|
|
335
|
+
{ pattern: "api.groq.com/", providerName: "groq" },
|
|
336
|
+
{ pattern: "api.together.xyz/", providerName: "together" },
|
|
337
|
+
{ pattern: "api.mistral.ai/", providerName: "mistral" },
|
|
338
|
+
{ pattern: "api.fireworks.ai/", providerName: "fireworks" },
|
|
339
|
+
{ pattern: "api.perplexity.ai/", providerName: "perplexity" },
|
|
340
|
+
{ pattern: "api.deepseek.com/", providerName: "deepseek" },
|
|
341
|
+
{ pattern: "openrouter.ai/api/", providerName: "openrouter" },
|
|
342
|
+
// Azure OpenAI: https://{resource}.openai.azure.com/openai/deployments/{model}/chat/completions
|
|
343
|
+
{ pattern: "openai.azure.com/openai/deployments/", providerName: "azure_openai" },
|
|
344
|
+
// Local Ollama (OpenAI-compatible mode)
|
|
345
|
+
{ pattern: "localhost:11434/", providerName: "ollama" },
|
|
346
|
+
{ pattern: "127.0.0.1:11434/", providerName: "ollama" }
|
|
347
|
+
];
|
|
334
348
|
var _originalFetch = null;
|
|
335
349
|
var _installed = false;
|
|
336
350
|
var _sessionId = null;
|
|
@@ -346,8 +360,11 @@ function readEnvVar(name) {
|
|
|
346
360
|
return void 0;
|
|
347
361
|
}
|
|
348
362
|
function detectProvider(url) {
|
|
349
|
-
if (url.includes(ANTHROPIC_PATTERN)) return "anthropic";
|
|
350
|
-
if (url.includes(OPENAI_PATTERN)) return "openai";
|
|
363
|
+
if (url.includes(ANTHROPIC_PATTERN)) return { format: "anthropic", name: "anthropic" };
|
|
364
|
+
if (url.includes(OPENAI_PATTERN)) return { format: "openai", name: "openai" };
|
|
365
|
+
for (const { pattern, providerName } of OPENAI_COMPAT_PATTERNS) {
|
|
366
|
+
if (url.includes(pattern)) return { format: "openai", name: providerName };
|
|
367
|
+
}
|
|
351
368
|
return null;
|
|
352
369
|
}
|
|
353
370
|
function resolveUrl(input) {
|
|
@@ -378,7 +395,7 @@ function extractLastUserMessage(messages) {
|
|
|
378
395
|
}
|
|
379
396
|
return "";
|
|
380
397
|
}
|
|
381
|
-
function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
398
|
+
function extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, providerName = "anthropic") {
|
|
382
399
|
const messages = reqBody.messages ?? [];
|
|
383
400
|
const userMsg = extractLastUserMessage(messages);
|
|
384
401
|
const systemMsg = typeof reqBody.system === "string" ? reqBody.system : "";
|
|
@@ -386,9 +403,9 @@ function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
|
386
403
|
input: { user_message: userMsg },
|
|
387
404
|
model: {
|
|
388
405
|
name: resBody.model ?? reqBody.model ?? "unknown",
|
|
389
|
-
provider:
|
|
406
|
+
provider: providerName
|
|
390
407
|
},
|
|
391
|
-
performance: { duration_ms: durationMs }
|
|
408
|
+
performance: { duration_ms: durationMs, ttfb_ms: ttfbMs }
|
|
392
409
|
};
|
|
393
410
|
const prompt = {};
|
|
394
411
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -419,13 +436,13 @@ function extractAnthropicTrace(reqBody, resBody, durationMs) {
|
|
|
419
436
|
if (total > 0) {
|
|
420
437
|
payload.response = { ...payload.response, tokens_used: total };
|
|
421
438
|
}
|
|
422
|
-
payload.performance = { duration_ms: durationMs };
|
|
439
|
+
payload.performance = { ...payload.performance, duration_ms: durationMs };
|
|
423
440
|
if (inputTokens) payload.performance.tokens_input = inputTokens;
|
|
424
441
|
if (outputTokens) payload.performance.tokens_output = outputTokens;
|
|
425
442
|
}
|
|
426
443
|
return payload;
|
|
427
444
|
}
|
|
428
|
-
function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
445
|
+
function extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, providerName = "openai") {
|
|
429
446
|
const messages = reqBody.messages ?? [];
|
|
430
447
|
let systemMsg = "";
|
|
431
448
|
let userMsg = "";
|
|
@@ -439,9 +456,9 @@ function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
|
439
456
|
input: { user_message: userMsg },
|
|
440
457
|
model: {
|
|
441
458
|
name: resBody.model ?? reqBody.model ?? "unknown",
|
|
442
|
-
provider:
|
|
459
|
+
provider: providerName
|
|
443
460
|
},
|
|
444
|
-
performance: { duration_ms: durationMs }
|
|
461
|
+
performance: { duration_ms: durationMs, ttfb_ms: ttfbMs }
|
|
445
462
|
};
|
|
446
463
|
const prompt = {};
|
|
447
464
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -483,7 +500,7 @@ function extractOpenAITrace(reqBody, resBody, durationMs) {
|
|
|
483
500
|
if (total > 0) {
|
|
484
501
|
payload.response = { ...payload.response, tokens_used: total };
|
|
485
502
|
}
|
|
486
|
-
payload.performance = { duration_ms: durationMs };
|
|
503
|
+
payload.performance = { ...payload.performance, duration_ms: durationMs };
|
|
487
504
|
if (promptTokens) payload.performance.tokens_input = promptTokens;
|
|
488
505
|
if (completionTokens) payload.performance.tokens_output = completionTokens;
|
|
489
506
|
}
|
|
@@ -499,7 +516,8 @@ function makeAnthropicState() {
|
|
|
499
516
|
toolCalls: [],
|
|
500
517
|
currentToolName: "",
|
|
501
518
|
currentToolArgs: "",
|
|
502
|
-
done: false
|
|
519
|
+
done: false,
|
|
520
|
+
firstTokenAt: null
|
|
503
521
|
};
|
|
504
522
|
}
|
|
505
523
|
function makeOpenAIState() {
|
|
@@ -508,7 +526,8 @@ function makeOpenAIState() {
|
|
|
508
526
|
textContent: "",
|
|
509
527
|
toolCallMap: /* @__PURE__ */ new Map(),
|
|
510
528
|
finishReason: "",
|
|
511
|
-
done: false
|
|
529
|
+
done: false,
|
|
530
|
+
firstTokenAt: null
|
|
512
531
|
};
|
|
513
532
|
}
|
|
514
533
|
function processAnthropicSSE(line, state) {
|
|
@@ -537,6 +556,7 @@ function processAnthropicSSE(line, state) {
|
|
|
537
556
|
case "content_block_delta": {
|
|
538
557
|
const delta = event.delta;
|
|
539
558
|
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
559
|
+
if (state.firstTokenAt === null) state.firstTokenAt = Date.now();
|
|
540
560
|
state.textContent += delta.text;
|
|
541
561
|
}
|
|
542
562
|
if (delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
@@ -592,6 +612,8 @@ function processOpenAISSE(line, state) {
|
|
|
592
612
|
const delta = choice.delta;
|
|
593
613
|
if (delta) {
|
|
594
614
|
if (typeof delta.content === "string") {
|
|
615
|
+
if (state.firstTokenAt === null && delta.content.length > 0)
|
|
616
|
+
state.firstTokenAt = Date.now();
|
|
595
617
|
state.textContent += delta.content;
|
|
596
618
|
}
|
|
597
619
|
if (typeof choice.finish_reason === "string") {
|
|
@@ -619,14 +641,14 @@ function processOpenAISSE(line, state) {
|
|
|
619
641
|
} catch {
|
|
620
642
|
}
|
|
621
643
|
}
|
|
622
|
-
function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
644
|
+
function buildAnthropicStreamTrace(reqBody, state, durationMs, ttfbMs, timeToFirstTokenMs, streamingDurationMs, providerName = "anthropic") {
|
|
623
645
|
const messages = reqBody.messages ?? [];
|
|
624
646
|
const userMsg = extractLastUserMessage(messages);
|
|
625
647
|
const systemMsg = typeof reqBody.system === "string" ? reqBody.system : "";
|
|
626
648
|
const total = state.inputTokens + state.outputTokens;
|
|
627
649
|
const payload = {
|
|
628
650
|
input: { user_message: userMsg },
|
|
629
|
-
model: { name: state.model || reqBody.model || "unknown", provider:
|
|
651
|
+
model: { name: state.model || reqBody.model || "unknown", provider: providerName },
|
|
630
652
|
response: {
|
|
631
653
|
text: state.textContent,
|
|
632
654
|
finish_reason: state.stopReason || void 0,
|
|
@@ -634,6 +656,9 @@ function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
|
634
656
|
},
|
|
635
657
|
performance: {
|
|
636
658
|
duration_ms: durationMs,
|
|
659
|
+
ttfb_ms: ttfbMs,
|
|
660
|
+
time_to_first_token_ms: timeToFirstTokenMs,
|
|
661
|
+
streaming_duration_ms: streamingDurationMs,
|
|
637
662
|
tokens_input: state.inputTokens || void 0,
|
|
638
663
|
tokens_output: state.outputTokens || void 0
|
|
639
664
|
}
|
|
@@ -645,7 +670,7 @@ function buildAnthropicStreamTrace(reqBody, state, durationMs) {
|
|
|
645
670
|
if (state.toolCalls.length > 0) payload.tool_calls = state.toolCalls;
|
|
646
671
|
return payload;
|
|
647
672
|
}
|
|
648
|
-
function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
673
|
+
function buildOpenAIStreamTrace(reqBody, state, durationMs, ttfbMs, timeToFirstTokenMs, streamingDurationMs, providerName = "openai") {
|
|
649
674
|
const messages = reqBody.messages ?? [];
|
|
650
675
|
let systemMsg = "";
|
|
651
676
|
for (const msg of messages) {
|
|
@@ -657,12 +682,17 @@ function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
|
657
682
|
const userMsg = extractLastUserMessage(messages);
|
|
658
683
|
const payload = {
|
|
659
684
|
input: { user_message: userMsg },
|
|
660
|
-
model: { name: state.model || reqBody.model || "unknown", provider:
|
|
685
|
+
model: { name: state.model || reqBody.model || "unknown", provider: providerName },
|
|
661
686
|
response: {
|
|
662
687
|
text: state.textContent || void 0,
|
|
663
688
|
finish_reason: state.finishReason || void 0
|
|
664
689
|
},
|
|
665
|
-
performance: {
|
|
690
|
+
performance: {
|
|
691
|
+
duration_ms: durationMs,
|
|
692
|
+
ttfb_ms: ttfbMs,
|
|
693
|
+
time_to_first_token_ms: timeToFirstTokenMs,
|
|
694
|
+
streaming_duration_ms: streamingDurationMs
|
|
695
|
+
}
|
|
666
696
|
};
|
|
667
697
|
const prompt = {};
|
|
668
698
|
if (systemMsg) prompt.system = systemMsg;
|
|
@@ -683,11 +713,11 @@ function buildOpenAIStreamTrace(reqBody, state, durationMs) {
|
|
|
683
713
|
}
|
|
684
714
|
return payload;
|
|
685
715
|
}
|
|
686
|
-
function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
716
|
+
function wrapStreamingResponse(response, provider, reqBody, startTime, ttfbMs) {
|
|
687
717
|
const body = response.body;
|
|
688
718
|
if (!body) return response;
|
|
689
719
|
const decoder = new TextDecoder();
|
|
690
|
-
const state = provider === "anthropic" ? makeAnthropicState() : makeOpenAIState();
|
|
720
|
+
const state = provider.format === "anthropic" ? makeAnthropicState() : makeOpenAIState();
|
|
691
721
|
let buffer = "";
|
|
692
722
|
const transformedStream = new ReadableStream({
|
|
693
723
|
async start(controller) {
|
|
@@ -703,7 +733,7 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
703
733
|
for (const line of lines) {
|
|
704
734
|
const trimmed = line.trim();
|
|
705
735
|
if (!trimmed) continue;
|
|
706
|
-
if (provider === "anthropic") {
|
|
736
|
+
if (provider.format === "anthropic") {
|
|
707
737
|
processAnthropicSSE(trimmed, state);
|
|
708
738
|
} else {
|
|
709
739
|
processOpenAISSE(trimmed, state);
|
|
@@ -711,7 +741,7 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
711
741
|
}
|
|
712
742
|
}
|
|
713
743
|
if (buffer.trim()) {
|
|
714
|
-
if (provider === "anthropic") {
|
|
744
|
+
if (provider.format === "anthropic") {
|
|
715
745
|
processAnthropicSSE(buffer.trim(), state);
|
|
716
746
|
} else {
|
|
717
747
|
processOpenAISSE(buffer.trim(), state);
|
|
@@ -719,8 +749,28 @@ function wrapStreamingResponse(response, provider, reqBody, startTime) {
|
|
|
719
749
|
}
|
|
720
750
|
state.done = true;
|
|
721
751
|
try {
|
|
722
|
-
const
|
|
723
|
-
const
|
|
752
|
+
const endTime = Date.now();
|
|
753
|
+
const durationMs = endTime - startTime;
|
|
754
|
+
const firstTokenAt = state.firstTokenAt;
|
|
755
|
+
const timeToFirstTokenMs = firstTokenAt ? firstTokenAt - startTime : void 0;
|
|
756
|
+
const streamingDurationMs = firstTokenAt ? endTime - firstTokenAt : void 0;
|
|
757
|
+
const tracePayload = provider.format === "anthropic" ? buildAnthropicStreamTrace(
|
|
758
|
+
reqBody,
|
|
759
|
+
state,
|
|
760
|
+
durationMs,
|
|
761
|
+
ttfbMs,
|
|
762
|
+
timeToFirstTokenMs,
|
|
763
|
+
streamingDurationMs,
|
|
764
|
+
provider.name
|
|
765
|
+
) : buildOpenAIStreamTrace(
|
|
766
|
+
reqBody,
|
|
767
|
+
state,
|
|
768
|
+
durationMs,
|
|
769
|
+
ttfbMs,
|
|
770
|
+
timeToFirstTokenMs,
|
|
771
|
+
streamingDurationMs,
|
|
772
|
+
provider.name
|
|
773
|
+
);
|
|
724
774
|
const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;
|
|
725
775
|
const traceType = hasToolCalls ? "tool_use" : "chat";
|
|
726
776
|
if (isInitialized()) {
|
|
@@ -763,10 +813,11 @@ async function patchedFetch(input, init2) {
|
|
|
763
813
|
}
|
|
764
814
|
try {
|
|
765
815
|
const response = await _originalFetch(input, init2);
|
|
816
|
+
const ttfbMs = Date.now() - startTime;
|
|
766
817
|
const isStreaming = reqBody?.stream === true;
|
|
767
818
|
if (isStreaming && reqBody) {
|
|
768
819
|
try {
|
|
769
|
-
return wrapStreamingResponse(response, provider, reqBody, startTime);
|
|
820
|
+
return wrapStreamingResponse(response, provider, reqBody, startTime, ttfbMs);
|
|
770
821
|
} catch {
|
|
771
822
|
return response;
|
|
772
823
|
}
|
|
@@ -776,7 +827,7 @@ async function patchedFetch(input, init2) {
|
|
|
776
827
|
const clone = response.clone();
|
|
777
828
|
const resBody = await clone.json();
|
|
778
829
|
const durationMs = Date.now() - startTime;
|
|
779
|
-
const tracePayload = provider === "anthropic" ? extractAnthropicTrace(reqBody, resBody, durationMs) : extractOpenAITrace(reqBody, resBody, durationMs);
|
|
830
|
+
const tracePayload = provider.format === "anthropic" ? extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, provider.name) : extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, provider.name);
|
|
780
831
|
const hasToolCalls = (tracePayload.tool_calls?.length ?? 0) > 0;
|
|
781
832
|
const traceType = hasToolCalls ? "tool_use" : "chat";
|
|
782
833
|
if (isInitialized()) {
|
package/dist/auto.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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\n/**\n * OpenAI-compatible providers that use the same SSE / response format.\n * Each entry maps a URL substring to the provider label stored in the trace.\n */\nconst OPENAI_COMPAT_PATTERNS: Array<{ pattern: string; providerName: string }> = [\n { pattern: 'api.groq.com/', providerName: 'groq' },\n { pattern: 'api.together.xyz/', providerName: 'together' },\n { pattern: 'api.mistral.ai/', providerName: 'mistral' },\n { pattern: 'api.fireworks.ai/', providerName: 'fireworks' },\n { pattern: 'api.perplexity.ai/', providerName: 'perplexity' },\n { pattern: 'api.deepseek.com/', providerName: 'deepseek' },\n { pattern: 'openrouter.ai/api/', providerName: 'openrouter' },\n // Azure OpenAI: https://{resource}.openai.azure.com/openai/deployments/{model}/chat/completions\n { pattern: 'openai.azure.com/openai/deployments/', providerName: 'azure_openai' },\n // Local Ollama (OpenAI-compatible mode)\n { pattern: 'localhost:11434/', providerName: 'ollama' },\n { pattern: '127.0.0.1:11434/', providerName: 'ollama' },\n];\n\n/** Protocol-level format: Anthropic Messages vs OpenAI Chat Completions. */\ntype ProviderFormat = 'anthropic' | 'openai';\n\n/** Detected provider info: wire format + label for the trace. */\ninterface DetectedProvider {\n format: ProviderFormat;\n name: string;\n}\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): DetectedProvider | null {\n if (url.includes(ANTHROPIC_PATTERN)) return { format: 'anthropic', name: 'anthropic' };\n if (url.includes(OPENAI_PATTERN)) return { format: 'openai', name: 'openai' };\n // OpenAI-compatible providers (Groq, Together, Mistral, Azure, Ollama, etc.)\n for (const { pattern, providerName } of OPENAI_COMPAT_PATTERNS) {\n if (url.includes(pattern)) return { format: 'openai', name: providerName };\n }\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 ttfbMs?: number,\n providerName: string = 'anthropic'\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: providerName,\n },\n performance: { duration_ms: durationMs, ttfb_ms: ttfbMs },\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 = { ...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 ttfbMs?: number,\n providerName: string = 'openai'\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: providerName,\n },\n performance: { duration_ms: durationMs, ttfb_ms: ttfbMs },\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 = { ...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 /** Timestamp when the first content token was received (streaming). */\n firstTokenAt: number | null;\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 /** Timestamp when the first content token was received (streaming). */\n firstTokenAt: number | null;\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 firstTokenAt: null,\n };\n}\n\nfunction makeOpenAIState(): OpenAISSEState {\n return {\n model: '',\n textContent: '',\n toolCallMap: new Map(),\n finishReason: '',\n done: false,\n firstTokenAt: null,\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 if (state.firstTokenAt === null) state.firstTokenAt = Date.now();\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 if (state.firstTokenAt === null && delta.content.length > 0)\n state.firstTokenAt = Date.now();\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 ttfbMs?: number,\n timeToFirstTokenMs?: number,\n streamingDurationMs?: number,\n providerName: string = 'anthropic'\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: providerName },\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 ttfb_ms: ttfbMs,\n time_to_first_token_ms: timeToFirstTokenMs,\n streaming_duration_ms: streamingDurationMs,\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 ttfbMs?: number,\n timeToFirstTokenMs?: number,\n streamingDurationMs?: number,\n providerName: string = 'openai'\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: providerName },\n response: {\n text: state.textContent || undefined,\n finish_reason: state.finishReason || undefined,\n },\n performance: {\n duration_ms: durationMs,\n ttfb_ms: ttfbMs,\n time_to_first_token_ms: timeToFirstTokenMs,\n streaming_duration_ms: streamingDurationMs,\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 // 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: DetectedProvider,\n reqBody: Record<string, unknown>,\n startTime: number,\n ttfbMs: number\n): Response {\n const body = response.body;\n if (!body) return response;\n\n const decoder = new TextDecoder();\n const state = provider.format === '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.format === '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.format === '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 endTime = Date.now();\n const durationMs = endTime - startTime;\n const firstTokenAt = state.firstTokenAt;\n const timeToFirstTokenMs = firstTokenAt ? firstTokenAt - startTime : undefined;\n const streamingDurationMs = firstTokenAt ? endTime - firstTokenAt : undefined;\n\n const tracePayload =\n provider.format === 'anthropic'\n ? buildAnthropicStreamTrace(\n reqBody,\n state as AnthropicSSEState,\n durationMs,\n ttfbMs,\n timeToFirstTokenMs,\n streamingDurationMs,\n provider.name\n )\n : buildOpenAIStreamTrace(\n reqBody,\n state as OpenAISSEState,\n durationMs,\n ttfbMs,\n timeToFirstTokenMs,\n streamingDurationMs,\n provider.name\n );\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 const ttfbMs = Date.now() - startTime;\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, ttfbMs);\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.format === 'anthropic'\n ? extractAnthropicTrace(reqBody, resBody, durationMs, ttfbMs, provider.name)\n : extractOpenAITrace(reqBody, resBody, durationMs, ttfbMs, provider.name);\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":";AASA,IAAM,QAAQ,CAAC,OACb,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAiB3C,IAAM,cAAN,MAAkB;AAAA,EACf,QAAyB,CAAC;AAAA,EAC1B,QAA+C;AAAA,EAC/C,WAAW;AAAA,EACX,UAAU;AAAA,EACD;AAAA,EACT,eAAoC;AAAA,EAE5C,YAAY,QAAsB;AAChC,SAAK,SAAS;AACd,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,OAA+B;AACrC,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,SAAS;AAC5C,WAAK,MAAM,MAAM;AAAA,IACnB;AACA,SAAK,MAAM,KAAK,KAAK;AACrB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,eAAuB;AACzB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAuB;AAC3B,QAAI,KAAK,YAAY,KAAK,MAAM,WAAW,EAAG;AAC9C,SAAK,WAAW;AAEhB,QAAI;AACF,aAAO,KAAK,MAAM,SAAS,GAAG;AAC5B,cAAM,QAAQ,KAAK,MAAM,OAAO,GAAG,KAAK,OAAO,SAAS;AACxD,cAAM,KAAK,UAAU,KAAK;AAAA,MAC5B;AAAA,IACF,UAAE;AACA,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAS,YAAY,KAAqB;AAC9C,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,UAAU;AAGf,QAAI,KAAK,UAAU,MAAM;AACvB,oBAAc,KAAK,KAAK;AACxB,WAAK,QAAQ;AAAA,IACf;AAGA,SAAK,mBAAmB;AAGxB,UAAM,eAAe,KAAK,MAAM;AAChC,UAAM,iBAAiB,MAAM,SAAS;AAEtC,UAAM,QAAQ,KAAK,CAAC,cAAc,cAAc,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAU,OAAuC;AAC7D,UAAM,MAAM,GAAG,KAAK,OAAO,QAAQ;AAInC,UAAM,aAAa,MAAM,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,MAAM,KAAK;AAE/D,aAAS,UAAU,GAAG,UAAU,KAAK,OAAO,YAAY,WAAW;AACjE,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,YAC3C,gBAAgB;AAAA,UAClB;AAAA,UACA,MAAM,KAAK,UAAU,UAAU;AAAA,QACjC,CAAC;AAED,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,gBAAM,WAAW,KAAK,aAAa,CAAC;AACpC,eAAK,OAAO,iBAAiB,OAAO,QAAQ;AAC5C;AAAA,QACF;AAEA,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,mBAAmB,SAAS,QAAQ,IAAI,aAAa;AAC3D,gBAAM,gBAAgB,mBAClB,SAAS,kBAAkB,EAAE,IAC7B,KAAK;AACT,gBAAM,MAAM,gBAAgB,GAAI;AAChC;AAAA,QACF;AAGA;AAAA,MACF,QAAQ;AAEN,cAAM,YAAY,KAAK,UAAU;AACjC,cAAM,MAAM,SAAS;AAAA,MACvB;AAAA,IACF;AAAA,EAGF;AAAA,EAEQ,QAAc;AACpB,SAAK,QAAQ,YAAY,MAAM;AAC7B,WAAK,KAAK,MAAM;AAAA,IAClB,GAAG,KAAK,OAAO,eAAe;AAE9B,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEQ,sBAA4B;AAClC,UAAM,UAAU,MAAY;AAC1B,WAAK,KAAK,SAAS;AAAA,IACrB;AAGA,UAAM,IAAI;AACV,QACE,OAAO,EAAE,WAAW,eACpB,OAAQ,EAAE,OAAmC,qBAC3C,YACF;AACA,YAAM,MAAM,EAAE;AAId,UAAI,iBAAiB,gBAAgB,OAAO;AAC5C,WAAK,eAAe,MAAM,IAAI,oBAAoB,gBAAgB,OAAO;AAAA,IAC3E,WACE,OAAO,YAAY,eACnB,OAAO,QAAQ,OAAO,YACtB;AAEA,cAAQ,GAAG,cAAc,OAAO;AAChC,WAAK,eAAe,MAAM,QAAQ,eAAe,cAAc,OAAO;AAAA,IACxE;AAAA,EACF;AAAA,EAEQ,qBAA2B;AACjC,SAAK,eAAe;AACpB,SAAK,eAAe;AAAA,EACtB;AACF;;;AC9KA,IAAM,mBACJ;AAaF,SAAS,cAAc,QAAwC;AAC7D,MAAI,CAAC,OAAO,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACxD,MAAI,CAAC,OAAO,QAAS,OAAM,IAAI,MAAM,qBAAqB;AAE1D,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO,YAAY,kBAAkB,QAAQ,QAAQ,EAAE;AAAA,IAClE,YAAY,OAAO,cAAc;AAAA,IACjC,WAAW,OAAO,aAAa;AAAA,IAC/B,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C,YAAY,OAAO,cAAc;AAAA,IACjC,SAAS,OAAO,WAAW;AAAA,EAC7B;AACF;AAEO,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA,EACA;AAAA,EACA,aAAkC,oBAAI,IAAI;AAAA,EACnD,eAAe;AAAA,EAEvB,YAAY,QAAwB;AAClC,SAAK,SAAS,cAAc,MAAM;AAElC,SAAK,SAAS,IAAI,YAAY;AAAA,MAC5B,UAAU,KAAK,OAAO;AAAA,MACtB,QAAQ,KAAK,OAAO;AAAA,MACpB,SAAS,KAAK,OAAO;AAAA,MACrB,WAAW,KAAK,OAAO;AAAA,MACvB,iBAAiB,KAAK,OAAO;AAAA,MAC7B,YAAY,KAAK,OAAO;AAAA,MACxB,gBAAgB,CAAC,OAAO,aACtB,KAAK,iBAAiB,OAAO,QAAQ;AAAA,IACzC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aACE,SACA,SACe;AACf,QAAI,CAAC,KAAK,OAAO,QAAS,QAAO;AAEjC,UAAM,WAAW,aAAa,EAAE,KAAK,YAAY;AAEjD,UAAM,WAA0B;AAAA,MAC9B,UAAU,KAAK,OAAO;AAAA,MACtB;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,WAAW;AAAA,IACb;AAEA,QAAI,SAAS,aAAa,MAAM;AAC9B,eAAS,aAAa,QAAQ;AAAA,IAChC;AACA,QAAI,SAAS,iBAAiB,MAAM;AAClC,eAAS,kBAAkB,QAAQ;AAAA,IACrC;AACA,QAAI,SAAS,aAAa,MAAM;AAC9B,eAAS,aAAa,QAAQ;AAAA,IAChC;AAEA,SAAK,OAAO,QAAQ,QAAQ;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WACJ,SACA,UACe;AACf,QAAI,CAAC,KAAK,OAAO,QAAS;AAE1B,QAAI,aAAa;AACjB,QAAI,QAAQ,WAAW,YAAY,GAAG;AACpC,YAAM,WAAW,KAAK,WAAW,IAAI,OAAO;AAC5C,UAAI,UAAU;AACZ,qBAAa;AAAA,MACf,OAAO;AACL,gBAAQ;AAAA,UACN,oBAAoB,OAAO;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,QAAQ;AACnC,QAAI;AACF,YAAM,MAAM,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,UAC3C,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,UAAU,YAAY,SAAS,CAAC;AAAA,MACzD,CAAC;AAAA,IACH,QAAQ;AACN,cAAQ,KAAK,8CAA8C,UAAU,EAAE;AAAA,IACzE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,iBACJ,SACsC;AACtC,QAAI,CAAC,KAAK,OAAO,QAAS,QAAO;AAEjC,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AACA,QAAI,QAAQ,SAAS,KAAK;AACxB,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAGA,UAAM,kBAAkB,QAAQ,IAAI,CAAC,UAAU;AAC7C,UAAI,aAAa,MAAM;AACvB,UAAI,MAAM,SAAS,WAAW,YAAY,GAAG;AAC3C,cAAM,WAAW,KAAK,WAAW,IAAI,MAAM,QAAQ;AACnD,YAAI,UAAU;AACZ,uBAAa;AAAA,QACf,OAAO;AACL,kBAAQ;AAAA,YACN,oBAAoB,MAAM,QAAQ;AAAA,UACpC;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,UAAU,YAAY,UAAU,MAAM,SAAS;AAAA,IAC1D,CAAC;AAED,UAAM,MAAM,GAAG,KAAK,OAAO,QAAQ;AACnC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,QAC3C,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,SAAS,gBAAgB,CAAC;AAAA,IACnD,CAAC;AAED,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,kBACJ,WACA,UACwC;AACxC,QAAI,CAAC,KAAK,OAAO,QAAS,QAAO;AAEjC,UAAM,MAAM,GAAG,KAAK,OAAO,QAAQ;AACnC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,QAC3C,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,YAAY,WAAW,SAAS,CAAC;AAAA,IAC1D,CAAC;AAED,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,WAAmC;AAChD,UAAM,KAAK,OAAO,SAAS,SAAS;AAAA,EACtC;AAAA;AAAA,EAGA,IAAI,eAAuB;AACzB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBACN,OACA,UACM;AACN,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,WAAW,MAAM,CAAC,EAAE;AAC1B,UAAI,YAAY,SAAS,CAAC,GAAG;AAC3B,aAAK,WAAW,IAAI,UAAU,SAAS,CAAC,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;;;ACnNA,IAAI,UAAiC;AAQ9B,SAAS,KAAK,QAA8B;AACjD,MAAI,YAAY,MAAM;AACpB,SAAK,QAAQ,SAAS;AAAA,EACxB;AACA,YAAU,IAAI,eAAe,MAAM;AACrC;AAQO,SAAS,aAAa,SAAuB,SAA8C;AAChG,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO,QAAQ,aAAa,SAAS,OAAO;AAC9C;AAmFO,SAAS,gBAAyB;AACvC,SAAO,YAAY;AACrB;;;AC5IA,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AAMvB,IAAM,yBAA2E;AAAA,EAC/E,EAAE,SAAS,iBAAiB,cAAc,OAAO;AAAA,EACjD,EAAE,SAAS,qBAAqB,cAAc,WAAW;AAAA,EACzD,EAAE,SAAS,mBAAmB,cAAc,UAAU;AAAA,EACtD,EAAE,SAAS,qBAAqB,cAAc,YAAY;AAAA,EAC1D,EAAE,SAAS,sBAAsB,cAAc,aAAa;AAAA,EAC5D,EAAE,SAAS,qBAAqB,cAAc,WAAW;AAAA,EACzD,EAAE,SAAS,sBAAsB,cAAc,aAAa;AAAA;AAAA,EAE5D,EAAE,SAAS,wCAAwC,cAAc,eAAe;AAAA;AAAA,EAEhF,EAAE,SAAS,oBAAoB,cAAc,SAAS;AAAA,EACtD,EAAE,SAAS,oBAAoB,cAAc,SAAS;AACxD;AAaA,IAAI,iBAAiD;AACrD,IAAI,aAAa;AACjB,IAAI,aAA4B;AAChC,IAAI,YAAY;AAIhB,SAAS,WAAW,MAAkC;AAEpD,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,SAAS,eAAe,EAAE,KAAK,KAAK,KAAK;AACpD,WAAO,EAAE,KAAK,IAAI,IAAI,IAAI;AAAA,EAC5B;AACA,MAAI,OAAO,EAAE,YAAY,eAAe,EAAE,QAAQ,KAAK;AACrD,WAAO,EAAE,QAAQ,IAAI,IAAI;AAAA,EAC3B;AAEA,SAAO;AACT;AAIA,SAAS,eAAe,KAAsC;AAC5D,MAAI,IAAI,SAAS,iBAAiB,EAAG,QAAO,EAAE,QAAQ,aAAa,MAAM,YAAY;AACrF,MAAI,IAAI,SAAS,cAAc,EAAG,QAAO,EAAE,QAAQ,UAAU,MAAM,SAAS;AAE5E,aAAW,EAAE,SAAS,aAAa,KAAK,wBAAwB;AAC9D,QAAI,IAAI,SAAS,OAAO,EAAG,QAAO,EAAE,QAAQ,UAAU,MAAM,aAAa;AAAA,EAC3E;AACA,SAAO;AACT;AAIA,SAAS,WAAW,OAAuC;AACzD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,iBAAiB,IAAK,QAAO,MAAM;AACvC,SAAO,MAAM;AACf;AAIA,SAAS,cAAcA,OAA+D;AACpF,MAAI,CAACA,OAAM,QAAQ,OAAOA,MAAK,SAAS,SAAU,QAAO;AACzD,MAAI;AACF,WAAO,KAAK,MAAMA,MAAK,IAAI;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,SAAS,uBAAuB,UAA6B;AAC3D,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAM,MAAM,SAAS,CAAC;AACtB,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,UAAU,IAAI;AACpB,QAAI,OAAO,YAAY,SAAU,QAAO;AACxC,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,iBAAW,SAAS,SAAS;AAC3B,cAAM,IAAI;AACV,YAAI,GAAG,SAAS,UAAU,OAAO,EAAE,SAAS,SAAU,QAAO,EAAE;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,sBACP,SACA,SACA,YACA,QACA,eAAuB,aACT;AACd,QAAM,WAAY,QAAQ,YAAY,CAAC;AACvC,QAAM,UAAU,uBAAuB,QAAQ;AAC/C,QAAM,YAAY,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AAExE,QAAM,UAAwB;AAAA,IAC5B,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,OAAO;AAAA,MACL,MAAO,QAAQ,SAAqB,QAAQ,SAAoB;AAAA,MAChE,UAAU;AAAA,IACZ;AAAA,IACA,aAAa,EAAE,aAAa,YAAY,SAAS,OAAO;AAAA,EAC1D;AAGA,QAAM,SAAiC,CAAC;AACxC,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,QAAS,QAAO,OAAO;AAC3B,MAAI,OAAO,UAAU,OAAO,KAAM,SAAQ,SAAS;AAGnD,QAAM,gBAAiB,QAAQ,WAAW,CAAC;AAC3C,QAAM,YAAwB,CAAC;AAE/B,aAAW,SAAS,eAAe;AACjC,QAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,YAAY,CAAC,QAAQ,UAAU,MAAM;AACtF,cAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,MAAM,MAAM,KAAK;AAAA,IAC7D;AACA,QAAI,MAAM,SAAS,YAAY;AAC7B,gBAAU,KAAK;AAAA,QACb,MAAO,MAAM,QAAmB;AAAA,QAChC,WAAY,MAAM,SAAqC;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,UAAU,SAAS,EAAG,SAAQ,aAAa;AAG/C,MAAI,OAAO,QAAQ,gBAAgB,UAAU;AAC3C,YAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,eAAe,QAAQ,YAAY;AAAA,EAC/E;AAGA,QAAM,QAAQ,QAAQ;AACtB,MAAI,OAAO;AACT,UAAM,cAAc,MAAM,gBAAgB;AAC1C,UAAM,eAAe,MAAM,iBAAiB;AAC5C,UAAM,QAAQ,cAAc;AAC5B,QAAI,QAAQ,GAAG;AACb,cAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,aAAa,MAAM;AAAA,IAC/D;AACA,YAAQ,cAAc,EAAE,GAAG,QAAQ,aAAa,aAAa,WAAW;AACxE,QAAI,YAAa,SAAQ,YAAY,eAAe;AACpD,QAAI,aAAc,SAAQ,YAAY,gBAAgB;AAAA,EACxD;AAEA,SAAO;AACT;AAIA,SAAS,mBACP,SACA,SACA,YACA,QACA,eAAuB,UACT;AACd,QAAM,WAAY,QAAQ,YAAY,CAAC;AAGvC,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,SAAS,YAAY,OAAO,IAAI,YAAY,UAAU;AAC5D,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF;AACA,YAAU,uBAAuB,QAAQ;AAEzC,QAAM,UAAwB;AAAA,IAC5B,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,OAAO;AAAA,MACL,MAAO,QAAQ,SAAqB,QAAQ,SAAoB;AAAA,MAChE,UAAU;AAAA,IACZ;AAAA,IACA,aAAa,EAAE,aAAa,YAAY,SAAS,OAAO;AAAA,EAC1D;AAGA,QAAM,SAAiC,CAAC;AACxC,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,QAAS,QAAO,OAAO;AAC3B,MAAI,OAAO,UAAU,OAAO,KAAM,SAAQ,SAAS;AAGnD,QAAM,UAAW,QAAQ,WAAW,CAAC;AACrC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,SAAS,QAAQ,CAAC;AACxB,UAAM,UAAU,OAAO;AACvB,QAAI,SAAS;AACX,UAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,gBAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,MAAM,QAAQ,QAAQ;AAAA,MAClE;AAGA,YAAM,eAAe,QAAQ;AAC7B,UAAI,gBAAgB,aAAa,SAAS,GAAG;AAC3C,gBAAQ,aAAa,aAAa,IAAI,CAAC,OAAO;AAC5C,gBAAM,KAAK,GAAG;AACd,gBAAM,QAAkB,EAAE,MAAO,IAAI,QAAmB,UAAU;AAClE,cAAI,OAAO,IAAI,cAAc,UAAU;AACrC,gBAAI;AACF,oBAAM,YAAY,KAAK,MAAM,GAAG,SAAS;AAAA,YAC3C,QAAQ;AACN,oBAAM,YAAY,EAAE,KAAK,GAAG,UAAU;AAAA,YACxC;AAAA,UACF;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,OAAO,OAAO,kBAAkB,UAAU;AAC5C,cAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,eAAe,OAAO,cAAc;AAAA,IAChF;AAAA,EACF;AAGA,QAAM,QAAQ,QAAQ;AACtB,MAAI,OAAO;AACT,UAAM,eAAe,MAAM,iBAAiB;AAC5C,UAAM,mBAAmB,MAAM,qBAAqB;AACpD,UAAM,QAAQ,MAAM,gBAAgB,eAAe;AACnD,QAAI,QAAQ,GAAG;AACb,cAAQ,WAAW,EAAE,GAAG,QAAQ,UAAU,aAAa,MAAM;AAAA,IAC/D;AACA,YAAQ,cAAc,EAAE,GAAG,QAAQ,aAAa,aAAa,WAAW;AACxE,QAAI,aAAc,SAAQ,YAAY,eAAe;AACrD,QAAI,iBAAkB,SAAQ,YAAY,gBAAgB;AAAA,EAC5D;AAEA,SAAO;AACT;AA4BA,SAAS,qBAAwC;AAC/C,SAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,WAAW,CAAC;AAAA,IACZ,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AACF;AAEA,SAAS,kBAAkC;AACzC,SAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa,oBAAI,IAAI;AAAA,IACrB,cAAc;AAAA,IACd,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AACF;AAIA,SAAS,oBAAoB,MAAc,OAAgC;AACzE,MAAI,CAAC,KAAK,WAAW,QAAQ,EAAG;AAChC,QAAM,OAAO,KAAK,MAAM,CAAC;AACzB,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,iBAAiB;AACpB,cAAM,MAAM,MAAM;AAClB,YAAI,KAAK;AACP,cAAI,OAAO,IAAI,UAAU,SAAU,OAAM,QAAQ,IAAI;AACrD,gBAAM,QAAQ,IAAI;AAClB,cAAI,OAAO,aAAc,OAAM,cAAc,MAAM;AAAA,QACrD;AACA;AAAA,MACF;AAAA,MACA,KAAK,uBAAuB;AAC1B,cAAM,QAAQ,MAAM;AACpB,YAAI,OAAO,SAAS,YAAY;AAC9B,gBAAM,kBAAmB,MAAM,QAAmB;AAClD,gBAAM,kBAAkB;AAAA,QAC1B;AACA;AAAA,MACF;AAAA,MACA,KAAK,uBAAuB;AAC1B,cAAM,QAAQ,MAAM;AACpB,YAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,SAAS,UAAU;AAClE,cAAI,MAAM,iBAAiB,KAAM,OAAM,eAAe,KAAK,IAAI;AAC/D,gBAAM,eAAe,MAAM;AAAA,QAC7B;AACA,YAAI,OAAO,SAAS,sBAAsB,OAAO,MAAM,iBAAiB,UAAU;AAChF,gBAAM,mBAAmB,MAAM;AAAA,QACjC;AACA;AAAA,MACF;AAAA,MACA,KAAK,sBAAsB;AACzB,YAAI,MAAM,iBAAiB;AACzB,gBAAM,KAAe,EAAE,MAAM,MAAM,gBAAgB;AACnD,cAAI,MAAM,iBAAiB;AACzB,gBAAI;AACF,iBAAG,YAAY,KAAK,MAAM,MAAM,eAAe;AAAA,YACjD,QAAQ;AACN,iBAAG,YAAY,EAAE,KAAK,MAAM,gBAAgB;AAAA,YAC9C;AAAA,UACF;AACA,gBAAM,UAAU,KAAK,EAAE;AACvB,gBAAM,kBAAkB;AACxB,gBAAM,kBAAkB;AAAA,QAC1B;AACA;AAAA,MACF;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,QAAQ,MAAM;AACpB,YAAI,OAAO,OAAO,gBAAgB,SAAU,OAAM,aAAa,MAAM;AACrE,cAAM,QAAQ,MAAM;AACpB,YAAI,OAAO,cAAe,OAAM,eAAe,MAAM;AACrD;AAAA,MACF;AAAA,MACA,KAAK;AACH,cAAM,OAAO;AACb;AAAA,IACJ;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,iBAAiB,MAAc,OAA6B;AACnE,MAAI,CAAC,KAAK,WAAW,QAAQ,EAAG;AAChC,QAAM,OAAO,KAAK,MAAM,CAAC,EAAE,KAAK;AAChC,MAAI,SAAS,UAAU;AACrB,UAAM,OAAO;AACb;AAAA,EACF;AACA,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,QAAI,OAAO,MAAM,UAAU,YAAY,CAAC,MAAM,OAAO;AACnD,YAAM,QAAQ,MAAM;AAAA,IACtB;AACA,UAAM,UAAW,MAAM,WAAW,CAAC;AACnC,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,SAAS,QAAQ,CAAC;AACxB,YAAM,QAAQ,OAAO;AACrB,UAAI,OAAO;AACT,YAAI,OAAO,MAAM,YAAY,UAAU;AACrC,cAAI,MAAM,iBAAiB,QAAQ,MAAM,QAAQ,SAAS;AACxD,kBAAM,eAAe,KAAK,IAAI;AAChC,gBAAM,eAAe,MAAM;AAAA,QAC7B;AACA,YAAI,OAAO,OAAO,kBAAkB,UAAU;AAC5C,gBAAM,eAAe,OAAO;AAAA,QAC9B;AAEA,cAAM,iBAAiB,MAAM;AAC7B,YAAI,gBAAgB;AAClB,qBAAW,OAAO,gBAAgB;AAChC,kBAAM,MAAO,IAAI,SAAoB;AACrC,kBAAM,WAAW,MAAM,YAAY,IAAI,GAAG;AAC1C,kBAAM,KAAK,IAAI;AACf,gBAAI,CAAC,UAAU;AACb,oBAAM,YAAY,IAAI,KAAK;AAAA,gBACzB,MAAO,IAAI,QAAmB;AAAA,gBAC9B,cAAe,IAAI,aAAwB;AAAA,cAC7C,CAAC;AAAA,YACH,OAAO;AACL,kBAAI,IAAI,KAAM,UAAS,QAAQ,GAAG;AAClC,kBAAI,IAAI,UAAW,UAAS,gBAAgB,GAAG;AAAA,YACjD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAIA,SAAS,0BACP,SACA,OACA,YACA,QACA,oBACA,qBACA,eAAuB,aACT;AACd,QAAM,WAAY,QAAQ,YAAY,CAAC;AACvC,QAAM,UAAU,uBAAuB,QAAQ;AAC/C,QAAM,YAAY,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AACxE,QAAM,QAAQ,MAAM,cAAc,MAAM;AAExC,QAAM,UAAwB;AAAA,IAC5B,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,OAAO,EAAE,MAAM,MAAM,SAAU,QAAQ,SAAoB,WAAW,UAAU,aAAa;AAAA,IAC7F,UAAU;AAAA,MACR,MAAM,MAAM;AAAA,MACZ,eAAe,MAAM,cAAc;AAAA,MACnC,aAAa,QAAQ,IAAI,QAAQ;AAAA,IACnC;AAAA,IACA,aAAa;AAAA,MACX,aAAa;AAAA,MACb,SAAS;AAAA,MACT,wBAAwB;AAAA,MACxB,uBAAuB;AAAA,MACvB,cAAc,MAAM,eAAe;AAAA,MACnC,eAAe,MAAM,gBAAgB;AAAA,IACvC;AAAA,EACF;AAEA,QAAM,SAAiC,CAAC;AACxC,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,QAAS,QAAO,OAAO;AAC3B,MAAI,OAAO,UAAU,OAAO,KAAM,SAAQ,SAAS;AAEnD,MAAI,MAAM,UAAU,SAAS,EAAG,SAAQ,aAAa,MAAM;AAE3D,SAAO;AACT;AAEA,SAAS,uBACP,SACA,OACA,YACA,QACA,oBACA,qBACA,eAAuB,UACT;AACd,QAAM,WAAY,QAAQ,YAAY,CAAC;AACvC,MAAI,YAAY;AAChB,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,SAAS,YAAY,OAAO,IAAI,YAAY,UAAU;AAC5D,kBAAY,IAAI;AAChB;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,uBAAuB,QAAQ;AAE/C,QAAM,UAAwB;AAAA,IAC5B,OAAO,EAAE,cAAc,QAAQ;AAAA,IAC/B,OAAO,EAAE,MAAM,MAAM,SAAU,QAAQ,SAAoB,WAAW,UAAU,aAAa;AAAA,IAC7F,UAAU;AAAA,MACR,MAAM,MAAM,eAAe;AAAA,MAC3B,eAAe,MAAM,gBAAgB;AAAA,IACvC;AAAA,IACA,aAAa;AAAA,MACX,aAAa;AAAA,MACb,SAAS;AAAA,MACT,wBAAwB;AAAA,MACxB,uBAAuB;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,SAAiC,CAAC;AACxC,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,QAAS,QAAO,OAAO;AAC3B,MAAI,OAAO,UAAU,OAAO,KAAM,SAAQ,SAAS;AAGnD,MAAI,MAAM,YAAY,OAAO,GAAG;AAC9B,YAAQ,aAAa,MAAM,KAAK,MAAM,YAAY,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO;AACtE,YAAM,QAAkB,EAAE,MAAM,GAAG,KAAK;AACxC,UAAI,GAAG,cAAc;AACnB,YAAI;AACF,gBAAM,YAAY,KAAK,MAAM,GAAG,YAAY;AAAA,QAC9C,QAAQ;AACN,gBAAM,YAAY,EAAE,KAAK,GAAG,aAAa;AAAA,QAC3C;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAIA,SAAS,sBACP,UACA,UACA,SACA,WACA,QACU;AACV,QAAM,OAAO,SAAS;AACtB,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,QAAQ,SAAS,WAAW,cAAc,mBAAmB,IAAI,gBAAgB;AACvF,MAAI,SAAS;AAEb,QAAM,oBAAoB,IAAI,eAA2B;AAAA,IACvD,MAAM,MAAM,YAAY;AACtB,YAAM,SAAS,KAAK,UAAU;AAC9B,UAAI;AACF,mBAAS;AACP,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,cAAI,KAAM;AAGV,qBAAW,QAAQ,KAAK;AAGxB,oBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,gBAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,mBAAS,MAAM,IAAI,KAAK;AAExB,qBAAW,QAAQ,OAAO;AACxB,kBAAM,UAAU,KAAK,KAAK;AAC1B,gBAAI,CAAC,QAAS;AACd,gBAAI,SAAS,WAAW,aAAa;AACnC,kCAAoB,SAAS,KAA0B;AAAA,YACzD,OAAO;AACL,+BAAiB,SAAS,KAAuB;AAAA,YACnD;AAAA,UACF;AAAA,QACF;AAGA,YAAI,OAAO,KAAK,GAAG;AACjB,cAAI,SAAS,WAAW,aAAa;AACnC,gCAAoB,OAAO,KAAK,GAAG,KAA0B;AAAA,UAC/D,OAAO;AACL,6BAAiB,OAAO,KAAK,GAAG,KAAuB;AAAA,UACzD;AAAA,QACF;AAGA,cAAM,OAAO;AACb,YAAI;AACF,gBAAM,UAAU,KAAK,IAAI;AACzB,gBAAM,aAAa,UAAU;AAC7B,gBAAM,eAAe,MAAM;AAC3B,gBAAM,qBAAqB,eAAe,eAAe,YAAY;AACrE,gBAAM,sBAAsB,eAAe,UAAU,eAAe;AAEpE,gBAAM,eACJ,SAAS,WAAW,cAChB;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS;AAAA,UACX,IACA;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS;AAAA,UACX;AAEN,gBAAM,gBAAgB,aAAa,YAAY,UAAU,KAAK;AAC9D,gBAAM,YAAuB,eAAe,aAAa;AAEzD,cAAI,cAAc,GAAG;AACnB,yBAAa,cAAc;AAAA,cACzB,WAAW,cAAc;AAAA,cACzB;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,QAAQ;AAAA,QAER;AAEA,mBAAW,MAAM;AAAA,MACnB,SAAS,KAAK;AACZ,mBAAW,MAAM,GAAG;AAAA,MACtB,UAAE;AACA,eAAO,YAAY;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS,mBAAmB;AAAA,IACrC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB,SAAS,SAAS;AAAA,EACpB,CAAC;AACH;AAIA,eAAe,aAAa,OAA+BA,OAAuC;AAEhG,MAAI,WAAW;AACb,WAAO,eAAgB,OAAOA,KAAI;AAAA,EACpC;AAEA,QAAM,MAAM,WAAW,KAAK;AAC5B,QAAM,WAAW,eAAe,GAAG;AAGnC,MAAI,CAAC,UAAU;AACb,WAAO,eAAgB,OAAOA,KAAI;AAAA,EACpC;AAEA,cAAY;AACZ,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,UAA0C;AAE9C,MAAI;AACF,cAAU,cAAcA,KAAI;AAAA,EAC9B,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,eAAgB,OAAOA,KAAI;AAClD,UAAM,SAAS,KAAK,IAAI,IAAI;AAG5B,UAAM,cAAc,SAAS,WAAW;AAExC,QAAI,eAAe,SAAS;AAC1B,UAAI;AACF,eAAO,sBAAsB,UAAU,UAAU,SAAS,WAAW,MAAM;AAAA,MAC7E,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,SAAS;AACX,UAAI;AACF,cAAM,QAAQ,SAAS,MAAM;AAC7B,cAAM,UAAW,MAAM,MAAM,KAAK;AAClC,cAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,cAAM,eACJ,SAAS,WAAW,cAChB,sBAAsB,SAAS,SAAS,YAAY,QAAQ,SAAS,IAAI,IACzE,mBAAmB,SAAS,SAAS,YAAY,QAAQ,SAAS,IAAI;AAE5E,cAAM,gBAAgB,aAAa,YAAY,UAAU,KAAK;AAC9D,cAAM,YAAuB,eAAe,aAAa;AAEzD,YAAI,cAAc,GAAG;AACnB,uBAAa,cAAc;AAAA,YACzB,WAAW,cAAc;AAAA,YACzB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO;AAAA,EACT,UAAE;AACA,gBAAY;AAAA,EACd;AACF;AASO,SAAS,QAAQ,SAA0E;AAChG,MAAI,WAAY;AAEhB,QAAM,SAAS,SAAS,UAAU,WAAW,kBAAkB;AAC/D,QAAM,UAAU,SAAS,WAAW,WAAW,mBAAmB;AAElE,MAAI,CAAC,cAAc,KAAK,UAAU,SAAS;AACzC,SAAK,EAAE,QAAQ,SAAS,UAAU,SAAS,SAAS,CAAC;AAAA,EACvD;AAEA,mBAAiB,WAAW;AAC5B,aAAW,QAAQ;AACnB,eAAa;AACf;AAKO,SAAS,YAAkB;AAChC,MAAI,CAAC,cAAc,CAAC,eAAgB;AACpC,aAAW,QAAQ;AACnB,mBAAiB;AACjB,eAAa;AACf;AAMO,SAAS,aAAa,IAAyB;AACpD,eAAa;AACf;AAGO,SAAS,mBAAyB;AACvC,MAAI,WAAY,WAAU;AAC1B,eAAa;AACf;AAGA,QAAQ;","names":["init"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -33,6 +33,12 @@ interface TraceDecision {
|
|
|
33
33
|
}
|
|
34
34
|
interface TracePerformance {
|
|
35
35
|
duration_ms?: number;
|
|
36
|
+
/** Time from fetch start until the HTTP response headers arrive (first byte). */
|
|
37
|
+
ttfb_ms?: number;
|
|
38
|
+
/** Time from fetch start until the first content token is emitted (streaming only). */
|
|
39
|
+
time_to_first_token_ms?: number;
|
|
40
|
+
/** Time from first content token to stream end (streaming only). */
|
|
41
|
+
streaming_duration_ms?: number;
|
|
36
42
|
tokens_input?: number;
|
|
37
43
|
tokens_output?: number;
|
|
38
44
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ interface TraceDecision {
|
|
|
33
33
|
}
|
|
34
34
|
interface TracePerformance {
|
|
35
35
|
duration_ms?: number;
|
|
36
|
+
/** Time from fetch start until the HTTP response headers arrive (first byte). */
|
|
37
|
+
ttfb_ms?: number;
|
|
38
|
+
/** Time from fetch start until the first content token is emitted (streaming only). */
|
|
39
|
+
time_to_first_token_ms?: number;
|
|
40
|
+
/** Time from first content token to stream end (streaming only). */
|
|
41
|
+
streaming_duration_ms?: number;
|
|
36
42
|
tokens_input?: number;
|
|
37
43
|
tokens_output?: number;
|
|
38
44
|
}
|