ironside 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ import type { IronsideClient, TraceHandle } from "../client.js";
2
+
3
+ // The Vercel AI SDK (`ai` package, v7) already wraps whichever underlying
4
+ // provider you configure and has its own first-class OTel telemetry hook
5
+ // (`telemetry: {...}` on generateText/streamText, stable as of v7 —
6
+ // experimental_telemetry is now a deprecated alias). That's the more
7
+ // durable integration point for full OTel users (M3's /v1/otel/traces
8
+ // endpoint accepts it directly), so this module does NOT monkey-patch AI
9
+ // SDK internals the way wrapOpenAI/wrapAnthropic patch their respective
10
+ // clients. Instead it's a thin recorder: call recordGenerateTextResult()
11
+ // with the object generateText()/streamText() already returned.
12
+ //
13
+ // Verified against ai@7.0.22: LanguageModelUsage uses camelCase
14
+ // inputTokens/outputTokens — a third naming vocabulary, distinct from both
15
+ // OpenAI's (prompt_tokens/completion_tokens or input_tokens/output_tokens
16
+ // depending on endpoint) and Anthropic's (input_tokens/output_tokens).
17
+
18
+ export interface RecordGenerateTextOptions {
19
+ trace?: TraceHandle;
20
+ /** Passed through to the generation's name; defaults to "ai.generateText". */
21
+ name?: string;
22
+ /** The `model` id string you passed to generateText/streamText, since the result object doesn't always echo it back verbatim. */
23
+ model?: string;
24
+ /** The `prompt`/`messages` you passed in, for the recorded input. */
25
+ input?: unknown;
26
+ /** Sampling parameters (temperature, maxOutputTokens, ...) you passed to generateText/streamText — this recorder doesn't intercept the call, so these aren't available on the result and must be passed through explicitly. */
27
+ modelParameters?: Record<string, string | number | boolean | null>;
28
+ }
29
+
30
+ interface LanguageModelUsageLike {
31
+ inputTokens?: number;
32
+ outputTokens?: number;
33
+ }
34
+
35
+ interface GenerateTextResultLike {
36
+ text?: string;
37
+ usage?: LanguageModelUsageLike;
38
+ }
39
+
40
+ /**
41
+ * Records a completed generateText()/streamText() result as a generation.
42
+ * Call after awaiting the result (or after a stream finishes and its
43
+ * `usage` promise/property resolves) — this does not intercept the call
44
+ * itself, since the AI SDK's own `telemetry` option is the recommended
45
+ * hook for that.
46
+ */
47
+ export function recordGenerateTextResult(
48
+ ironside: IronsideClient,
49
+ result: GenerateTextResultLike,
50
+ options: RecordGenerateTextOptions = {}
51
+ ): void {
52
+ const trace = options.trace ?? ironside.trace({ name: options.name ?? "ai.generateText" });
53
+ const generation = trace.generation({
54
+ name: options.name ?? "ai.generateText",
55
+ ...(options.model && { model: options.model }),
56
+ ...(options.modelParameters && { modelParameters: options.modelParameters }),
57
+ input: options.input
58
+ });
59
+
60
+ generation.end({
61
+ output: result.text,
62
+ ...(result.usage && {
63
+ usageDetails: {
64
+ ...(result.usage.inputTokens !== undefined && {
65
+ input_tokens: result.usage.inputTokens
66
+ }),
67
+ ...(result.usage.outputTokens !== undefined && {
68
+ output_tokens: result.usage.outputTokens
69
+ })
70
+ }
71
+ })
72
+ });
73
+ }