Skip to content

Commit

Permalink
Add LangWatch integration (FlowiseAI#2677)
Browse files Browse the repository at this point in the history
Add langwatch integration
  • Loading branch information
rogeriochaves committed Jun 21, 2024
1 parent aec9e7a commit 0fc5e3d
Show file tree
Hide file tree
Showing 9 changed files with 1,014 additions and 218 deletions.
33 changes: 33 additions & 0 deletions packages/components/credentials/LangWatchApi.credential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { INodeParams, INodeCredential } from '../src/Interface'

class LangWatchApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]

constructor() {
this.label = 'LangWatch API'
this.name = 'langwatchApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://docs.langwatch.ai/integration/python/guide">integration guide</a> on how to get API keys on LangWatch'
this.inputs = [
{
label: 'API Key',
name: 'langWatchApiKey',
type: 'password',
placeholder: '<LANGWATCH_API_KEY>'
},
{
label: 'Endpoint',
name: 'langWatchEndpoint',
type: 'string',
default: 'https://app.langwatch.ai'
}
]
}
}

module.exports = { credClass: LangWatchApi }
3 changes: 3 additions & 0 deletions packages/components/nodes/analytic/LangWatch/LangWatch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions packages/components/nodes/analytic/LangWatch/LangWatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { INode, INodeParams } from '../../../src/Interface'

class LangWatch_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 = 'LangWatch'
this.name = 'LangWatch'
this.version = 1.0
this.type = 'LangWatch'
this.icon = 'LangWatch.svg'
this.category = 'Analytic'
this.baseClasses = [this.type]
this.inputs = []
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['langwatchApi']
}
}
}

module.exports = { nodeClass: LangWatch_Analytic }
1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"langfuse": "3.3.4",
"langfuse-langchain": "^3.3.4",
"langsmith": "0.1.6",
"langwatch": "^0.1.1",
"linkifyjs": "^4.1.1",
"llamaindex": "^0.3.13",
"lodash": "^4.17.21",
Expand Down
131 changes: 130 additions & 1 deletion packages/components/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LunaryHandler } from '@langchain/community/callbacks/handlers/lunary'

import { getCredentialData, getCredentialParam, getEnvironmentVariable } from './utils'
import { ICommonObject, INodeData } from './Interface'
import { LangWatch, LangWatchSpan, LangWatchTrace, autoconvertTypedValues } from 'langwatch'

interface AgentRun extends Run {
actions: AgentAction[]
Expand Down Expand Up @@ -293,6 +294,17 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO

const handler = new LunaryHandler(lunaryFields)
callbacks.push(handler)
} else if (provider === 'langWatch') {
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, nodeData)
const langWatchEndpoint = getCredentialParam('langWatchEndpoint', credentialData, nodeData)

const langwatch = new LangWatch({
apiKey: langWatchApiKey,
endpoint: langWatchEndpoint
})

const trace = langwatch.getTrace()
callbacks.push(trace.getLangChainCallback())
}
}
}
Expand Down Expand Up @@ -360,6 +372,16 @@ export class AnalyticHandler {
})

this.handlers['lunary'] = { client: lunary }
} else if (provider === 'langWatch') {
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, this.nodeData)
const langWatchEndpoint = getCredentialParam('langWatchEndpoint', credentialData, this.nodeData)

const langwatch = new LangWatch({
apiKey: langWatchApiKey,
endpoint: langWatchEndpoint
})

this.handlers['langWatch'] = { client: langwatch }
}
}
}
Expand All @@ -372,7 +394,8 @@ export class AnalyticHandler {
const returnIds: ICommonObject = {
langSmith: {},
langFuse: {},
lunary: {}
lunary: {},
langWatch: {}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) {
Expand Down Expand Up @@ -460,6 +483,33 @@ export class AnalyticHandler {
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
let langwatchTrace: LangWatchTrace

if (!parentIds || !Object.keys(parentIds).length) {
const langwatch: LangWatch = this.handlers['langWatch'].client
langwatchTrace = langwatch.getTrace({
name,
metadata: { tags: ['openai-assistant'], threadId: this.options.chatId },
...this.nodeData?.inputs?.analytics?.langWatch
})
} else {
langwatchTrace = this.handlers['langWatch'].trace[parentIds['langWatch']]
}

if (langwatchTrace) {
const span = langwatchTrace.startSpan({
name,
type: 'chain',
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].trace = { [langwatchTrace.traceId]: langwatchTrace }
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].trace = langwatchTrace.traceId
returnIds['langWatch'].span = span.spanId
}
}

return returnIds
}

Expand Down Expand Up @@ -508,6 +558,15 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}

async onChainError(returnIds: ICommonObject, error: string | object, shutdown = false) {
Expand Down Expand Up @@ -557,6 +616,15 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}

async onLLMStart(name: string, input: string, parentIds: ICommonObject) {
Expand Down Expand Up @@ -612,6 +680,18 @@ export class AnalyticHandler {
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const trace: LangWatchTrace | undefined = this.handlers['langWatch'].trace[parentIds['langWatch'].trace]
if (trace) {
const span = trace.startLLMSpan({
name,
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].span = span.spanId
}
}

return returnIds
}

Expand Down Expand Up @@ -648,6 +728,15 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}

async onLLMError(returnIds: ICommonObject, error: string | object) {
Expand Down Expand Up @@ -683,6 +772,15 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}

async onToolStart(name: string, input: string | object, parentIds: ICommonObject) {
Expand Down Expand Up @@ -738,6 +836,19 @@ export class AnalyticHandler {
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const trace: LangWatchTrace | undefined = this.handlers['langWatch'].trace[parentIds['langWatch'].trace]
if (trace) {
const span = trace.startSpan({
name,
type: 'tool',
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].span = span.spanId
}
}

return returnIds
}

Expand Down Expand Up @@ -774,6 +885,15 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}

async onToolError(returnIds: ICommonObject, error: string | object) {
Expand Down Expand Up @@ -809,5 +929,14 @@ export class AnalyticHandler {
})
}
}

if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}
}
1 change: 1 addition & 0 deletions packages/components/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const availableDependencies = [
'langchain',
'langfuse',
'langsmith',
'langwatch',
'linkifyjs',
'lunary',
'mammoth',
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/assets/images/langwatch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions packages/ui/src/ui-component/extended/AnalyseFlow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { StyledButton } from '@/ui-component/button/StyledButton'
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'

// store
import useNotifier from '@/utils/useNotifier'
Expand Down Expand Up @@ -109,6 +110,26 @@ const analyticProviders = [
optional: true
}
]
},
{
label: 'LangWatch',
name: 'langWatch',
icon: langwatchSVG,
url: 'https://langwatch.com',
inputs: [
{
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['langwatchApi']
},
{
label: 'On/Off',
name: 'status',
type: 'boolean',
optional: true
}
]
}
]

Expand Down
Loading

0 comments on commit 0fc5e3d

Please sign in to comment.