opik-vercel 2.0.74 → 2.0.76
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/index.cjs +1 -1
- package/dist/index.d.cts +18 -15
- package/dist/index.d.ts +18 -15
- package/dist/index.js +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var api=require('@opentelemetry/api'),opik=require('opik');var C=new opik.Opik,f=class{constructor({client:n=C,tags:e=[],metadata:t={},threadId:s}={}){this.traces=new Map;this.spans=new Map;this.getSpanInput=n=>{let e={},{attributes:t}=n;return Object.keys(t).forEach(a=>{if(a==="ai.prompt"||a==="gen_ai.request"){let o=T(t[a]);o&&(e={...e,...o});}if(a.startsWith("ai.prompt.")){let o=a.replace("ai.prompt.","");e[o]=l(t[a]);}if(a.startsWith("gen_ai.request.")){let o=a.replace("gen_ai.request.","");e[o]=l(t[a]);}}),Object.keys(e).length>0||("ai.toolCall.name"in t&&(e.toolName=t["ai.toolCall.name"]),"ai.toolCall.args"in t&&(e.args=t["ai.toolCall.args"])),e};this.getSpanOutput=n=>{let{attributes:e}=n;return e["ai.response.text"]?{text:e["ai.response.text"]}:e["ai.response.object"]?{object:l(e["ai.response.object"])}:e["ai.toolCall.result"]?{result:e["ai.toolCall.result"]}:e["ai.response.toolCalls"]?{toolCalls:l(e["ai.response.toolCalls"])}:{}};this.getSpanMetadata=n=>{let{attributes:e}=n,t={};return e["gen_ai.response.model"]&&(t.model=e["gen_ai.response.model"]),e["gen_ai.system"]&&(t.system=e["gen_ai.system"]),t};this.getSpanUsage=n=>{let{attributes:e}=n,t={};return "ai.usage.promptTokens"in e&&(t.prompt_tokens=e["ai.usage.promptTokens"]),"gen_ai.usage.input_tokens"in e&&(t.prompt_tokens=e["gen_ai.usage.input_tokens"]),"ai.usage.completionTokens"in e&&(t.completion_tokens=e["ai.usage.completionTokens"]),"gen_ai.usage.output_tokens"in e&&(t.completion_tokens=e["gen_ai.usage.output_tokens"]),("prompt_tokens"in t||"completion_tokens"in t)&&(t.total_tokens=(t.prompt_tokens||0)+(t.completion_tokens||0)),t};this.getThreadId=n=>{var t;let{attributes:e}=n;return e["ai.telemetry.metadata.threadId"]!=null?(t=e["ai.telemetry.metadata.threadId"])==null?void 0:t.toString():this.threadId};this.getErrorInfo=n=>{var u,r,p;if(n.status.code!==api.SpanStatusCode.ERROR)return;let e=n.events.find(c=>c.name==="exception");if(!e)return {exceptionType:"Error",message:n.status.message||"An error occurred",traceback:""};let{attributes:t}=e,s=((u=t==null?void 0:t["exception.type"])==null?void 0:u.toString())||"Error",a=(r=t==null?void 0:t["exception.message"])==null?void 0:r.toString(),o=((p=t==null?void 0:t["exception.stacktrace"])==null?void 0:p.toString())||"";return {exceptionType:s,message:a,traceback:o}};this.processSpan=({otelSpan:n,parentSpan:e,trace:t})=>{let s=this.getErrorInfo(n);return t.span({name:n.name,startTime:new Date(g(n.startTime)),endTime:new Date(g(n.endTime)),parentSpanId:e==null?void 0:e.data.id,input:this.getSpanInput(n),output:this.getSpanOutput(n),metadata:this.getSpanMetadata(n),usage:this.getSpanUsage(n),type:"llm",...s&&{errorInfo:s}})};this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(n,e)=>{let t=n.filter(o=>O(o)==="ai"),s=n.length-t.length;if(s>0&&opik.logger.debug(`Ignored ${s} non-AI SDK spans`),t.length===0){opik.logger.debug("No AI SDK spans found"),e({code:0});return}let a=w(t);opik.logger.debug("Exporting spans",t),Object.entries(a).forEach(([o,u])=>{var h,b;let[r,...p]=u,c=this.getErrorInfo(r),S=this.client.trace({startTime:new Date(g(r.startTime)),endTime:new Date(g(r.endTime)),name:(b=(h=r.attributes["ai.telemetry.metadata.traceName"])==null?void 0:h.toString())!=null?b:r.name,input:this.getSpanInput(r),output:this.getSpanOutput(r),metadata:{...this.getSpanMetadata(r),...this.metadata},tags:this.tags,usage:this.getSpanUsage(r),threadId:this.getThreadId(r),...c&&{errorInfo:c}});this.traces.set(o,S),p.forEach(m=>{var y,I;let x=this.spans.get((I=(y=m.parentSpanContext)==null?void 0:y.spanId)!=null?I:""),R=this.processSpan({parentSpan:x,otelSpan:m,trace:S});this.spans.set(m.spanContext().spanId,R);});});try{await this.client.flush(),e({code:0});}catch(o){opik.logger.error("Error exporting spans",o),e({code:1,error:o instanceof Error?o:new Error("Unknown error")});}};this.client=n,this.tags=[...e],this.metadata={...t},this.threadId=s;}static getSettings(n){var t,s,a;let e={...n.metadata};return n.name&&(e.traceName=n.name),{isEnabled:(t=n.isEnabled)!=null?t:true,recordInputs:(s=n.recordInputs)!=null?s:true,recordOutputs:(a=n.recordOutputs)!=null?a:true,functionId:n.functionId,metadata:e}}};function w(i){let n={};return i.forEach(e=>{let t=e.spanContext();n[t.traceId]||(n[t.traceId]=[]),n[t.traceId].push(e);}),Object.entries(n).forEach(([e,t])=>{n[e]=_(t);}),n}function O(i){var e,t,s,a;let n=i;return (a=(s=(e=n.instrumentationScope)==null?void 0:e.name)!=null?s:(t=n.instrumentationLibrary)==null?void 0:t.name)!=null?a:void 0}function g(i){return i[0]*1e3+i[1]/1e6}function l(i){try{return JSON.parse(i)}catch{return i}}function T(i){if(typeof i=="string")try{let n=JSON.parse(i);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}catch{return}}function _(i){var o,u;let n=new Map,e=new Map;for(let r of i){let{spanId:p}=r.spanContext(),c=(u=(o=r.parentSpanContext)==null?void 0:o.spanId)!=null?u:"";n.set(p,r),c&&(e.has(c)||e.set(c,[]),e.get(c).push(r));}let t=i.filter(r=>{var p;return !((p=r.parentSpanContext)!=null&&p.spanId)||!n.has(r.parentSpanContext.spanId)}),s=[],a=[...t];for(;a.length>0;){let r=a.shift();s.push(r);let p=r.spanContext().spanId,c=e.get(p)||[];a.push(...c);}return s}exports.OpikExporter=f;
|
|
1
|
+
'use strict';var api=require('@opentelemetry/api'),opik=require('opik');function l(e){try{return JSON.parse(e)}catch{return e}}function F(e){if(typeof e=="string")try{let n=JSON.parse(e);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}catch{return}}function T(e){return typeof e=="string"?e:JSON.stringify(e)}function z(e){var a,p,d;if(e==null||typeof e!="object")return [];let{role:n,parts:t}=e,o=n!=null?n:"user";if(!Array.isArray(t))return [e];let r=[],s=[],i=[];for(let g of t){if(g==null||typeof g!="object")continue;let c=g;c.type==="text"?s.push(String((p=(a=c.content)!=null?a:c.text)!=null?p:"")):c.type==="tool_call"?i.push({id:c.id,type:"function",function:{name:c.name,arguments:T(c.arguments)}}):c.type==="tool_call_response"&&r.push({role:"tool",tool_call_id:c.id,content:T((d=c.response)!=null?d:c.output)});}if(s.length>0||i.length>0){let g={role:o};(s.length>0||i.length===0)&&(g.content=s.join("")),i.length>0&&(g.tool_calls=i),r.unshift(g);}return r}function L(e){return Array.isArray(e)?e.flatMap(z):[]}var I={input(e){let n={};for(let t of Object.keys(e))if(t==="ai.prompt"){let o=F(e[t]);o&&(n={...n,...o});}else t.startsWith("ai.prompt.")&&(n[t.slice(10)]=l(e[t]));return "ai.toolCall.name"in e&&(n.toolName=e["ai.toolCall.name"]),"ai.toolCall.args"in e&&(n.args=l(e["ai.toolCall.args"])),n},output(e){let n={};return e["ai.response.text"]&&(n.text=e["ai.response.text"]),e["ai.response.object"]&&(n.object=l(e["ai.response.object"])),e["ai.response.toolCalls"]&&(n.toolCalls=l(e["ai.response.toolCalls"])),e["ai.toolCall.result"]&&(n.result=l(e["ai.toolCall.result"])),n},usage(e){let n={};return "ai.usage.promptTokens"in e&&(n.prompt_tokens=Number(e["ai.usage.promptTokens"])),"ai.usage.completionTokens"in e&&(n.completion_tokens=Number(e["ai.usage.completionTokens"])),n}},m={input(e){let n={};for(let t of Object.keys(e))if(t==="gen_ai.request"){let o=F(e[t]);o&&(n={...n,...o});}else t.startsWith("gen_ai.request.")&&(n[t.slice(15)]=l(e[t]));if("gen_ai.input.messages"in e){let t=[];if("gen_ai.system_instructions"in e){let o=l(e["gen_ai.system_instructions"]),r=Array.isArray(o)?o.map(s=>{var i,a;return String(s&&typeof s=="object"?(a=(i=s.content)!=null?i:s.text)!=null?a:"":s)}).join(""):T(o);t.push({role:"system",content:r});}n.messages=[...t,...L(l(e["gen_ai.input.messages"]))];}return "gen_ai.tool.name"in e&&(n.toolName=e["gen_ai.tool.name"]),"gen_ai.tool.call.arguments"in e&&(n.args=l(e["gen_ai.tool.call.arguments"])),n},output(e){let n={};if("gen_ai.output.messages"in e){let t=l(e["gen_ai.output.messages"]),o=Array.isArray(t)?t:[];n.choices=L(t).map((r,s)=>{var p;let i=o[s],a=i&&typeof i=="object"&&(p=i.finish_reason)!=null?p:null;return {index:s,message:r,finish_reason:a}});}return "gen_ai.tool.call.result"in e&&(n.result=l(e["gen_ai.tool.call.result"])),n},usage(e){let n={};return "gen_ai.usage.input_tokens"in e&&(n.prompt_tokens=Number(e["gen_ai.usage.input_tokens"])),"gen_ai.usage.output_tokens"in e&&(n.completion_tokens=Number(e["gen_ai.usage.output_tokens"])),"gen_ai.usage.cache_read.input_tokens"in e&&(n["original_usage.cache_read_input_tokens"]=Number(e["gen_ai.usage.cache_read.input_tokens"])),"gen_ai.usage.cache_creation.input_tokens"in e&&(n["original_usage.cache_creation_input_tokens"]=Number(e["gen_ai.usage.cache_creation.input_tokens"])),n},metadata(e){let n={},t=R(e);t&&(n.model=t);let o=w(e);o&&(n.provider=o),"gen_ai.operation.name"in e&&(n.operation=e["gen_ai.operation.name"]),"gen_ai.response.finish_reasons"in e&&(n.finish_reasons=l(e["gen_ai.response.finish_reasons"]));for(let r of Object.keys(e))r.startsWith("eve.")?n[r]=e[r]:r.startsWith("ai.settings.context.eve.")&&(n[r.slice(20)]=e[r]);return n}};function h(e){return {...I.input(e),...m.input(e)}}function S(e){return {...I.output(e),...m.output(e)}}function x(e){return m.metadata(e)}function U(e){let n={...I.usage(e),...m.usage(e)};return ("prompt_tokens"in n||"completion_tokens"in n)&&(n.total_tokens=(n.prompt_tokens||0)+(n.completion_tokens||0)),n}var Q=new Set(["chat","text_completion","generate_content","embeddings"]);function R(e){var t;let n=(t=e["gen_ai.response.model"])!=null?t:e["gen_ai.request.model"];return n!=null?String(n):void 0}function w(e){var t;let n=(t=e["gen_ai.system"])!=null?t:e["gen_ai.provider.name"];return n!=null?String(n):void 0}function b(e){let n=e["gen_ai.operation.name"];return n==="execute_tool"||"ai.toolCall.name"in e||"gen_ai.tool.name"in e?"tool":typeof n=="string"?Q.has(n)?"llm":"general":"ai.prompt"in e||"ai.response.text"in e||"ai.response.object"in e||"ai.usage.promptTokens"in e||"ai.usage.completionTokens"in e?"llm":"general"}function K(e){if(e["ai.telemetry.metadata.threadId"]!=null)return e["ai.telemetry.metadata.threadId"].toString();if(e["eve.session.id"]!=null)return e["eve.session.id"].toString();if(e["ai.settings.context.eve.session.id"]!=null)return e["ai.settings.context.eve.session.id"].toString()}var H=new opik.Opik,X=600*1e3,Y=new Set(["ai","gen_ai","eve"]),C=class{constructor({client:n=H,tags:t=[],metadata:o={},threadId:r,traceTtlMs:s=X}={}){this.otelSpansByTrace=new Map;this.traceIds=new Map;this.spanIds=new Map;this.lastSeenByTrace=new Map;this.opikTraceId=n=>{let t=this.traceIds.get(n);return t||(t=opik.generateId(),this.traceIds.set(n,t)),t};this.opikSpanId=n=>{let t=this.spanIds.get(n);return t||(t=opik.generateId(),this.spanIds.set(n,t)),t};this.pruneStaleTraces=n=>{for(let[t,o]of this.lastSeenByTrace){if(n-o<=this.traceTtlMs)continue;let r=this.otelSpansByTrace.get(t);if(r)for(let s of r.keys())this.spanIds.delete(s);this.otelSpansByTrace.delete(t),this.traceIds.delete(t),this.lastSeenByTrace.delete(t);}};this.getErrorInfo=n=>{var a,p,d;if(n.status.code!==api.SpanStatusCode.ERROR)return;let t=n.events.find(g=>g.name==="exception");if(!t)return {exceptionType:"Error",message:n.status.message||"An error occurred",traceback:""};let{attributes:o}=t,r=((a=o==null?void 0:o["exception.type"])==null?void 0:a.toString())||"Error",s=(p=o==null?void 0:o["exception.message"])==null?void 0:p.toString(),i=((d=o==null?void 0:o["exception.stacktrace"])==null?void 0:d.toString())||"";return {exceptionType:r,message:s,traceback:i}};this.resolveThreadId=n=>{for(let t of n){let o=K(t.attributes);if(o!=null)return o}return this.threadId};this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(n,t)=>{let o=n.filter(a=>{var p;return Y.has((p=Z(a))!=null?p:"")}),r=n.length-o.length;if(r>0&&opik.logger.debug(`Ignored ${r} non-AI SDK spans`),o.length===0){opik.logger.debug("No AI SDK spans found"),t({code:0});return}opik.logger.debug("Exporting spans",o);let s=new Set;for(let a of o){let p=a.spanContext().traceId;s.add(p);let d=this.otelSpansByTrace.get(p);d||(d=new Map,this.otelSpansByTrace.set(p,d)),d.set(a.spanContext().spanId,a);}let i=Date.now();for(let a of s)this.lastSeenByTrace.set(a,i),this.exportTrace(a);this.pruneStaleTraces(i);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=n,this.tags=[...t],this.metadata={...o},this.threadId=r,this.traceTtlMs=s;}exportTrace(n){var M,A,O,N,j;let t=[...(A=(M=this.otelSpansByTrace.get(n))==null?void 0:M.values())!=null?A:[]];if(t.length===0)return;let o=this.opikTraceId(n),r=this.client.config.projectName,s=se(t),i=ae(t,s),a=i.spanContext().spanId,p=v(t.filter(u=>b(u.attributes)==="llm")),d=q(h(i.attributes),()=>ne(p,h)),g=q(S(i.attributes),()=>te(p,S)),c=(O=this.getErrorInfo(i))!=null?O:ie(t,this.getErrorInfo);this.client.traceBatchQueue.create({id:o,name:(j=(N=i.attributes["ai.telemetry.metadata.traceName"])==null?void 0:N.toString())!=null?j:i.name,startTime:new Date(Math.min(...t.map(f))),endTime:new Date(Math.max(...t.map(E))),input:d,output:g,metadata:{...oe(t),...this.metadata},tags:this.tags,threadId:this.resolveThreadId(t),projectName:r,...c&&{errorInfo:c}});for(let u of t){let _=u.spanContext().spanId;if(_===a)continue;let k=s.get(_),B=k!=null&&k!==a?this.opikSpanId(k):void 0,D=this.getErrorInfo(u),P=b(u.attributes),V=P==="llm"?{...re(u.attributes),usage:U(u.attributes)}:{};this.client.spanBatchQueue.create({id:this.opikSpanId(_),traceId:o,...B?{parentSpanId:B}:{},name:u.name,type:P,startTime:new Date(f(u)),endTime:new Date(E(u)),input:h(u.attributes),output:S(u.attributes),metadata:x(u.attributes),...V,projectName:r,...D&&{errorInfo:D}});}}static getSettings(n){var o,r,s;let t={...n.metadata};return n.name&&(t.traceName=n.name),{isEnabled:(o=n.isEnabled)!=null?o:true,recordInputs:(r=n.recordInputs)!=null?r:true,recordOutputs:(s=n.recordOutputs)!=null?s:true,functionId:n.functionId,metadata:t}}};function Z(e){var t,o,r,s;let n=e;return (s=(r=(t=n.instrumentationScope)==null?void 0:t.name)!=null?r:(o=n.instrumentationLibrary)==null?void 0:o.name)!=null?s:void 0}function W(e){return e[0]*1e3+e[1]/1e6}function f(e){return W(e.startTime)}function E(e){return W(e.endTime)}function v(e){return [...e].sort((n,t)=>f(n)-f(t))}function ee(e){let n=e.map(o=>{let r=f(o),s=E(o);return {id:o.spanContext().spanId,start:r,end:s,duration:s-r}}),t=new Map;for(let o of n){let r;for(let s of n){if(s.id===o.id)continue;s.start<=o.start&&s.end>=o.end&&s.duration>o.duration&&(!r||s.duration<r.duration)&&(r=s);}t.set(o.id,r==null?void 0:r.id);}return t}function ne(e,n){for(let t of e){let o=n(t.attributes);if(Object.keys(o).length>0)return o}return {}}function te(e,n){for(let t=e.length-1;t>=0;t--){let o=n(e[t].attributes);if(Object.keys(o).length>0)return o}return {}}function oe(e){let n={};for(let t of e)n={...n,...x(t.attributes)};return n}function re(e){let n=R(e),t=w(e);return {...n?{model:n}:{},...t?{provider:t}:{}}}function se(e){var r;let n=new Set(e.map(s=>s.spanContext().spanId)),t=ee(e),o=new Map;for(let s of e){let i=s.spanContext().spanId,a=(r=s.parentSpanContext)==null?void 0:r.spanId;o.set(i,a!=null&&n.has(a)?a:t.get(i));}return o}function ae(e,n){let t=e.filter(o=>n.get(o.spanContext().spanId)==null);return v(t.length>0?t:e)[0]}function q(e,n){return Object.keys(e).length>0?e:n()}function ie(e,n){for(let t of v(e)){let o=n(t);if(o)return o}}exports.OpikExporter=C;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { AttributeValue, Tracer } from '@opentelemetry/api';
|
|
2
2
|
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
3
|
-
import { Opik
|
|
3
|
+
import { Opik } from 'opik';
|
|
4
4
|
|
|
5
5
|
type SpanExporter = NodeSDKConfiguration["traceExporter"];
|
|
6
6
|
type ExportFunction = SpanExporter["export"];
|
|
7
|
-
type ReadableSpan = Parameters<ExportFunction>[0][0];
|
|
8
7
|
type TelemetrySettings = {
|
|
9
8
|
isEnabled?: boolean;
|
|
10
9
|
recordInputs?: boolean;
|
|
@@ -21,29 +20,33 @@ type OpikExporterOptions = {
|
|
|
21
20
|
tags?: string[];
|
|
22
21
|
metadata?: Record<string, AttributeValue>;
|
|
23
22
|
threadId?: string;
|
|
23
|
+
/**
|
|
24
|
+
* How long (ms) to retain a trace's accumulated spans/ids after its last
|
|
25
|
+
* activity before pruning them, to bound memory in long-running processes.
|
|
26
|
+
* A trace idle longer than this is assumed complete. Defaults to 10 minutes.
|
|
27
|
+
*/
|
|
28
|
+
traceTtlMs?: number;
|
|
24
29
|
};
|
|
25
30
|
declare class OpikExporter implements SpanExporter {
|
|
26
|
-
private readonly
|
|
27
|
-
private readonly
|
|
31
|
+
private readonly otelSpansByTrace;
|
|
32
|
+
private readonly traceIds;
|
|
33
|
+
private readonly spanIds;
|
|
34
|
+
private readonly lastSeenByTrace;
|
|
28
35
|
private readonly client;
|
|
29
36
|
private readonly tags;
|
|
30
37
|
private readonly metadata;
|
|
31
38
|
private readonly threadId?;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private getThreadId;
|
|
39
|
+
private readonly traceTtlMs;
|
|
40
|
+
constructor({ client, tags, metadata, threadId, traceTtlMs, }?: OpikExporterOptions);
|
|
41
|
+
private opikTraceId;
|
|
42
|
+
private opikSpanId;
|
|
43
|
+
private pruneStaleTraces;
|
|
38
44
|
private getErrorInfo;
|
|
39
|
-
|
|
40
|
-
otelSpan: ReadableSpan;
|
|
41
|
-
parentSpan?: Span;
|
|
42
|
-
trace: Trace;
|
|
43
|
-
}) => Span;
|
|
45
|
+
private resolveThreadId;
|
|
44
46
|
shutdown: () => Promise<void>;
|
|
45
47
|
forceFlush: () => Promise<void>;
|
|
46
48
|
export: ExportFunction;
|
|
49
|
+
private exportTrace;
|
|
47
50
|
static getSettings(settings: OpikExporterSettings): TelemetrySettings;
|
|
48
51
|
}
|
|
49
52
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { AttributeValue, Tracer } from '@opentelemetry/api';
|
|
2
2
|
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
3
|
-
import { Opik
|
|
3
|
+
import { Opik } from 'opik';
|
|
4
4
|
|
|
5
5
|
type SpanExporter = NodeSDKConfiguration["traceExporter"];
|
|
6
6
|
type ExportFunction = SpanExporter["export"];
|
|
7
|
-
type ReadableSpan = Parameters<ExportFunction>[0][0];
|
|
8
7
|
type TelemetrySettings = {
|
|
9
8
|
isEnabled?: boolean;
|
|
10
9
|
recordInputs?: boolean;
|
|
@@ -21,29 +20,33 @@ type OpikExporterOptions = {
|
|
|
21
20
|
tags?: string[];
|
|
22
21
|
metadata?: Record<string, AttributeValue>;
|
|
23
22
|
threadId?: string;
|
|
23
|
+
/**
|
|
24
|
+
* How long (ms) to retain a trace's accumulated spans/ids after its last
|
|
25
|
+
* activity before pruning them, to bound memory in long-running processes.
|
|
26
|
+
* A trace idle longer than this is assumed complete. Defaults to 10 minutes.
|
|
27
|
+
*/
|
|
28
|
+
traceTtlMs?: number;
|
|
24
29
|
};
|
|
25
30
|
declare class OpikExporter implements SpanExporter {
|
|
26
|
-
private readonly
|
|
27
|
-
private readonly
|
|
31
|
+
private readonly otelSpansByTrace;
|
|
32
|
+
private readonly traceIds;
|
|
33
|
+
private readonly spanIds;
|
|
34
|
+
private readonly lastSeenByTrace;
|
|
28
35
|
private readonly client;
|
|
29
36
|
private readonly tags;
|
|
30
37
|
private readonly metadata;
|
|
31
38
|
private readonly threadId?;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private getThreadId;
|
|
39
|
+
private readonly traceTtlMs;
|
|
40
|
+
constructor({ client, tags, metadata, threadId, traceTtlMs, }?: OpikExporterOptions);
|
|
41
|
+
private opikTraceId;
|
|
42
|
+
private opikSpanId;
|
|
43
|
+
private pruneStaleTraces;
|
|
38
44
|
private getErrorInfo;
|
|
39
|
-
|
|
40
|
-
otelSpan: ReadableSpan;
|
|
41
|
-
parentSpan?: Span;
|
|
42
|
-
trace: Trace;
|
|
43
|
-
}) => Span;
|
|
45
|
+
private resolveThreadId;
|
|
44
46
|
shutdown: () => Promise<void>;
|
|
45
47
|
forceFlush: () => Promise<void>;
|
|
46
48
|
export: ExportFunction;
|
|
49
|
+
private exportTrace;
|
|
47
50
|
static getSettings(settings: OpikExporterSettings): TelemetrySettings;
|
|
48
51
|
}
|
|
49
52
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {SpanStatusCode}from'@opentelemetry/api';import {Opik,logger}from'opik';var C=new Opik,f=class{constructor({client:n=C,tags:e=[],metadata:t={},threadId:s}={}){this.traces=new Map;this.spans=new Map;this.getSpanInput=n=>{let e={},{attributes:t}=n;return Object.keys(t).forEach(a=>{if(a==="ai.prompt"||a==="gen_ai.request"){let o=T(t[a]);o&&(e={...e,...o});}if(a.startsWith("ai.prompt.")){let o=a.replace("ai.prompt.","");e[o]=l(t[a]);}if(a.startsWith("gen_ai.request.")){let o=a.replace("gen_ai.request.","");e[o]=l(t[a]);}}),Object.keys(e).length>0||("ai.toolCall.name"in t&&(e.toolName=t["ai.toolCall.name"]),"ai.toolCall.args"in t&&(e.args=t["ai.toolCall.args"])),e};this.getSpanOutput=n=>{let{attributes:e}=n;return e["ai.response.text"]?{text:e["ai.response.text"]}:e["ai.response.object"]?{object:l(e["ai.response.object"])}:e["ai.toolCall.result"]?{result:e["ai.toolCall.result"]}:e["ai.response.toolCalls"]?{toolCalls:l(e["ai.response.toolCalls"])}:{}};this.getSpanMetadata=n=>{let{attributes:e}=n,t={};return e["gen_ai.response.model"]&&(t.model=e["gen_ai.response.model"]),e["gen_ai.system"]&&(t.system=e["gen_ai.system"]),t};this.getSpanUsage=n=>{let{attributes:e}=n,t={};return "ai.usage.promptTokens"in e&&(t.prompt_tokens=e["ai.usage.promptTokens"]),"gen_ai.usage.input_tokens"in e&&(t.prompt_tokens=e["gen_ai.usage.input_tokens"]),"ai.usage.completionTokens"in e&&(t.completion_tokens=e["ai.usage.completionTokens"]),"gen_ai.usage.output_tokens"in e&&(t.completion_tokens=e["gen_ai.usage.output_tokens"]),("prompt_tokens"in t||"completion_tokens"in t)&&(t.total_tokens=(t.prompt_tokens||0)+(t.completion_tokens||0)),t};this.getThreadId=n=>{var t;let{attributes:e}=n;return e["ai.telemetry.metadata.threadId"]!=null?(t=e["ai.telemetry.metadata.threadId"])==null?void 0:t.toString():this.threadId};this.getErrorInfo=n=>{var u,r,p;if(n.status.code!==SpanStatusCode.ERROR)return;let e=n.events.find(c=>c.name==="exception");if(!e)return {exceptionType:"Error",message:n.status.message||"An error occurred",traceback:""};let{attributes:t}=e,s=((u=t==null?void 0:t["exception.type"])==null?void 0:u.toString())||"Error",a=(r=t==null?void 0:t["exception.message"])==null?void 0:r.toString(),o=((p=t==null?void 0:t["exception.stacktrace"])==null?void 0:p.toString())||"";return {exceptionType:s,message:a,traceback:o}};this.processSpan=({otelSpan:n,parentSpan:e,trace:t})=>{let s=this.getErrorInfo(n);return t.span({name:n.name,startTime:new Date(g(n.startTime)),endTime:new Date(g(n.endTime)),parentSpanId:e==null?void 0:e.data.id,input:this.getSpanInput(n),output:this.getSpanOutput(n),metadata:this.getSpanMetadata(n),usage:this.getSpanUsage(n),type:"llm",...s&&{errorInfo:s}})};this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(n,e)=>{let t=n.filter(o=>O(o)==="ai"),s=n.length-t.length;if(s>0&&logger.debug(`Ignored ${s} non-AI SDK spans`),t.length===0){logger.debug("No AI SDK spans found"),e({code:0});return}let a=w(t);logger.debug("Exporting spans",t),Object.entries(a).forEach(([o,u])=>{var h,b;let[r,...p]=u,c=this.getErrorInfo(r),S=this.client.trace({startTime:new Date(g(r.startTime)),endTime:new Date(g(r.endTime)),name:(b=(h=r.attributes["ai.telemetry.metadata.traceName"])==null?void 0:h.toString())!=null?b:r.name,input:this.getSpanInput(r),output:this.getSpanOutput(r),metadata:{...this.getSpanMetadata(r),...this.metadata},tags:this.tags,usage:this.getSpanUsage(r),threadId:this.getThreadId(r),...c&&{errorInfo:c}});this.traces.set(o,S),p.forEach(m=>{var y,I;let x=this.spans.get((I=(y=m.parentSpanContext)==null?void 0:y.spanId)!=null?I:""),R=this.processSpan({parentSpan:x,otelSpan:m,trace:S});this.spans.set(m.spanContext().spanId,R);});});try{await this.client.flush(),e({code:0});}catch(o){logger.error("Error exporting spans",o),e({code:1,error:o instanceof Error?o:new Error("Unknown error")});}};this.client=n,this.tags=[...e],this.metadata={...t},this.threadId=s;}static getSettings(n){var t,s,a;let e={...n.metadata};return n.name&&(e.traceName=n.name),{isEnabled:(t=n.isEnabled)!=null?t:true,recordInputs:(s=n.recordInputs)!=null?s:true,recordOutputs:(a=n.recordOutputs)!=null?a:true,functionId:n.functionId,metadata:e}}};function w(i){let n={};return i.forEach(e=>{let t=e.spanContext();n[t.traceId]||(n[t.traceId]=[]),n[t.traceId].push(e);}),Object.entries(n).forEach(([e,t])=>{n[e]=_(t);}),n}function O(i){var e,t,s,a;let n=i;return (a=(s=(e=n.instrumentationScope)==null?void 0:e.name)!=null?s:(t=n.instrumentationLibrary)==null?void 0:t.name)!=null?a:void 0}function g(i){return i[0]*1e3+i[1]/1e6}function l(i){try{return JSON.parse(i)}catch{return i}}function T(i){if(typeof i=="string")try{let n=JSON.parse(i);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}catch{return}}function _(i){var o,u;let n=new Map,e=new Map;for(let r of i){let{spanId:p}=r.spanContext(),c=(u=(o=r.parentSpanContext)==null?void 0:o.spanId)!=null?u:"";n.set(p,r),c&&(e.has(c)||e.set(c,[]),e.get(c).push(r));}let t=i.filter(r=>{var p;return !((p=r.parentSpanContext)!=null&&p.spanId)||!n.has(r.parentSpanContext.spanId)}),s=[],a=[...t];for(;a.length>0;){let r=a.shift();s.push(r);let p=r.spanContext().spanId,c=e.get(p)||[];a.push(...c);}return s}export{f as OpikExporter};
|
|
1
|
+
import {SpanStatusCode}from'@opentelemetry/api';import {Opik,generateId,logger}from'opik';function l(e){try{return JSON.parse(e)}catch{return e}}function F(e){if(typeof e=="string")try{let n=JSON.parse(e);if(n!==null&&typeof n=="object"&&!Array.isArray(n))return n}catch{return}}function T(e){return typeof e=="string"?e:JSON.stringify(e)}function z(e){var a,p,d;if(e==null||typeof e!="object")return [];let{role:n,parts:t}=e,o=n!=null?n:"user";if(!Array.isArray(t))return [e];let r=[],s=[],i=[];for(let g of t){if(g==null||typeof g!="object")continue;let c=g;c.type==="text"?s.push(String((p=(a=c.content)!=null?a:c.text)!=null?p:"")):c.type==="tool_call"?i.push({id:c.id,type:"function",function:{name:c.name,arguments:T(c.arguments)}}):c.type==="tool_call_response"&&r.push({role:"tool",tool_call_id:c.id,content:T((d=c.response)!=null?d:c.output)});}if(s.length>0||i.length>0){let g={role:o};(s.length>0||i.length===0)&&(g.content=s.join("")),i.length>0&&(g.tool_calls=i),r.unshift(g);}return r}function L(e){return Array.isArray(e)?e.flatMap(z):[]}var I={input(e){let n={};for(let t of Object.keys(e))if(t==="ai.prompt"){let o=F(e[t]);o&&(n={...n,...o});}else t.startsWith("ai.prompt.")&&(n[t.slice(10)]=l(e[t]));return "ai.toolCall.name"in e&&(n.toolName=e["ai.toolCall.name"]),"ai.toolCall.args"in e&&(n.args=l(e["ai.toolCall.args"])),n},output(e){let n={};return e["ai.response.text"]&&(n.text=e["ai.response.text"]),e["ai.response.object"]&&(n.object=l(e["ai.response.object"])),e["ai.response.toolCalls"]&&(n.toolCalls=l(e["ai.response.toolCalls"])),e["ai.toolCall.result"]&&(n.result=l(e["ai.toolCall.result"])),n},usage(e){let n={};return "ai.usage.promptTokens"in e&&(n.prompt_tokens=Number(e["ai.usage.promptTokens"])),"ai.usage.completionTokens"in e&&(n.completion_tokens=Number(e["ai.usage.completionTokens"])),n}},m={input(e){let n={};for(let t of Object.keys(e))if(t==="gen_ai.request"){let o=F(e[t]);o&&(n={...n,...o});}else t.startsWith("gen_ai.request.")&&(n[t.slice(15)]=l(e[t]));if("gen_ai.input.messages"in e){let t=[];if("gen_ai.system_instructions"in e){let o=l(e["gen_ai.system_instructions"]),r=Array.isArray(o)?o.map(s=>{var i,a;return String(s&&typeof s=="object"?(a=(i=s.content)!=null?i:s.text)!=null?a:"":s)}).join(""):T(o);t.push({role:"system",content:r});}n.messages=[...t,...L(l(e["gen_ai.input.messages"]))];}return "gen_ai.tool.name"in e&&(n.toolName=e["gen_ai.tool.name"]),"gen_ai.tool.call.arguments"in e&&(n.args=l(e["gen_ai.tool.call.arguments"])),n},output(e){let n={};if("gen_ai.output.messages"in e){let t=l(e["gen_ai.output.messages"]),o=Array.isArray(t)?t:[];n.choices=L(t).map((r,s)=>{var p;let i=o[s],a=i&&typeof i=="object"&&(p=i.finish_reason)!=null?p:null;return {index:s,message:r,finish_reason:a}});}return "gen_ai.tool.call.result"in e&&(n.result=l(e["gen_ai.tool.call.result"])),n},usage(e){let n={};return "gen_ai.usage.input_tokens"in e&&(n.prompt_tokens=Number(e["gen_ai.usage.input_tokens"])),"gen_ai.usage.output_tokens"in e&&(n.completion_tokens=Number(e["gen_ai.usage.output_tokens"])),"gen_ai.usage.cache_read.input_tokens"in e&&(n["original_usage.cache_read_input_tokens"]=Number(e["gen_ai.usage.cache_read.input_tokens"])),"gen_ai.usage.cache_creation.input_tokens"in e&&(n["original_usage.cache_creation_input_tokens"]=Number(e["gen_ai.usage.cache_creation.input_tokens"])),n},metadata(e){let n={},t=R(e);t&&(n.model=t);let o=w(e);o&&(n.provider=o),"gen_ai.operation.name"in e&&(n.operation=e["gen_ai.operation.name"]),"gen_ai.response.finish_reasons"in e&&(n.finish_reasons=l(e["gen_ai.response.finish_reasons"]));for(let r of Object.keys(e))r.startsWith("eve.")?n[r]=e[r]:r.startsWith("ai.settings.context.eve.")&&(n[r.slice(20)]=e[r]);return n}};function h(e){return {...I.input(e),...m.input(e)}}function S(e){return {...I.output(e),...m.output(e)}}function x(e){return m.metadata(e)}function U(e){let n={...I.usage(e),...m.usage(e)};return ("prompt_tokens"in n||"completion_tokens"in n)&&(n.total_tokens=(n.prompt_tokens||0)+(n.completion_tokens||0)),n}var Q=new Set(["chat","text_completion","generate_content","embeddings"]);function R(e){var t;let n=(t=e["gen_ai.response.model"])!=null?t:e["gen_ai.request.model"];return n!=null?String(n):void 0}function w(e){var t;let n=(t=e["gen_ai.system"])!=null?t:e["gen_ai.provider.name"];return n!=null?String(n):void 0}function b(e){let n=e["gen_ai.operation.name"];return n==="execute_tool"||"ai.toolCall.name"in e||"gen_ai.tool.name"in e?"tool":typeof n=="string"?Q.has(n)?"llm":"general":"ai.prompt"in e||"ai.response.text"in e||"ai.response.object"in e||"ai.usage.promptTokens"in e||"ai.usage.completionTokens"in e?"llm":"general"}function K(e){if(e["ai.telemetry.metadata.threadId"]!=null)return e["ai.telemetry.metadata.threadId"].toString();if(e["eve.session.id"]!=null)return e["eve.session.id"].toString();if(e["ai.settings.context.eve.session.id"]!=null)return e["ai.settings.context.eve.session.id"].toString()}var H=new Opik,X=600*1e3,Y=new Set(["ai","gen_ai","eve"]),C=class{constructor({client:n=H,tags:t=[],metadata:o={},threadId:r,traceTtlMs:s=X}={}){this.otelSpansByTrace=new Map;this.traceIds=new Map;this.spanIds=new Map;this.lastSeenByTrace=new Map;this.opikTraceId=n=>{let t=this.traceIds.get(n);return t||(t=generateId(),this.traceIds.set(n,t)),t};this.opikSpanId=n=>{let t=this.spanIds.get(n);return t||(t=generateId(),this.spanIds.set(n,t)),t};this.pruneStaleTraces=n=>{for(let[t,o]of this.lastSeenByTrace){if(n-o<=this.traceTtlMs)continue;let r=this.otelSpansByTrace.get(t);if(r)for(let s of r.keys())this.spanIds.delete(s);this.otelSpansByTrace.delete(t),this.traceIds.delete(t),this.lastSeenByTrace.delete(t);}};this.getErrorInfo=n=>{var a,p,d;if(n.status.code!==SpanStatusCode.ERROR)return;let t=n.events.find(g=>g.name==="exception");if(!t)return {exceptionType:"Error",message:n.status.message||"An error occurred",traceback:""};let{attributes:o}=t,r=((a=o==null?void 0:o["exception.type"])==null?void 0:a.toString())||"Error",s=(p=o==null?void 0:o["exception.message"])==null?void 0:p.toString(),i=((d=o==null?void 0:o["exception.stacktrace"])==null?void 0:d.toString())||"";return {exceptionType:r,message:s,traceback:i}};this.resolveThreadId=n=>{for(let t of n){let o=K(t.attributes);if(o!=null)return o}return this.threadId};this.shutdown=async()=>{await this.client.flush();};this.forceFlush=async()=>{await this.client.flush();};this.export=async(n,t)=>{let o=n.filter(a=>{var p;return Y.has((p=Z(a))!=null?p:"")}),r=n.length-o.length;if(r>0&&logger.debug(`Ignored ${r} non-AI SDK spans`),o.length===0){logger.debug("No AI SDK spans found"),t({code:0});return}logger.debug("Exporting spans",o);let s=new Set;for(let a of o){let p=a.spanContext().traceId;s.add(p);let d=this.otelSpansByTrace.get(p);d||(d=new Map,this.otelSpansByTrace.set(p,d)),d.set(a.spanContext().spanId,a);}let i=Date.now();for(let a of s)this.lastSeenByTrace.set(a,i),this.exportTrace(a);this.pruneStaleTraces(i);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=n,this.tags=[...t],this.metadata={...o},this.threadId=r,this.traceTtlMs=s;}exportTrace(n){var M,A,O,N,j;let t=[...(A=(M=this.otelSpansByTrace.get(n))==null?void 0:M.values())!=null?A:[]];if(t.length===0)return;let o=this.opikTraceId(n),r=this.client.config.projectName,s=se(t),i=ae(t,s),a=i.spanContext().spanId,p=v(t.filter(u=>b(u.attributes)==="llm")),d=q(h(i.attributes),()=>ne(p,h)),g=q(S(i.attributes),()=>te(p,S)),c=(O=this.getErrorInfo(i))!=null?O:ie(t,this.getErrorInfo);this.client.traceBatchQueue.create({id:o,name:(j=(N=i.attributes["ai.telemetry.metadata.traceName"])==null?void 0:N.toString())!=null?j:i.name,startTime:new Date(Math.min(...t.map(f))),endTime:new Date(Math.max(...t.map(E))),input:d,output:g,metadata:{...oe(t),...this.metadata},tags:this.tags,threadId:this.resolveThreadId(t),projectName:r,...c&&{errorInfo:c}});for(let u of t){let _=u.spanContext().spanId;if(_===a)continue;let k=s.get(_),B=k!=null&&k!==a?this.opikSpanId(k):void 0,D=this.getErrorInfo(u),P=b(u.attributes),V=P==="llm"?{...re(u.attributes),usage:U(u.attributes)}:{};this.client.spanBatchQueue.create({id:this.opikSpanId(_),traceId:o,...B?{parentSpanId:B}:{},name:u.name,type:P,startTime:new Date(f(u)),endTime:new Date(E(u)),input:h(u.attributes),output:S(u.attributes),metadata:x(u.attributes),...V,projectName:r,...D&&{errorInfo:D}});}}static getSettings(n){var o,r,s;let t={...n.metadata};return n.name&&(t.traceName=n.name),{isEnabled:(o=n.isEnabled)!=null?o:true,recordInputs:(r=n.recordInputs)!=null?r:true,recordOutputs:(s=n.recordOutputs)!=null?s:true,functionId:n.functionId,metadata:t}}};function Z(e){var t,o,r,s;let n=e;return (s=(r=(t=n.instrumentationScope)==null?void 0:t.name)!=null?r:(o=n.instrumentationLibrary)==null?void 0:o.name)!=null?s:void 0}function W(e){return e[0]*1e3+e[1]/1e6}function f(e){return W(e.startTime)}function E(e){return W(e.endTime)}function v(e){return [...e].sort((n,t)=>f(n)-f(t))}function ee(e){let n=e.map(o=>{let r=f(o),s=E(o);return {id:o.spanContext().spanId,start:r,end:s,duration:s-r}}),t=new Map;for(let o of n){let r;for(let s of n){if(s.id===o.id)continue;s.start<=o.start&&s.end>=o.end&&s.duration>o.duration&&(!r||s.duration<r.duration)&&(r=s);}t.set(o.id,r==null?void 0:r.id);}return t}function ne(e,n){for(let t of e){let o=n(t.attributes);if(Object.keys(o).length>0)return o}return {}}function te(e,n){for(let t=e.length-1;t>=0;t--){let o=n(e[t].attributes);if(Object.keys(o).length>0)return o}return {}}function oe(e){let n={};for(let t of e)n={...n,...x(t.attributes)};return n}function re(e){let n=R(e),t=w(e);return {...n?{model:n}:{},...t?{provider:t}:{}}}function se(e){var r;let n=new Set(e.map(s=>s.spanContext().spanId)),t=ee(e),o=new Map;for(let s of e){let i=s.spanContext().spanId,a=(r=s.parentSpanContext)==null?void 0:r.spanId;o.set(i,a!=null&&n.has(a)?a:t.get(i));}return o}function ae(e,n){let t=e.filter(o=>n.get(o.spanContext().spanId)==null);return v(t.length>0?t:e)[0]}function q(e,n){return Object.keys(e).length>0?e:n()}function ie(e,n){for(let t of v(e)){let o=n(t);if(o)return o}}export{C as OpikExporter};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opik-vercel",
|
|
3
3
|
"description": "Opik TypeScript and JavaScript SDK integration with Vercel AI SDK",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.76",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
7
7
|
},
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"@opentelemetry/sdk-node": ">=0.56.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
+
"@ai-sdk/anthropic": "^3.0.85",
|
|
67
68
|
"@eslint/js": "^9.38.0",
|
|
68
69
|
"@opentelemetry/auto-instrumentations-node": "^0.66.0",
|
|
69
70
|
"ai": "^6.0.13",
|