mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-22 07:01:07 +03:00
feat: Add Arize & Phoenix Tracer Integration (#4046)
Added Arize Phoenix Tracer Co-authored-by: Ilango <ilango.rajagopal@flowiseai.com>
This commit is contained in:
@@ -71,6 +71,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"@google/generative-ai": "^0.15.0",
|
||||
"@grpc/grpc-js": "^1.10.10",
|
||||
"@langchain/core": "0.3.37",
|
||||
"@qdrant/openapi-typescript-fetch": "1.2.6",
|
||||
"openai": "4.82.0",
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { INodeParams, INodeCredential } from '../src/Interface'
|
||||
|
||||
class ArizeApi implements INodeCredential {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Arize API'
|
||||
this.name = 'arizeApi'
|
||||
this.version = 1.0
|
||||
this.description =
|
||||
'Refer to <a target="_blank" href="https://docs.arize.com/arize">official guide</a> on how to get API keys on Arize.'
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'API Key',
|
||||
name: 'arizeApiKey',
|
||||
type: 'password',
|
||||
placeholder: '<ARIZE_API_KEY>'
|
||||
},
|
||||
{
|
||||
label: 'Space ID',
|
||||
name: 'arizeSpaceId',
|
||||
type: 'string',
|
||||
placeholder: '<ARIZE_SPACE_ID>'
|
||||
},
|
||||
{
|
||||
label: 'Endpoint',
|
||||
name: 'arizeEndpoint',
|
||||
type: 'string',
|
||||
default: 'https://otlp.arize.com'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { credClass: ArizeApi }
|
||||
@@ -0,0 +1,33 @@
|
||||
import { INodeParams, INodeCredential } from '../src/Interface'
|
||||
|
||||
class PhoenixApi implements INodeCredential {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Phoenix API'
|
||||
this.name = 'phoenixApi'
|
||||
this.version = 1.0
|
||||
this.description =
|
||||
'Refer to <a target="_blank" href="https://docs.arize.com/phoenix">official guide</a> on how to get API keys on Phoenix.'
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'API Key',
|
||||
name: 'phoenixApiKey',
|
||||
type: 'password',
|
||||
placeholder: '<PHOENIX_API_KEY>'
|
||||
},
|
||||
{
|
||||
label: 'Endpoint',
|
||||
name: 'phoenixEndpoint',
|
||||
type: 'string',
|
||||
default: 'https://app.phoenix.arize.com'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { credClass: PhoenixApi }
|
||||
@@ -0,0 +1,33 @@
|
||||
import { INode, INodeParams } from '../../../src/Interface'
|
||||
|
||||
class Arize_Analytic implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
inputs?: INodeParams[]
|
||||
credential: INodeParams
|
||||
|
||||
constructor() {
|
||||
this.label = 'Arize'
|
||||
this.name = 'arize'
|
||||
this.version = 1.0
|
||||
this.type = 'Arize'
|
||||
this.icon = 'arize.png'
|
||||
this.category = 'Analytic'
|
||||
this.baseClasses = [this.type]
|
||||
this.inputs = []
|
||||
this.credential = {
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['arizeApi']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: Arize_Analytic }
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,33 @@
|
||||
import { INode, INodeParams } from '../../../src/Interface'
|
||||
|
||||
class Phoenix_Analytic implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
inputs?: INodeParams[]
|
||||
credential: INodeParams
|
||||
|
||||
constructor() {
|
||||
this.label = 'Phoenix'
|
||||
this.name = 'phoenix'
|
||||
this.version = 1.0
|
||||
this.type = 'Phoenix'
|
||||
this.icon = 'phoenix.png'
|
||||
this.category = 'Analytic'
|
||||
this.baseClasses = [this.type]
|
||||
this.inputs = []
|
||||
this.credential = {
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['phoenixApi']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: Phoenix_Analytic }
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -21,6 +21,7 @@
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^11.7.0",
|
||||
"@arizeai/openinference-instrumentation-langchain": "^2.0.0",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.422.0",
|
||||
"@aws-sdk/client-dynamodb": "^3.360.0",
|
||||
"@aws-sdk/client-s3": "^3.427.0",
|
||||
|
||||
@@ -5,8 +5,19 @@ import CallbackHandler from 'langfuse-langchain'
|
||||
import lunary from 'lunary'
|
||||
import { RunTree, RunTreeConfig, Client as LangsmithClient } from 'langsmith'
|
||||
import { Langfuse, LangfuseTraceClient, LangfuseSpanClient, LangfuseGenerationClient } from 'langfuse'
|
||||
import { LangChainInstrumentation } from '@arizeai/openinference-instrumentation-langchain'
|
||||
import { Metadata } from '@grpc/grpc-js'
|
||||
import opentelemetry, { Span, SpanStatusCode } from '@opentelemetry/api'
|
||||
import { OTLPTraceExporter as GrpcOTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'
|
||||
import { OTLPTraceExporter as ProtoOTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
|
||||
import { registerInstrumentations } from '@opentelemetry/instrumentation'
|
||||
import { Resource } from '@opentelemetry/resources'
|
||||
import { SimpleSpanProcessor, Tracer } from '@opentelemetry/sdk-trace-base'
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
|
||||
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'
|
||||
|
||||
import { BaseCallbackHandler, NewTokenIndices, HandleLLMNewTokenCallbackFields } from '@langchain/core/callbacks/base'
|
||||
import * as CallbackManagerModule from '@langchain/core/callbacks/manager'
|
||||
import { LangChainTracer, LangChainTracerFields } from '@langchain/core/tracers/tracer_langchain'
|
||||
import { BaseTracer, Run } from '@langchain/core/tracers/base'
|
||||
import { ChainValues } from '@langchain/core/utils/types'
|
||||
@@ -24,6 +35,91 @@ interface AgentRun extends Run {
|
||||
actions: AgentAction[]
|
||||
}
|
||||
|
||||
interface ArizeTracerOptions {
|
||||
apiKey: string
|
||||
spaceId: string
|
||||
baseUrl: string
|
||||
projectName: string
|
||||
sdkIntegration?: string
|
||||
sessionId?: string
|
||||
enableCallback?: boolean
|
||||
}
|
||||
|
||||
function getArizeTracer(options: ArizeTracerOptions): Tracer | undefined {
|
||||
const SEMRESATTRS_PROJECT_NAME = 'openinference.project.name'
|
||||
try {
|
||||
const metadata = new Metadata()
|
||||
metadata.set('api_key', options.apiKey)
|
||||
metadata.set('space_id', options.spaceId)
|
||||
const traceExporter = new GrpcOTLPTraceExporter({
|
||||
url: `${options.baseUrl}/v1`,
|
||||
metadata
|
||||
})
|
||||
const tracerProvider = new NodeTracerProvider({
|
||||
resource: new Resource({
|
||||
[ATTR_SERVICE_NAME]: options.projectName,
|
||||
[ATTR_SERVICE_VERSION]: '1.0.0',
|
||||
[SEMRESATTRS_PROJECT_NAME]: options.projectName,
|
||||
model_id: options.projectName
|
||||
})
|
||||
})
|
||||
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(traceExporter))
|
||||
if (options.enableCallback) {
|
||||
registerInstrumentations({
|
||||
instrumentations: []
|
||||
})
|
||||
const lcInstrumentation = new LangChainInstrumentation()
|
||||
lcInstrumentation.manuallyInstrument(CallbackManagerModule)
|
||||
tracerProvider.register()
|
||||
}
|
||||
return tracerProvider.getTracer(`arize-tracer-${uuidv4().toString()}`)
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG === 'true') console.error(`Error setting up Arize tracer: ${err.message}`)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
interface PhoenixTracerOptions {
|
||||
apiKey: string
|
||||
baseUrl: string
|
||||
projectName: string
|
||||
sdkIntegration?: string
|
||||
sessionId?: string
|
||||
enableCallback?: boolean
|
||||
}
|
||||
|
||||
function getPhoenixTracer(options: PhoenixTracerOptions): Tracer | undefined {
|
||||
const SEMRESATTRS_PROJECT_NAME = 'openinference.project.name'
|
||||
try {
|
||||
const traceExporter = new ProtoOTLPTraceExporter({
|
||||
url: `${options.baseUrl}/v1/traces`,
|
||||
headers: {
|
||||
api_key: options.apiKey
|
||||
}
|
||||
})
|
||||
const tracerProvider = new NodeTracerProvider({
|
||||
resource: new Resource({
|
||||
[ATTR_SERVICE_NAME]: options.projectName,
|
||||
[ATTR_SERVICE_VERSION]: '1.0.0',
|
||||
[SEMRESATTRS_PROJECT_NAME]: options.projectName
|
||||
})
|
||||
})
|
||||
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(traceExporter))
|
||||
if (options.enableCallback) {
|
||||
registerInstrumentations({
|
||||
instrumentations: []
|
||||
})
|
||||
const lcInstrumentation = new LangChainInstrumentation()
|
||||
lcInstrumentation.manuallyInstrument(CallbackManagerModule)
|
||||
tracerProvider.register()
|
||||
}
|
||||
return tracerProvider.getTracer(`phoenix-tracer-${uuidv4().toString()}`)
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG === 'true') console.error(`Error setting up Phoenix tracer: ${err.message}`)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetJsonSpaces() {
|
||||
try {
|
||||
return parseInt(getEnvironmentVariable('LOG_JSON_SPACES') ?? '2')
|
||||
@@ -420,6 +516,48 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO
|
||||
|
||||
const trace = langwatch.getTrace()
|
||||
callbacks.push(trace.getLangChainCallback())
|
||||
} else if (provider === 'arize') {
|
||||
const arizeApiKey = getCredentialParam('arizeApiKey', credentialData, nodeData)
|
||||
const arizeSpaceId = getCredentialParam('arizeSpaceId', credentialData, nodeData)
|
||||
const arizeEndpoint = getCredentialParam('arizeEndpoint', credentialData, nodeData)
|
||||
const arizeProject = analytic[provider].projectName as string
|
||||
|
||||
let arizeOptions: ArizeTracerOptions = {
|
||||
apiKey: arizeApiKey,
|
||||
spaceId: arizeSpaceId,
|
||||
baseUrl: arizeEndpoint ?? 'https://otlp.arize.com',
|
||||
projectName: arizeProject ?? 'default',
|
||||
sdkIntegration: 'Flowise',
|
||||
enableCallback: true
|
||||
}
|
||||
|
||||
if (options.chatId) arizeOptions.sessionId = options.chatId
|
||||
if (nodeData?.inputs?.analytics?.arize) {
|
||||
arizeOptions = { ...arizeOptions, ...nodeData?.inputs?.analytics?.arize }
|
||||
}
|
||||
|
||||
const tracer: Tracer | undefined = getArizeTracer(arizeOptions)
|
||||
callbacks.push(tracer)
|
||||
} else if (provider === 'phoenix') {
|
||||
const phoenixApiKey = getCredentialParam('phoenixApiKey', credentialData, nodeData)
|
||||
const phoenixEndpoint = getCredentialParam('phoenixEndpoint', credentialData, nodeData)
|
||||
const phoenixProject = analytic[provider].projectName as string
|
||||
|
||||
let phoenixOptions: PhoenixTracerOptions = {
|
||||
apiKey: phoenixApiKey,
|
||||
baseUrl: phoenixEndpoint ?? 'https://app.phoenix.arize.com',
|
||||
projectName: phoenixProject ?? 'default',
|
||||
sdkIntegration: 'Flowise',
|
||||
enableCallback: true
|
||||
}
|
||||
|
||||
if (options.chatId) phoenixOptions.sessionId = options.chatId
|
||||
if (nodeData?.inputs?.analytics?.phoenix) {
|
||||
phoenixOptions = { ...phoenixOptions, ...nodeData?.inputs?.analytics?.phoenix }
|
||||
}
|
||||
|
||||
const tracer: Tracer | undefined = getPhoenixTracer(phoenixOptions)
|
||||
callbacks.push(tracer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,6 +636,42 @@ export class AnalyticHandler {
|
||||
})
|
||||
|
||||
this.handlers['langWatch'] = { client: langwatch }
|
||||
} else if (provider === 'arize') {
|
||||
const arizeApiKey = getCredentialParam('arizeApiKey', credentialData, this.nodeData)
|
||||
const arizeSpaceId = getCredentialParam('arizeSpaceId', credentialData, this.nodeData)
|
||||
const arizeEndpoint = getCredentialParam('arizeEndpoint', credentialData, this.nodeData)
|
||||
const arizeProject = analytic[provider].projectName as string
|
||||
|
||||
let arizeOptions: ArizeTracerOptions = {
|
||||
apiKey: arizeApiKey,
|
||||
spaceId: arizeSpaceId,
|
||||
baseUrl: arizeEndpoint ?? 'https://otlp.arize.com',
|
||||
projectName: arizeProject ?? 'default',
|
||||
sdkIntegration: 'Flowise',
|
||||
enableCallback: false
|
||||
}
|
||||
|
||||
const arize: Tracer | undefined = getArizeTracer(arizeOptions)
|
||||
const rootSpan: Span | undefined = undefined
|
||||
|
||||
this.handlers['arize'] = { client: arize, arizeProject, rootSpan }
|
||||
} else if (provider === 'phoenix') {
|
||||
const phoenixApiKey = getCredentialParam('phoenixApiKey', credentialData, this.nodeData)
|
||||
const phoenixEndpoint = getCredentialParam('phoenixEndpoint', credentialData, this.nodeData)
|
||||
const phoenixProject = analytic[provider].projectName as string
|
||||
|
||||
let phoenixOptions: PhoenixTracerOptions = {
|
||||
apiKey: phoenixApiKey,
|
||||
baseUrl: phoenixEndpoint ?? 'https://app.phoenix.arize.com',
|
||||
projectName: phoenixProject ?? 'default',
|
||||
sdkIntegration: 'Flowise',
|
||||
enableCallback: false
|
||||
}
|
||||
|
||||
const phoenix: Tracer | undefined = getPhoenixTracer(phoenixOptions)
|
||||
const rootSpan: Span | undefined = undefined
|
||||
|
||||
this.handlers['phoenix'] = { client: phoenix, phoenixProject, rootSpan }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,7 +685,9 @@ export class AnalyticHandler {
|
||||
langSmith: {},
|
||||
langFuse: {},
|
||||
lunary: {},
|
||||
langWatch: {}
|
||||
langWatch: {},
|
||||
arize: {},
|
||||
phoenix: {}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) {
|
||||
@@ -625,6 +801,74 @@ export class AnalyticHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const tracer: Tracer | undefined = this.handlers['arize'].client
|
||||
let rootSpan: Span | undefined = this.handlers['arize'].rootSpan
|
||||
|
||||
if (!parentIds || !Object.keys(parentIds).length) {
|
||||
rootSpan = tracer ? tracer.startSpan('Flowise') : undefined
|
||||
if (rootSpan) {
|
||||
rootSpan.setAttribute('session.id', this.options.chatId)
|
||||
rootSpan.setAttribute('openinference.span.kind', 'CHAIN')
|
||||
rootSpan.setAttribute('input.value', input)
|
||||
rootSpan.setAttribute('input.mime_type', 'text/plain')
|
||||
rootSpan.setAttribute('output.value', '[Object]')
|
||||
rootSpan.setAttribute('output.mime_type', 'text/plain')
|
||||
rootSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
rootSpan.end()
|
||||
}
|
||||
this.handlers['arize'].rootSpan = rootSpan
|
||||
}
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const chainSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('openinference.span.kind', 'CHAIN')
|
||||
chainSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
chainSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const chainSpanId: any = chainSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['arize'].chainSpan = { [chainSpanId]: chainSpan }
|
||||
returnIds['arize'].chainSpan = chainSpanId
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const tracer: Tracer | undefined = this.handlers['phoenix'].client
|
||||
let rootSpan: Span | undefined = this.handlers['phoenix'].rootSpan
|
||||
|
||||
if (!parentIds || !Object.keys(parentIds).length) {
|
||||
rootSpan = tracer ? tracer.startSpan('Flowise') : undefined
|
||||
if (rootSpan) {
|
||||
rootSpan.setAttribute('session.id', this.options.chatId)
|
||||
rootSpan.setAttribute('openinference.span.kind', 'CHAIN')
|
||||
rootSpan.setAttribute('input.value', input)
|
||||
rootSpan.setAttribute('input.mime_type', 'text/plain')
|
||||
rootSpan.setAttribute('output.value', '[Object]')
|
||||
rootSpan.setAttribute('output.mime_type', 'text/plain')
|
||||
rootSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
rootSpan.end()
|
||||
}
|
||||
this.handlers['phoenix'].rootSpan = rootSpan
|
||||
}
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const chainSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('openinference.span.kind', 'CHAIN')
|
||||
chainSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
chainSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const chainSpanId: any = chainSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['phoenix'].chainSpan = { [chainSpanId]: chainSpan }
|
||||
returnIds['phoenix'].chainSpan = chainSpanId
|
||||
}
|
||||
|
||||
return returnIds
|
||||
}
|
||||
|
||||
@@ -682,6 +926,26 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const chainSpan: Span | undefined = this.handlers['arize'].chainSpan[returnIds['arize'].chainSpan]
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
chainSpan.setAttribute('output.mime_type', 'application/json')
|
||||
chainSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
chainSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const chainSpan: Span | undefined = this.handlers['phoenix'].chainSpan[returnIds['phoenix'].chainSpan]
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
chainSpan.setAttribute('output.mime_type', 'application/json')
|
||||
chainSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
chainSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onChainError(returnIds: ICommonObject, error: string | object, shutdown = false) {
|
||||
@@ -740,6 +1004,26 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const chainSpan: Span | undefined = this.handlers['arize'].chainSpan[returnIds['arize'].chainSpan]
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
chainSpan.setAttribute('error.mime_type', 'application/json')
|
||||
chainSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
chainSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const chainSpan: Span | undefined = this.handlers['phoenix'].chainSpan[returnIds['phoenix'].chainSpan]
|
||||
if (chainSpan) {
|
||||
chainSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
chainSpan.setAttribute('error.mime_type', 'application/json')
|
||||
chainSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
chainSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onLLMStart(name: string, input: string, parentIds: ICommonObject) {
|
||||
@@ -747,7 +1031,9 @@ export class AnalyticHandler {
|
||||
langSmith: {},
|
||||
langFuse: {},
|
||||
lunary: {},
|
||||
langWatch: {}
|
||||
langWatch: {},
|
||||
arize: {},
|
||||
phoenix: {}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) {
|
||||
@@ -807,6 +1093,44 @@ export class AnalyticHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const tracer: Tracer | undefined = this.handlers['arize'].client
|
||||
const rootSpan: Span | undefined = this.handlers['arize'].rootSpan
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const llmSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('openinference.span.kind', 'LLM')
|
||||
llmSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
llmSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const llmSpanId: any = llmSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['arize'].llmSpan = { [llmSpanId]: llmSpan }
|
||||
returnIds['arize'].llmSpan = llmSpanId
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const tracer: Tracer | undefined = this.handlers['phoenix'].client
|
||||
const rootSpan: Span | undefined = this.handlers['phoenix'].rootSpan
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const llmSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('openinference.span.kind', 'LLM')
|
||||
llmSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
llmSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const llmSpanId: any = llmSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['phoenix'].llmSpan = { [llmSpanId]: llmSpan }
|
||||
returnIds['phoenix'].llmSpan = llmSpanId
|
||||
}
|
||||
|
||||
return returnIds
|
||||
}
|
||||
|
||||
@@ -852,6 +1176,26 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const llmSpan: Span | undefined = this.handlers['arize'].llmSpan[returnIds['arize'].llmSpan]
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
llmSpan.setAttribute('output.mime_type', 'application/json')
|
||||
llmSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
llmSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const llmSpan: Span | undefined = this.handlers['phoenix'].llmSpan[returnIds['phoenix'].llmSpan]
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
llmSpan.setAttribute('output.mime_type', 'application/json')
|
||||
llmSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
llmSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onLLMError(returnIds: ICommonObject, error: string | object) {
|
||||
@@ -896,6 +1240,26 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const llmSpan: Span | undefined = this.handlers['arize'].llmSpan[returnIds['arize'].llmSpan]
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
llmSpan.setAttribute('error.mime_type', 'application/json')
|
||||
llmSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
llmSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const llmSpan: Span | undefined = this.handlers['phoenix'].llmSpan[returnIds['phoenix'].llmSpan]
|
||||
if (llmSpan) {
|
||||
llmSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
llmSpan.setAttribute('error.mime_type', 'application/json')
|
||||
llmSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
llmSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onToolStart(name: string, input: string | object, parentIds: ICommonObject) {
|
||||
@@ -903,7 +1267,9 @@ export class AnalyticHandler {
|
||||
langSmith: {},
|
||||
langFuse: {},
|
||||
lunary: {},
|
||||
langWatch: {}
|
||||
langWatch: {},
|
||||
arize: {},
|
||||
phoenix: {}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) {
|
||||
@@ -964,6 +1330,44 @@ export class AnalyticHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const tracer: Tracer | undefined = this.handlers['arize'].client
|
||||
const rootSpan: Span | undefined = this.handlers['arize'].rootSpan
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const toolSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('openinference.span.kind', 'TOOL')
|
||||
toolSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
toolSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const toolSpanId: any = toolSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['arize'].toolSpan = { [toolSpanId]: toolSpan }
|
||||
returnIds['arize'].toolSpan = toolSpanId
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const tracer: Tracer | undefined = this.handlers['phoenix'].client
|
||||
const rootSpan: Span | undefined = this.handlers['phoenix'].rootSpan
|
||||
|
||||
const rootSpanContext = rootSpan
|
||||
? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span)
|
||||
: opentelemetry.context.active()
|
||||
const toolSpan = tracer?.startSpan(name, undefined, rootSpanContext)
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('openinference.span.kind', 'TOOL')
|
||||
toolSpan.setAttribute('input.value', JSON.stringify(input))
|
||||
toolSpan.setAttribute('input.mime_type', 'application/json')
|
||||
}
|
||||
const toolSpanId: any = toolSpan?.spanContext().spanId
|
||||
|
||||
this.handlers['phoenix'].toolSpan = { [toolSpanId]: toolSpan }
|
||||
returnIds['phoenix'].toolSpan = toolSpanId
|
||||
}
|
||||
|
||||
return returnIds
|
||||
}
|
||||
|
||||
@@ -1009,6 +1413,26 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const toolSpan: Span | undefined = this.handlers['arize'].toolSpan[returnIds['arize'].toolSpan]
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
toolSpan.setAttribute('output.mime_type', 'application/json')
|
||||
toolSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
toolSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const toolSpan: Span | undefined = this.handlers['phoenix'].toolSpan[returnIds['phoenix'].toolSpan]
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('output.value', JSON.stringify(output))
|
||||
toolSpan.setAttribute('output.mime_type', 'application/json')
|
||||
toolSpan.setStatus({ code: SpanStatusCode.OK })
|
||||
toolSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onToolError(returnIds: ICommonObject, error: string | object) {
|
||||
@@ -1053,5 +1477,25 @@ export class AnalyticHandler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'arize')) {
|
||||
const toolSpan: Span | undefined = this.handlers['arize'].toolSpan[returnIds['arize'].toolSpan]
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
toolSpan.setAttribute('error.mime_type', 'application/json')
|
||||
toolSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
toolSpan.end()
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.handlers, 'phoenix')) {
|
||||
const toolSpan: Span | undefined = this.handlers['phoenix'].toolSpan[returnIds['phoenix'].toolSpan]
|
||||
if (toolSpan) {
|
||||
toolSpan.setAttribute('error.value', JSON.stringify(error))
|
||||
toolSpan.setAttribute('error.mime_type', 'application/json')
|
||||
toolSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() })
|
||||
toolSpan.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -28,6 +28,8 @@ import langsmithPNG from '@/assets/images/langchain.png'
|
||||
import langfuseSVG from '@/assets/images/langfuse.svg'
|
||||
import lunarySVG from '@/assets/images/lunary.svg'
|
||||
import langwatchSVG from '@/assets/images/langwatch.svg'
|
||||
import arizePNG from '@/assets/images/arize.png'
|
||||
import phoenixPNG from '@/assets/images/phoenix.png'
|
||||
|
||||
// store
|
||||
import useNotifier from '@/utils/useNotifier'
|
||||
@@ -130,6 +132,62 @@ const analyticProviders = [
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Arize',
|
||||
name: 'arize',
|
||||
icon: arizePNG,
|
||||
url: 'https://arize.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['arizeApi']
|
||||
},
|
||||
{
|
||||
label: 'Project Name',
|
||||
name: 'projectName',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'If not provided, default will be used.',
|
||||
placeholder: 'default'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Phoenix',
|
||||
name: 'phoenix',
|
||||
icon: phoenixPNG,
|
||||
url: 'https://phoenix.arize.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['phoenixApi']
|
||||
},
|
||||
{
|
||||
label: 'Project Name',
|
||||
name: 'projectName',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'If not provided, default will be used.',
|
||||
placeholder: 'default'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
Generated
+35596
-35625
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user