opik-vercel 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +46 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +1 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Opik Vercel AI SDK Integration
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/opik-vercel)
|
|
4
|
+
[](https://github.com/comet-ml/opik/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
Seamlessly integrate [Opik](https://www.comet.com/docs/opik/) observability with your [Vercel AI SDK](https://sdk.vercel.ai/docs) applications to trace, monitor, and debug your AI workflows.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🔍 **Comprehensive Tracing**: Automatically trace AI SDK calls and completions
|
|
11
|
+
- 📊 **Hierarchical Visualization**: View your AI execution as a structured trace with parent-child relationships
|
|
12
|
+
- 📝 **Detailed Metadata Capture**: Record model names, prompts, completions, token usage, and custom metadata
|
|
13
|
+
- 🚨 **Error Handling**: Capture and visualize errors in your AI API interactions
|
|
14
|
+
- 🏷️ **Custom Tagging**: Add custom tags to organize and filter your traces
|
|
15
|
+
- 🔄 **Streaming Support**: Full support for streamed completions and chat responses
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Node.js
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install opik-vercel ai @ai-sdk/openai @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Next.js
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install opik-vercel @vercel/otel @opentelemetry/api-logs @opentelemetry/instrumentation @opentelemetry/sdk-logs
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Requirements
|
|
32
|
+
|
|
33
|
+
- Node.js ≥ 18
|
|
34
|
+
- Vercel AI SDK (`ai` ≥ 3.0.0)
|
|
35
|
+
- Opik SDK (automatically installed as a peer dependency)
|
|
36
|
+
- OpenTelemetry packages (see installation commands above)
|
|
37
|
+
|
|
38
|
+
## Configuration
|
|
39
|
+
|
|
40
|
+
Set your environment variables:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
OPIK_API_KEY="<your-api-key>"
|
|
44
|
+
OPIK_URL_OVERRIDE="https://www.comet.com/opik/api" # Cloud version
|
|
45
|
+
OPIK_PROJECT_NAME="<custom-project-name>"
|
|
46
|
+
OPIK_WORKSPACE="<your-workspace>"
|
|
47
|
+
OPENAI_API_KEY="<your-openai-api-key>" # If using OpenAI models
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Node.js
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { openai } from "@ai-sdk/openai";
|
|
56
|
+
import { generateText } from "ai";
|
|
57
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
58
|
+
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
|
|
59
|
+
import { OpikExporter } from "opik-vercel";
|
|
60
|
+
|
|
61
|
+
const sdk = new NodeSDK({
|
|
62
|
+
traceExporter: new OpikExporter(),
|
|
63
|
+
instrumentations: [getNodeAutoInstrumentations()],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
sdk.start();
|
|
67
|
+
|
|
68
|
+
async function main() {
|
|
69
|
+
const result = await generateText({
|
|
70
|
+
model: openai("gpt-4o"),
|
|
71
|
+
maxTokens: 50,
|
|
72
|
+
prompt: "What is love?",
|
|
73
|
+
experimental_telemetry: OpikExporter.getSettings({
|
|
74
|
+
name: "opik-nodejs-example",
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
console.log(result.text);
|
|
79
|
+
|
|
80
|
+
await sdk.shutdown(); // Flushes the trace to Opik
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
main().catch(console.error);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Next.js
|
|
87
|
+
|
|
88
|
+
For Next.js applications, use the framework's built-in OpenTelemetry support:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// instrumentation.ts
|
|
92
|
+
import { registerOTel } from "@vercel/otel";
|
|
93
|
+
import { OpikExporter } from "opik-vercel";
|
|
94
|
+
|
|
95
|
+
export function register() {
|
|
96
|
+
registerOTel({
|
|
97
|
+
serviceName: "opik-vercel-ai-nextjs-example",
|
|
98
|
+
traceExporter: new OpikExporter(),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then use the AI SDK with telemetry enabled:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { openai } from "@ai-sdk/openai";
|
|
107
|
+
import { generateText } from "ai";
|
|
108
|
+
|
|
109
|
+
const result = await generateText({
|
|
110
|
+
model: openai("gpt-4o"),
|
|
111
|
+
prompt: "What is love?",
|
|
112
|
+
experimental_telemetry: { isEnabled: true },
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Advanced Configuration
|
|
117
|
+
|
|
118
|
+
### Custom Tags and Metadata
|
|
119
|
+
|
|
120
|
+
You can add custom tags and metadata to all traces generated by the OpikExporter:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const exporter = new OpikExporter({
|
|
124
|
+
// Optional: add custom tags to all traces
|
|
125
|
+
tags: ["production", "gpt-4o"],
|
|
126
|
+
// Optional: add custom metadata to all traces
|
|
127
|
+
metadata: {
|
|
128
|
+
environment: "production",
|
|
129
|
+
version: "1.0.0",
|
|
130
|
+
team: "ai-team",
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Tags are useful for filtering and grouping traces, while metadata adds additional context for debugging and analysis.
|
|
136
|
+
|
|
137
|
+
### Telemetry Settings
|
|
138
|
+
|
|
139
|
+
Use `OpikExporter.getSettings()` to configure telemetry for individual AI SDK calls:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const result = await generateText({
|
|
143
|
+
model: openai("gpt-4o"),
|
|
144
|
+
prompt: "Tell a joke",
|
|
145
|
+
experimental_telemetry: OpikExporter.getSettings({
|
|
146
|
+
name: "custom-trace-name",
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Or use the basic telemetry settings:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const result = await generateText({
|
|
155
|
+
model: openai("gpt-4o"),
|
|
156
|
+
prompt: "Tell a joke",
|
|
157
|
+
experimental_telemetry: { isEnabled: true },
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Viewing Traces
|
|
162
|
+
|
|
163
|
+
To view your traces:
|
|
164
|
+
|
|
165
|
+
1. Sign in to your [Comet account](https://www.comet.com/signin)
|
|
166
|
+
2. Navigate to the Opik section
|
|
167
|
+
3. Select your project to view all traces
|
|
168
|
+
4. Click on a specific trace to see the detailed execution flow
|
|
169
|
+
|
|
170
|
+
## Debugging
|
|
171
|
+
|
|
172
|
+
To enable more verbose logging for troubleshooting:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
OPIK_LOG_LEVEL=DEBUG
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Learn More
|
|
179
|
+
|
|
180
|
+
- [Opik Vercel AI SDK Integration Guide](https://www.comet.com/docs/opik/tracing/integrations/vercel-ai-sdk)
|
|
181
|
+
- [Opik Documentation](https://www.comet.com/docs/opik/)
|
|
182
|
+
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
|
|
183
|
+
- [Opik TypeScript SDK](https://github.com/comet-ml/opik/tree/main/sdks/typescript)
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
Apache 2.0
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var opik=require('opik');var E=new opik.Opik,f=class{constructor({client:e=E,tags:t=[],metadata:n={}}={}){this.traces=new Map;this.spans=new Map;this.getSpanInput=e=>{let t={},{attributes:n}=e;return Object.keys(n).forEach(o=>{if(o==="ai.prompt"||o==="gen_ai.request"){let a=C(n[o]);a&&(t={...t,...a});}if(o.startsWith("ai.prompt.")){let a=o.replace("ai.prompt.","");t[a]=m(n[o]);}if(o.startsWith("gen_ai.request.")){let a=o.replace("gen_ai.request.","");t[a]=m(n[o]);}}),Object.keys(t).length>0||("ai.toolCall.name"in n&&(t.toolName=n["ai.toolCall.name"]),"ai.toolCall.args"in n&&(t.args=n["ai.toolCall.args"])),t};this.getSpanOutput=e=>{let{attributes:t}=e;return t["ai.response.text"]?{text:t["ai.response.text"]}:t["ai.toolCall.result"]?{result:t["ai.toolCall.result"]}:t["ai.response.toolCalls"]?{toolCalls:m(t["ai.response.toolCalls"])}:{}};this.getSpanMetadata=e=>{let{attributes:t}=e,n={};return t["gen_ai.response.model"]&&(n.model=t["gen_ai.response.model"]),t["gen_ai.system"]&&(n.system=t["gen_ai.system"]),n};this.getSpanUsage=e=>{let{attributes:t}=e,n={};return "ai.usage.promptTokens"in t&&(n.prompt_tokens=t["ai.usage.promptTokens"]),"gen_ai.usage.input_tokens"in t&&(n.prompt_tokens=t["gen_ai.usage.input_tokens"]),"ai.usage.completionTokens"in t&&(n.completion_tokens=t["ai.usage.completionTokens"]),"gen_ai.usage.output_tokens"in t&&(n.completion_tokens=t["gen_ai.usage.output_tokens"]),("prompt_tokens"in n||"completion_tokens"in n)&&(n.total_tokens=(n.prompt_tokens||0)+(n.completion_tokens||0)),n};this.processSpan=({otelSpan:e,parentSpan:t,trace:n})=>n.span({name:e.name,startTime:new Date(l(e.startTime)),endTime:new Date(l(e.endTime)),parentSpanId:t==null?void 0:t.data.id,input:this.getSpanInput(e),output:this.getSpanOutput(e),metadata:this.getSpanMetadata(e),usage:this.getSpanUsage(e),type:"llm"});this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(e,t)=>{let n=e.filter(a=>a.instrumentationScope.name==="ai"),i=e.length-n.length;if(i>0&&opik.logger.debug(`Ignored ${i} non-AI SDK spans`),n.length===0){opik.logger.debug("No AI SDK spans found"),t({code:0});return}let o=w(n);opik.logger.debug("Exporting spans",n),Object.entries(o).forEach(([a,c])=>{var S,h;let[r,...u]=c,p=this.client.trace({startTime:new Date(l(r.startTime)),endTime:new Date(l(r.endTime)),name:(h=(S=r.attributes["ai.telemetry.metadata.traceName"])==null?void 0:S.toString())!=null?h:r.name,input:this.getSpanInput(r),output:this.getSpanOutput(r),metadata:{...this.getSpanMetadata(r),...this.metadata},tags:this.tags,usage:this.getSpanUsage(r)});this.traces.set(a,p),u.forEach(g=>{var b,y;let R=this.spans.get((y=(b=g.parentSpanContext)==null?void 0:b.spanId)!=null?y:""),x=this.processSpan({parentSpan:R,otelSpan:g,trace:p});this.spans.set(g.spanContext().spanId,x);});});try{await this.client.flush(),t({code:0});}catch(a){opik.logger.error("Error exporting spans",a),t({code:1,error:a instanceof Error?a:new Error("Unknown error")});}};this.client=e,this.tags=[...t],this.metadata={...n};}static getSettings(e){var n,i,o;let t={...e.metadata};return e.name&&(t.traceName=e.name),{isEnabled:(n=e.isEnabled)!=null?n:true,recordInputs:(i=e.recordInputs)!=null?i:true,recordOutputs:(o=e.recordOutputs)!=null?o:true,functionId:e.functionId,metadata:t}}};function w(s){let e={};return s.forEach(t=>{let n=t.spanContext();e[n.traceId]||(e[n.traceId]=[]),e[n.traceId].push(t);}),Object.entries(e).forEach(([t,n])=>{e[t]=I(n);}),e}function l(s){return s[0]*1e3+s[1]/1e6}function m(s){try{return JSON.parse(s)}catch{return s}}function C(s){if(typeof s=="string")try{let e=JSON.parse(s);if(e!==null&&typeof e=="object"&&!Array.isArray(e))return e}catch{return}}function I(s){var a,c;let e=new Map,t=new Map;for(let r of s){let{spanId:u}=r.spanContext(),p=(c=(a=r.parentSpanContext)==null?void 0:a.spanId)!=null?c:"";e.set(u,r),p&&(t.has(p)||t.set(p,[]),t.get(p).push(r));}let n=s.filter(r=>{var u;return !((u=r.parentSpanContext)!=null&&u.spanId)||!e.has(r.parentSpanContext.spanId)}),i=[],o=[...n];for(;o.length>0;){let r=o.shift();i.push(r);let u=r.spanContext().spanId,p=t.get(u)||[];o.push(...p);}return i}exports.OpikExporter=f;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AttributeValue, Tracer } from '@opentelemetry/api';
|
|
2
|
+
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
3
|
+
import { Opik, Span, Trace } from 'opik';
|
|
4
|
+
|
|
5
|
+
type SpanExporter = NodeSDKConfiguration["traceExporter"];
|
|
6
|
+
type ExportFunction = SpanExporter["export"];
|
|
7
|
+
type ReadableSpan = Parameters<ExportFunction>[0][0];
|
|
8
|
+
type TelemetrySettings = {
|
|
9
|
+
isEnabled?: boolean;
|
|
10
|
+
recordInputs?: boolean;
|
|
11
|
+
recordOutputs?: boolean;
|
|
12
|
+
functionId?: string;
|
|
13
|
+
metadata?: Record<string, AttributeValue>;
|
|
14
|
+
tracer?: Tracer;
|
|
15
|
+
};
|
|
16
|
+
type OpikExporterSettings = TelemetrySettings & {
|
|
17
|
+
name?: string;
|
|
18
|
+
};
|
|
19
|
+
type OpikExporterOptions = {
|
|
20
|
+
client?: Opik;
|
|
21
|
+
tags?: string[];
|
|
22
|
+
metadata?: Record<string, AttributeValue>;
|
|
23
|
+
};
|
|
24
|
+
declare class OpikExporter implements SpanExporter {
|
|
25
|
+
private readonly traces;
|
|
26
|
+
private readonly spans;
|
|
27
|
+
private readonly client;
|
|
28
|
+
private readonly tags;
|
|
29
|
+
private readonly metadata;
|
|
30
|
+
constructor({ client, tags, metadata, }?: OpikExporterOptions);
|
|
31
|
+
private getSpanInput;
|
|
32
|
+
private getSpanOutput;
|
|
33
|
+
private getSpanMetadata;
|
|
34
|
+
private getSpanUsage;
|
|
35
|
+
processSpan: ({ otelSpan, parentSpan, trace, }: {
|
|
36
|
+
otelSpan: ReadableSpan;
|
|
37
|
+
parentSpan?: Span;
|
|
38
|
+
trace: Trace;
|
|
39
|
+
}) => Span;
|
|
40
|
+
shutdown: () => Promise<void>;
|
|
41
|
+
forceFlush: () => Promise<void>;
|
|
42
|
+
export: ExportFunction;
|
|
43
|
+
static getSettings(settings: OpikExporterSettings): TelemetrySettings;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { OpikExporter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AttributeValue, Tracer } from '@opentelemetry/api';
|
|
2
|
+
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
3
|
+
import { Opik, Span, Trace } from 'opik';
|
|
4
|
+
|
|
5
|
+
type SpanExporter = NodeSDKConfiguration["traceExporter"];
|
|
6
|
+
type ExportFunction = SpanExporter["export"];
|
|
7
|
+
type ReadableSpan = Parameters<ExportFunction>[0][0];
|
|
8
|
+
type TelemetrySettings = {
|
|
9
|
+
isEnabled?: boolean;
|
|
10
|
+
recordInputs?: boolean;
|
|
11
|
+
recordOutputs?: boolean;
|
|
12
|
+
functionId?: string;
|
|
13
|
+
metadata?: Record<string, AttributeValue>;
|
|
14
|
+
tracer?: Tracer;
|
|
15
|
+
};
|
|
16
|
+
type OpikExporterSettings = TelemetrySettings & {
|
|
17
|
+
name?: string;
|
|
18
|
+
};
|
|
19
|
+
type OpikExporterOptions = {
|
|
20
|
+
client?: Opik;
|
|
21
|
+
tags?: string[];
|
|
22
|
+
metadata?: Record<string, AttributeValue>;
|
|
23
|
+
};
|
|
24
|
+
declare class OpikExporter implements SpanExporter {
|
|
25
|
+
private readonly traces;
|
|
26
|
+
private readonly spans;
|
|
27
|
+
private readonly client;
|
|
28
|
+
private readonly tags;
|
|
29
|
+
private readonly metadata;
|
|
30
|
+
constructor({ client, tags, metadata, }?: OpikExporterOptions);
|
|
31
|
+
private getSpanInput;
|
|
32
|
+
private getSpanOutput;
|
|
33
|
+
private getSpanMetadata;
|
|
34
|
+
private getSpanUsage;
|
|
35
|
+
processSpan: ({ otelSpan, parentSpan, trace, }: {
|
|
36
|
+
otelSpan: ReadableSpan;
|
|
37
|
+
parentSpan?: Span;
|
|
38
|
+
trace: Trace;
|
|
39
|
+
}) => Span;
|
|
40
|
+
shutdown: () => Promise<void>;
|
|
41
|
+
forceFlush: () => Promise<void>;
|
|
42
|
+
export: ExportFunction;
|
|
43
|
+
static getSettings(settings: OpikExporterSettings): TelemetrySettings;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { OpikExporter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {Opik,logger}from'opik';var E=new Opik,f=class{constructor({client:e=E,tags:t=[],metadata:n={}}={}){this.traces=new Map;this.spans=new Map;this.getSpanInput=e=>{let t={},{attributes:n}=e;return Object.keys(n).forEach(o=>{if(o==="ai.prompt"||o==="gen_ai.request"){let a=C(n[o]);a&&(t={...t,...a});}if(o.startsWith("ai.prompt.")){let a=o.replace("ai.prompt.","");t[a]=m(n[o]);}if(o.startsWith("gen_ai.request.")){let a=o.replace("gen_ai.request.","");t[a]=m(n[o]);}}),Object.keys(t).length>0||("ai.toolCall.name"in n&&(t.toolName=n["ai.toolCall.name"]),"ai.toolCall.args"in n&&(t.args=n["ai.toolCall.args"])),t};this.getSpanOutput=e=>{let{attributes:t}=e;return t["ai.response.text"]?{text:t["ai.response.text"]}:t["ai.toolCall.result"]?{result:t["ai.toolCall.result"]}:t["ai.response.toolCalls"]?{toolCalls:m(t["ai.response.toolCalls"])}:{}};this.getSpanMetadata=e=>{let{attributes:t}=e,n={};return t["gen_ai.response.model"]&&(n.model=t["gen_ai.response.model"]),t["gen_ai.system"]&&(n.system=t["gen_ai.system"]),n};this.getSpanUsage=e=>{let{attributes:t}=e,n={};return "ai.usage.promptTokens"in t&&(n.prompt_tokens=t["ai.usage.promptTokens"]),"gen_ai.usage.input_tokens"in t&&(n.prompt_tokens=t["gen_ai.usage.input_tokens"]),"ai.usage.completionTokens"in t&&(n.completion_tokens=t["ai.usage.completionTokens"]),"gen_ai.usage.output_tokens"in t&&(n.completion_tokens=t["gen_ai.usage.output_tokens"]),("prompt_tokens"in n||"completion_tokens"in n)&&(n.total_tokens=(n.prompt_tokens||0)+(n.completion_tokens||0)),n};this.processSpan=({otelSpan:e,parentSpan:t,trace:n})=>n.span({name:e.name,startTime:new Date(l(e.startTime)),endTime:new Date(l(e.endTime)),parentSpanId:t==null?void 0:t.data.id,input:this.getSpanInput(e),output:this.getSpanOutput(e),metadata:this.getSpanMetadata(e),usage:this.getSpanUsage(e),type:"llm"});this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(e,t)=>{let n=e.filter(a=>a.instrumentationScope.name==="ai"),i=e.length-n.length;if(i>0&&logger.debug(`Ignored ${i} non-AI SDK spans`),n.length===0){logger.debug("No AI SDK spans found"),t({code:0});return}let o=w(n);logger.debug("Exporting spans",n),Object.entries(o).forEach(([a,c])=>{var S,h;let[r,...u]=c,p=this.client.trace({startTime:new Date(l(r.startTime)),endTime:new Date(l(r.endTime)),name:(h=(S=r.attributes["ai.telemetry.metadata.traceName"])==null?void 0:S.toString())!=null?h:r.name,input:this.getSpanInput(r),output:this.getSpanOutput(r),metadata:{...this.getSpanMetadata(r),...this.metadata},tags:this.tags,usage:this.getSpanUsage(r)});this.traces.set(a,p),u.forEach(g=>{var b,y;let R=this.spans.get((y=(b=g.parentSpanContext)==null?void 0:b.spanId)!=null?y:""),x=this.processSpan({parentSpan:R,otelSpan:g,trace:p});this.spans.set(g.spanContext().spanId,x);});});try{await this.client.flush(),t({code:0});}catch(a){logger.error("Error exporting spans",a),t({code:1,error:a instanceof Error?a:new Error("Unknown error")});}};this.client=e,this.tags=[...t],this.metadata={...n};}static getSettings(e){var n,i,o;let t={...e.metadata};return e.name&&(t.traceName=e.name),{isEnabled:(n=e.isEnabled)!=null?n:true,recordInputs:(i=e.recordInputs)!=null?i:true,recordOutputs:(o=e.recordOutputs)!=null?o:true,functionId:e.functionId,metadata:t}}};function w(s){let e={};return s.forEach(t=>{let n=t.spanContext();e[n.traceId]||(e[n.traceId]=[]),e[n.traceId].push(t);}),Object.entries(e).forEach(([t,n])=>{e[t]=I(n);}),e}function l(s){return s[0]*1e3+s[1]/1e6}function m(s){try{return JSON.parse(s)}catch{return s}}function C(s){if(typeof s=="string")try{let e=JSON.parse(s);if(e!==null&&typeof e=="object"&&!Array.isArray(e))return e}catch{return}}function I(s){var a,c;let e=new Map,t=new Map;for(let r of s){let{spanId:u}=r.spanContext(),p=(c=(a=r.parentSpanContext)==null?void 0:a.spanId)!=null?c:"";e.set(u,r),p&&(t.has(p)||t.set(p,[]),t.get(p).push(r));}let n=s.filter(r=>{var u;return !((u=r.parentSpanContext)!=null&&u.spanId)||!e.has(r.parentSpanContext.spanId)}),i=[],o=[...n];for(;o.length>0;){let r=o.shift();i.push(r);let u=r.spanContext().spanId,p=t.get(u)||[];o.push(...p);}return i}export{f as OpikExporter};
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opik-vercel",
|
|
3
|
+
"description": "Opik TypeScript and JavaScript SDK integration with Vercel AI SDK",
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=18"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/comet-ml/opik.git",
|
|
11
|
+
"directory": "sdks/typescript/src/opik/integrations/opik-vercel"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://www.comet.com/docs/opik/",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Comet",
|
|
16
|
+
"email": "support@comet.com",
|
|
17
|
+
"url": "https://github.com/comet-ml"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/comet-ml/opik/issues",
|
|
21
|
+
"email": "support@comet.com"
|
|
22
|
+
},
|
|
23
|
+
"license": "Apache-2.0",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"opik",
|
|
26
|
+
"vercel",
|
|
27
|
+
"vercel-ai-sdk",
|
|
28
|
+
"vercel-integration",
|
|
29
|
+
"sdk",
|
|
30
|
+
"javascript",
|
|
31
|
+
"javascript-sdk",
|
|
32
|
+
"typescript",
|
|
33
|
+
"typescript-sdk",
|
|
34
|
+
"comet"
|
|
35
|
+
],
|
|
36
|
+
"exports": {
|
|
37
|
+
"./package.json": "./package.json",
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js",
|
|
41
|
+
"require": "./dist/index.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"main": "dist/index.cjs",
|
|
45
|
+
"module": "dist/index.js",
|
|
46
|
+
"types": "dist/index.d.ts",
|
|
47
|
+
"type": "module",
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"watch": "tsup --watch",
|
|
51
|
+
"lint": "eslint '**/*.{ts,tsx}'",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"format": "prettier --write 'src/**/*.{ts,tsx,js,jsx,json,md}'",
|
|
54
|
+
"test": "vitest run"
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"dist/**/*",
|
|
58
|
+
"README.md"
|
|
59
|
+
],
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"opik": "^1.8.75",
|
|
62
|
+
"@opentelemetry/api": "^1.0.0",
|
|
63
|
+
"@opentelemetry/core": "^2.0.0",
|
|
64
|
+
"@opentelemetry/sdk-node": ">=0.56.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@eslint/js": "^9.38.0",
|
|
68
|
+
"@opentelemetry/auto-instrumentations-node": "^0.66.0",
|
|
69
|
+
"ai": "^5.0.76",
|
|
70
|
+
"eslint": "^9.38.0",
|
|
71
|
+
"globals": "^16.4.0",
|
|
72
|
+
"msw": "^2.7.0",
|
|
73
|
+
"prettier": "^3.6.2",
|
|
74
|
+
"tsup": "^8.5.0",
|
|
75
|
+
"typescript": "^5.9.3",
|
|
76
|
+
"typescript-eslint": "^8.46.2",
|
|
77
|
+
"vitest": "^3.2.4",
|
|
78
|
+
"zod": "^3.25.55"
|
|
79
|
+
}
|
|
80
|
+
}
|