LunaryAI automatic Thread and User tracking (#3233)
* Lunary Thread/User tracking * Clean console logs * Clean * Remove commented lines * Remove commented line
This commit is contained in:
parent
8690c43ef5
commit
18f916a7e1
|
|
@ -8,22 +8,23 @@ class LunaryApi implements INodeCredential {
|
||||||
inputs: INodeParams[]
|
inputs: INodeParams[]
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.label = 'Lunary API'
|
this.label = 'Lunary AI'
|
||||||
this.name = 'lunaryApi'
|
this.name = 'lunaryApi'
|
||||||
this.version = 1.0
|
this.version = 1.0
|
||||||
this.description = 'Refer to <a target="_blank" href="https://lunary.ai/docs">official guide</a> to get APP ID'
|
this.description =
|
||||||
|
'Refer to the <a target="_blank" href="https://lunary.ai/docs?utm_source=flowise">official guide</a> to get a public key.'
|
||||||
this.inputs = [
|
this.inputs = [
|
||||||
{
|
{
|
||||||
label: 'APP ID',
|
label: 'Public Key / Project ID',
|
||||||
name: 'lunaryAppId',
|
name: 'lunaryAppId',
|
||||||
type: 'password',
|
type: 'string',
|
||||||
placeholder: '<Lunary_APP_ID>'
|
placeholder: '<Lunary_PROJECT_ID>'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Endpoint',
|
label: 'Endpoint',
|
||||||
name: 'lunaryEndpoint',
|
name: 'lunaryEndpoint',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'https://app.lunary.ai'
|
default: 'https://api.lunary.ai'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,26 @@
|
||||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg height="216" viewBox="0 0 216 216" width="216" xmlns="http://www.w3.org/2000/svg">
|
||||||
<ellipse cx="15.9562" cy="16.0002" rx="4.3478" ry="4.34782" stroke="black" stroke-width="2"/>
|
<defs>
|
||||||
<path d="M23.5651 23.6086C21.603 25.621 18.8688 26.8695 15.8445 26.8695C10.2386 26.8695 5.62933 22.5797 5.08691 17.0869" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
<linearGradient id="blue-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
<path d="M8.34766 8.23751C10.314 6.3155 13.0074 5.13037 15.9785 5.13037C21.6311 5.13037 26.2789 9.42024 26.8258 14.913" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
<stop offset="0%" style="stop-color:#006dcc;stop-opacity:1" />
|
||||||
<path d="M9.5217 9.47815C9.5217 10.7268 8.50948 11.739 7.26085 11.739C6.01222 11.739 5 10.7268 5 9.47815C5 8.22951 6.01222 7.21729 7.26085 7.21729C8.50948 7.21729 9.5217 8.22951 9.5217 9.47815Z" fill="black" stroke="black" stroke-width="2"/>
|
<stop offset="100%" style="stop-color:#3aa4ff;stop-opacity:1" />
|
||||||
<path d="M28.0002 21.4347C28.0002 22.6833 26.988 23.6956 25.7394 23.6956C24.4907 23.6956 23.4785 22.6833 23.4785 21.4347C23.4785 20.186 24.4907 19.1738 25.7394 19.1738C26.988 19.1738 28.0002 20.186 28.0002 21.4347Z" fill="black" stroke="black" stroke-width="2"/>
|
</linearGradient>
|
||||||
|
<filter id="shadow" x="-2%" y="-2%" width="110%" height="110%" filterUnits="objectBoundingBox" >
|
||||||
|
<feOffset result="offOut" in="SourceAlpha" dx="2" dy="3" />
|
||||||
|
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="4" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA type="linear" slope="0.1" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<rect x="8" y="8" width="200" height="200" rx="45" ry="45" fill="url(#blue-gradient)" fill-rule="nonzero" filter="url(#shadow)" style="filter: drop-shadow(2px 3px 4px rgba(128, 128, 128, 0.8));" />
|
||||||
|
<g stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="15" transform="translate(42 42)">
|
||||||
|
<path d="m132 58c-.991994-7.1686791-3.094482-13.9665431-6.127891-20.2149374-9.6743-19.9276923-28.8172875-34.26655561-51.6037985-37.22124123-26.5813666-3.47510895-52.6608614 9.32644484-66.2683105 32.52890253"/>
|
||||||
|
<path d="m0 74c3.9198666 28.335939 25.2597454 51.079666 53.1909971 56.69018 27.9312514 5.610514 56.3393579-7.140402 70.8090029-31.782463"/>
|
||||||
|
<path d="m123.5 108c4.69442 0 8.5-3.80558 8.5-8.5 0-4.6944203-3.80558-8.5-8.5-8.5s-8.5 3.8055797-8.5 8.5c0 4.69442 3.80558 8.5 8.5 8.5z"/>
|
||||||
|
<path d="m8.5 42c4.6944204 0 8.5-3.8055796 8.5-8.5s-3.8055796-8.5-8.5-8.5c-4.69442035 0-8.5 3.8055796-8.5 8.5s3.80557965 8.5 8.5 8.5z"/>
|
||||||
|
<path d="m66 91c13.8071191 0 25-11.1928809 25-25 0-13.8071187-11.1928809-25-25-25-13.8071187 0-25 11.1928813-25 25 0 13.8071191 11.1928813 25 25 25z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
|
@ -93,7 +93,7 @@
|
||||||
"linkifyjs": "^4.1.1",
|
"linkifyjs": "^4.1.1",
|
||||||
"llamaindex": "^0.3.13",
|
"llamaindex": "^0.3.13",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lunary": "^0.7.10",
|
"lunary": "^0.7.12",
|
||||||
"mammoth": "^1.5.1",
|
"mammoth": "^1.5.1",
|
||||||
"meilisearch": "^0.41.0",
|
"meilisearch": "^0.41.0",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.3",
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ import { AgentAction } from '@langchain/core/agents'
|
||||||
import { LunaryHandler } from '@langchain/community/callbacks/handlers/lunary'
|
import { LunaryHandler } from '@langchain/community/callbacks/handlers/lunary'
|
||||||
|
|
||||||
import { getCredentialData, getCredentialParam, getEnvironmentVariable } from './utils'
|
import { getCredentialData, getCredentialParam, getEnvironmentVariable } from './utils'
|
||||||
import { ICommonObject, INodeData, IServerSideEventStreamer } from './Interface'
|
import { ICommonObject, IDatabaseEntity, INodeData, IServerSideEventStreamer } from './Interface'
|
||||||
import { LangWatch, LangWatchSpan, LangWatchTrace, autoconvertTypedValues } from 'langwatch'
|
import { LangWatch, LangWatchSpan, LangWatchTrace, autoconvertTypedValues } from 'langwatch'
|
||||||
|
import { DataSource } from 'typeorm'
|
||||||
|
|
||||||
interface AgentRun extends Run {
|
interface AgentRun extends Run {
|
||||||
actions: AgentAction[]
|
actions: AgentAction[]
|
||||||
|
|
@ -90,6 +91,7 @@ export class ConsoleCallbackHandler extends BaseTracer {
|
||||||
|
|
||||||
onChainStart(run: Run) {
|
onChainStart(run: Run) {
|
||||||
const crumbs = this.getBreadcrumbs(run)
|
const crumbs = this.getBreadcrumbs(run)
|
||||||
|
|
||||||
this.logger.verbose(`[chain/start] [${crumbs}] Entering Chain run with input: ${tryJsonStringify(run.inputs, '[inputs]')}`)
|
this.logger.verbose(`[chain/start] [${crumbs}] Entering Chain run with input: ${tryJsonStringify(run.inputs, '[inputs]')}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,6 +237,78 @@ export class CustomChainHandler extends BaseCallbackHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ExtendedLunaryHandler extends LunaryHandler {
|
||||||
|
chatId: string
|
||||||
|
appDataSource: DataSource
|
||||||
|
databaseEntities: IDatabaseEntity
|
||||||
|
currentRunId: string | null
|
||||||
|
thread: any
|
||||||
|
|
||||||
|
constructor({ flowiseOptions, ...options }: any) {
|
||||||
|
super(options)
|
||||||
|
this.appDataSource = flowiseOptions.appDataSource
|
||||||
|
this.databaseEntities = flowiseOptions.databaseEntities
|
||||||
|
this.chatId = flowiseOptions.chatId
|
||||||
|
}
|
||||||
|
|
||||||
|
async initThread() {
|
||||||
|
const entity = await this.appDataSource.getRepository(this.databaseEntities['Lead']).findOne({
|
||||||
|
where: {
|
||||||
|
chatId: this.chatId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.thread = lunary.openThread({
|
||||||
|
id: this.chatId,
|
||||||
|
userId: entity?.email ?? entity?.id,
|
||||||
|
userProps: {
|
||||||
|
name: entity?.name ?? undefined,
|
||||||
|
email: entity?.email ?? undefined,
|
||||||
|
phone: entity?.phone ?? undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleChainStart(chain: any, inputs: any, runId: string, parentRunId?: string, tags?: string[], metadata?: any): Promise<void> {
|
||||||
|
// First chain (no parent run id) is the user message
|
||||||
|
if (this.chatId && !parentRunId) {
|
||||||
|
if (!this.thread) {
|
||||||
|
await this.initThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageText = inputs.input
|
||||||
|
|
||||||
|
const messageId = this.thread.trackMessage({
|
||||||
|
content: messageText,
|
||||||
|
role: 'user'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Track top level chain id for knowing when we got the final reply
|
||||||
|
this.currentRunId = runId
|
||||||
|
|
||||||
|
// Use the messageId as the parent of the chain for reconciliation
|
||||||
|
super.handleChainStart(chain, inputs, runId, messageId, tags, metadata)
|
||||||
|
} else {
|
||||||
|
super.handleChainStart(chain, inputs, runId, parentRunId, tags, metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleChainEnd(outputs: ChainValues, runId: string): Promise<void> {
|
||||||
|
if (this.chatId && runId === this.currentRunId) {
|
||||||
|
const answer = outputs.output
|
||||||
|
|
||||||
|
this.thread.trackMessage({
|
||||||
|
content: answer,
|
||||||
|
role: 'assistant'
|
||||||
|
})
|
||||||
|
|
||||||
|
this.currentRunId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
super.handleChainEnd(outputs, runId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const additionalCallbacks = async (nodeData: INodeData, options: ICommonObject) => {
|
export const additionalCallbacks = async (nodeData: INodeData, options: ICommonObject) => {
|
||||||
try {
|
try {
|
||||||
if (!options.analytic) return []
|
if (!options.analytic) return []
|
||||||
|
|
@ -293,19 +367,22 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO
|
||||||
const handler = new CallbackHandler(langFuseOptions)
|
const handler = new CallbackHandler(langFuseOptions)
|
||||||
callbacks.push(handler)
|
callbacks.push(handler)
|
||||||
} else if (provider === 'lunary') {
|
} else if (provider === 'lunary') {
|
||||||
const lunaryAppId = getCredentialParam('lunaryAppId', credentialData, nodeData)
|
const lunaryPublicKey = getCredentialParam('lunaryAppId', credentialData, nodeData)
|
||||||
const lunaryEndpoint = getCredentialParam('lunaryEndpoint', credentialData, nodeData)
|
const lunaryEndpoint = getCredentialParam('lunaryEndpoint', credentialData, nodeData)
|
||||||
|
|
||||||
let lunaryFields = {
|
let lunaryFields = {
|
||||||
appId: lunaryAppId,
|
publicKey: lunaryPublicKey,
|
||||||
apiUrl: lunaryEndpoint ?? 'https://app.lunary.ai'
|
apiUrl: lunaryEndpoint ?? 'https://api.lunary.ai',
|
||||||
|
runtime: 'flowise',
|
||||||
|
flowiseOptions: options
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeData?.inputs?.analytics?.lunary) {
|
if (nodeData?.inputs?.analytics?.lunary) {
|
||||||
lunaryFields = { ...lunaryFields, ...nodeData?.inputs?.analytics?.lunary }
|
lunaryFields = { ...lunaryFields, ...nodeData?.inputs?.analytics?.lunary }
|
||||||
}
|
}
|
||||||
|
|
||||||
const handler = new LunaryHandler(lunaryFields)
|
const handler = new ExtendedLunaryHandler(lunaryFields)
|
||||||
|
|
||||||
callbacks.push(handler)
|
callbacks.push(handler)
|
||||||
} else if (provider === 'langWatch') {
|
} else if (provider === 'langWatch') {
|
||||||
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, nodeData)
|
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, nodeData)
|
||||||
|
|
@ -376,12 +453,13 @@ export class AnalyticHandler {
|
||||||
})
|
})
|
||||||
this.handlers['langFuse'] = { client: langfuse }
|
this.handlers['langFuse'] = { client: langfuse }
|
||||||
} else if (provider === 'lunary') {
|
} else if (provider === 'lunary') {
|
||||||
const lunaryAppId = getCredentialParam('lunaryAppId', credentialData, this.nodeData)
|
const lunaryPublicKey = getCredentialParam('lunaryAppId', credentialData, this.nodeData)
|
||||||
const lunaryEndpoint = getCredentialParam('lunaryEndpoint', credentialData, this.nodeData)
|
const lunaryEndpoint = getCredentialParam('lunaryEndpoint', credentialData, this.nodeData)
|
||||||
|
|
||||||
lunary.init({
|
lunary.init({
|
||||||
appId: lunaryAppId,
|
publicKey: lunaryPublicKey,
|
||||||
apiUrl: lunaryEndpoint
|
apiUrl: lunaryEndpoint,
|
||||||
|
runtime: 'flowise'
|
||||||
})
|
})
|
||||||
|
|
||||||
this.handlers['lunary'] = { client: lunary }
|
this.handlers['lunary'] = { client: lunary }
|
||||||
|
|
@ -487,7 +565,6 @@ export class AnalyticHandler {
|
||||||
await monitor.trackEvent('chain', 'start', {
|
await monitor.trackEvent('chain', 'start', {
|
||||||
runId,
|
runId,
|
||||||
name,
|
name,
|
||||||
userId: this.options.chatId,
|
|
||||||
input,
|
input,
|
||||||
...this.nodeData?.inputs?.analytics?.lunary
|
...this.nodeData?.inputs?.analytics?.lunary
|
||||||
})
|
})
|
||||||
|
|
@ -686,7 +763,6 @@ export class AnalyticHandler {
|
||||||
runId,
|
runId,
|
||||||
parentRunId: chainEventId,
|
parentRunId: chainEventId,
|
||||||
name,
|
name,
|
||||||
userId: this.options.chatId,
|
|
||||||
input
|
input
|
||||||
})
|
})
|
||||||
this.handlers['lunary'].llmEvent = { [runId]: runId }
|
this.handlers['lunary'].llmEvent = { [runId]: runId }
|
||||||
|
|
@ -843,7 +919,6 @@ export class AnalyticHandler {
|
||||||
runId,
|
runId,
|
||||||
parentRunId: chainEventId,
|
parentRunId: chainEventId,
|
||||||
name,
|
name,
|
||||||
userId: this.options.chatId,
|
|
||||||
input
|
input
|
||||||
})
|
})
|
||||||
this.handlers['lunary'].toolEvent = { [runId]: runId }
|
this.handlers['lunary'].toolEvent = { [runId]: runId }
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import { ChatMessage } from '../database/entities/ChatMessage'
|
||||||
import { Credential } from '../database/entities/Credential'
|
import { Credential } from '../database/entities/Credential'
|
||||||
import { Tool } from '../database/entities/Tool'
|
import { Tool } from '../database/entities/Tool'
|
||||||
import { Assistant } from '../database/entities/Assistant'
|
import { Assistant } from '../database/entities/Assistant'
|
||||||
|
import { Lead } from '../database/entities/Lead'
|
||||||
import { DataSource } from 'typeorm'
|
import { DataSource } from 'typeorm'
|
||||||
import { CachePool } from '../CachePool'
|
import { CachePool } from '../CachePool'
|
||||||
import { Variable } from '../database/entities/Variable'
|
import { Variable } from '../database/entities/Variable'
|
||||||
|
|
@ -55,6 +56,7 @@ export const databaseEntities: IDatabaseEntity = {
|
||||||
ChatMessage: ChatMessage,
|
ChatMessage: ChatMessage,
|
||||||
Tool: Tool,
|
Tool: Tool,
|
||||||
Credential: Credential,
|
Credential: Credential,
|
||||||
|
Lead: Lead,
|
||||||
Assistant: Assistant,
|
Assistant: Assistant,
|
||||||
Variable: Variable,
|
Variable: Variable,
|
||||||
DocumentStore: DocumentStore,
|
DocumentStore: DocumentStore,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,26 @@
|
||||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg height="216" viewBox="0 0 216 216" width="216" xmlns="http://www.w3.org/2000/svg">
|
||||||
<ellipse cx="15.9562" cy="16.0002" rx="4.3478" ry="4.34782" stroke="black" stroke-width="2"/>
|
<defs>
|
||||||
<path d="M23.5651 23.6086C21.603 25.621 18.8688 26.8695 15.8445 26.8695C10.2386 26.8695 5.62933 22.5797 5.08691 17.0869" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
<linearGradient id="blue-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
<path d="M8.34766 8.23751C10.314 6.3155 13.0074 5.13037 15.9785 5.13037C21.6311 5.13037 26.2789 9.42024 26.8258 14.913" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
<stop offset="0%" style="stop-color:#006dcc;stop-opacity:1" />
|
||||||
<path d="M9.5217 9.47815C9.5217 10.7268 8.50948 11.739 7.26085 11.739C6.01222 11.739 5 10.7268 5 9.47815C5 8.22951 6.01222 7.21729 7.26085 7.21729C8.50948 7.21729 9.5217 8.22951 9.5217 9.47815Z" fill="black" stroke="black" stroke-width="2"/>
|
<stop offset="100%" style="stop-color:#3aa4ff;stop-opacity:1" />
|
||||||
<path d="M28.0002 21.4347C28.0002 22.6833 26.988 23.6956 25.7394 23.6956C24.4907 23.6956 23.4785 22.6833 23.4785 21.4347C23.4785 20.186 24.4907 19.1738 25.7394 19.1738C26.988 19.1738 28.0002 20.186 28.0002 21.4347Z" fill="black" stroke="black" stroke-width="2"/>
|
</linearGradient>
|
||||||
|
<filter id="shadow" x="-2%" y="-2%" width="110%" height="110%" filterUnits="objectBoundingBox" >
|
||||||
|
<feOffset result="offOut" in="SourceAlpha" dx="2" dy="3" />
|
||||||
|
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="4" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA type="linear" slope="0.1" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<rect x="8" y="8" width="200" height="200" rx="45" ry="45" fill="url(#blue-gradient)" fill-rule="nonzero" filter="url(#shadow)" style="filter: drop-shadow(2px 3px 4px rgba(128, 128, 128, 0.5));" />
|
||||||
|
<g stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="15" transform="translate(51 51) scale(0.89)">
|
||||||
|
<path d="m132 58c-.991994-7.1686791-3.094482-13.9665431-6.127891-20.2149374-9.6743-19.9276923-28.8172875-34.26655561-51.6037985-37.22124123-26.5813666-3.47510895-52.6608614 9.32644484-66.2683105 32.52890253"/>
|
||||||
|
<path d="m0 74c3.9198666 28.335939 25.2597454 51.079666 53.1909971 56.69018 27.9312514 5.610514 56.3393579-7.140402 70.8090029-31.782463"/>
|
||||||
|
<path d="m123.5 108c4.69442 0 8.5-3.80558 8.5-8.5 0-4.6944203-3.80558-8.5-8.5-8.5s-8.5 3.8055797-8.5 8.5c0 4.69442 3.80558 8.5 8.5 8.5z"/>
|
||||||
|
<path d="m8.5 42c4.6944204 0 8.5-3.8055796 8.5-8.5s-3.8055796-8.5-8.5-8.5c-4.69442035 0-8.5 3.8055796-8.5 8.5s3.80557965 8.5 8.5 8.5z"/>
|
||||||
|
<path d="m66 91c13.8071191 0 25-11.1928809 25-25 0-13.8071187-11.1928809-25-25-25-13.8071187 0-25 11.1928813-25 25 0 13.8071191 11.1928813 25 25 25z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.9 KiB |
65071
pnpm-lock.yaml
65071
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue