Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions lib/llm-events/langchain/attach-attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2026 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'

module.exports = attachAttributes

const { isSimpleObject } = require('#agentlib/util/objects.js')

/**
* Applies common attributes to the various LangChain object types. We can't
* inline this to a common base class, because they all need to inherit from
* disparate base classes.
*
* @param {object} params Function parameters
* @param {object} params.target The LLM event object to decorate.
* @param {object} [params.agent] The agent instance.
* @param {object} [params.metadata] A set of key-value pairs to attach.
* @param {string|string[]} [params.tags] A comma separated list of tags, or an
* array of string tags.
*/
function attachAttributes({ target, agent = null, metadata = null, tags = null }) {
if (agent) {
target.appName = agent.config.applications()[0]
}

if (isSimpleObject(metadata) === true) {
target.langchainMeta = metadata
for (const [k, v] of Object.entries(metadata)) {
target[`metadata.${k}`] = v
}
}

if (Array.isArray(tags) === true) {
target.tags = tags.join(',')
} else if (typeof tags === 'string') {
target.tags = tags
}
}
100 changes: 39 additions & 61 deletions lib/llm-events/langchain/chat-completion-message.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,50 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* Copyright 2026 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'
const LlmChatCompletionMessage = require('../chat-completion-message')
const attachAttributes = require('./attach-attributes')

const LangChainEvent = require('./event')
const { makeId } = require('../../util/hashes')

/**
* @typedef {object} LangChainCompletionMessageParams
* @augments LangChainEventParams
* @property {string} content The text of the response received from LangChain.
* @property {number} [sequence=0] The order of the message in the response.
* @property {string} [completionId] An identifier for the message.
* @property {boolean|undefined} [isResponse] Indicates if the completion
* message represents a response from the remote service.
*/
/**
* @type {LangChainCompletionMessageParams}
* Encapsulates a LangChain LlmChatCompletionMessage.
*/
const defaultParams = {
content: '',
role: null,
sequence: 0,
completionId: makeId(36),
isResponse: undefined
}

class LangChainCompletionMessage extends LangChainEvent {
content
role
sequence
completion_id
is_response

constructor(params = defaultParams) {
params = Object.assign({}, defaultParams, params)
super(params)
const { agent, runId, segment, sequence, role, content, completionId, isResponse } = params

if (runId) {
this.id = `${runId}-${sequence}`
} else {
this.id = `${this.id}-${sequence}`
}

this.sequence = sequence
this.completion_id = completionId

this.is_response = isResponse ?? false
if (this.is_response === false) {
// `timestamp` is only required for input/request messages.
this.timestamp = segment.timer.start
}

if (role) {
this.role = role
} else {
// As a backup, we can infer the role based on if it
// is a response or not.
this.role = this.is_response ? 'assistant' : 'user'
}

if (agent.config.ai_monitoring.record_content.enabled === true) {
this.content = content
}
class LangChainLlmChatCompletionMessage extends LlmChatCompletionMessage {
virtual_llm = true

/**
* @param {object} params constructor parameters
* @param {Agent} params.agent New Relic agent instance
* @param {object} params.segment Current segment
* @param {object} params.transaction Current and active transaction
* @param {string} params.runId LangChain run ID (will be used as response ID)
* @param {number} params.sequence Index (beginning at 0) associated with
* each message including the prompt and responses
* @param {string} params.content Content of the message
* @param {string} [params.role] Role of the message creator (e.g. `user`, `assistant`, `tool`)
* @param {string} params.completionId ID of the `LlmChatCompletionSummary` event that
* this message event is connected to
* @param {boolean} [params.isResponse] `true` if a message is the result of a chat
* completion and not an input message - omitted in `false` cases
* @param {object} params.metadata LangChain metadata object
* @param {string[]|string} params.tags LangChain tags, can be an array of strings or a comma-seperated string
*/
constructor({ agent, segment, transaction, runId, sequence, role, content, completionId, isResponse, metadata = {}, tags = '' }) {
super({ agent,
segment,
transaction,
vendor: 'langchain',
responseId: runId,
requestId: runId,
sequence,
content,
role,
completionId,
isResponse })

attachAttributes({ target: this, agent, metadata, tags })
}
}

module.exports = LangChainCompletionMessage
module.exports = LangChainLlmChatCompletionMessage
44 changes: 16 additions & 28 deletions lib/llm-events/langchain/chat-completion-summary.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,30 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* Copyright 2026 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'

const LangChainEvent = require('./event')
const LlmChatCompletionSummary = require('../chat-completion-summary')
const attachAttributes = require('./attach-attributes')

/**
* @typedef {object} LangChainCompletionSummaryParams
* @augments LangChainEventParams
* @property {string[]|string} [tags] A set of tags applied to the LangChain
* event. If provided as a simple string, it should be a comma separated value
* string.
* @property {object[]} messages The set of messages that were returned as the
* LangChain result.
* Encapsulates a LangChain LlmChatCompletionSummary.
*/
/**
* @type {LangChainCompletionSummaryParams}
*/
const defaultParams = {
tags: [],
messages: []
}

class LangChainCompletionSummary extends LangChainEvent {
duration
'response.number_of_messages' = 0
class LangChainLlmChatCompletionSummary extends LlmChatCompletionSummary {
virtual_llm = true

constructor(params = defaultParams) {
params = Object.assign({}, defaultParams, params)
super(params)
const { segment } = params
constructor({ agent, segment, transaction, error, numMsgs = 0, runId, metadata = {}, tags = '' }) {
super({ agent,
segment,
transaction,
vendor: 'langchain',
requestId: runId,
error,
numMsgs })

this.duration = segment.getDurationInMillis()
this['response.number_of_messages'] = params.messages?.length
this.timestamp = segment.timer.start
attachAttributes({ target: this, agent, metadata, tags })
}
}

module.exports = LangChainCompletionSummary
module.exports = LangChainLlmChatCompletionSummary
85 changes: 0 additions & 85 deletions lib/llm-events/langchain/event.js

This file was deleted.

15 changes: 6 additions & 9 deletions lib/llm-events/langchain/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* Copyright 2026 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'

module.exports = {
LangChainEvent: require('./event'),
LangChainCompletionMessage: require('./chat-completion-message'),
LangChainCompletionSummary: require('./chat-completion-summary'),
LangChainVectorSearch: require('./vector-search'),
LangChainVectorSearchResult: require('./vector-search-result'),
LangChainTool: require('./tool')
LlmChatCompletionMessage: require('./chat-completion-message'),
LlmChatCompletionSummary: require('./chat-completion-summary'),
LlmTool: require('./tool'),
LlmVectorSearch: require('./vector-search'),
LlmVectorSearchResult: require('./vector-search-result')
}
49 changes: 30 additions & 19 deletions lib/llm-events/langchain/tool.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* Copyright 2026 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'
const LangChainEvent = require('./event')

class LangChainTool extends LangChainEvent {
constructor(params) {
super(params)
const { agent } = params
const LlmTool = require('../tool')
const attachAttributes = require('./attach-attributes')

this.name = params.name
this.description = params.description
this.duration = params?.segment?.getDurationInMillis()
this.run_id = this.request_id
delete this.request_id
delete this.virtual_llm
delete this.conversation_id
/**
* Encapsulates a LangChain LlmTool event.
*/
module.exports = class LangChainLlmTool extends LlmTool {
/**
*
* @param {object} params constructor parameters
* @param {Agent} params.agent New Relic agent instance
* @param {object} params.segment Current segment
* @param {object} params.transaction Current and active transaction
* @param {string} params.input Argument(s) input to the tool before it is run (including the argument name and value if available)
* @param {string} params.output Output data returned after the tool call has completed
* @param {string} params.toolName Name of the tool being run
* @param {string} params.aiAgentName Name of the AI agent associated with the tool call
* @param {string} params.runId ID assigned by the framework to identify the tool call
* @param {string} params.description Description of the tool used
* @param {object} [params.metadata] LangChain metadata object
* @param {string[]|string} [params.tags] LangChain tags, can be an array of strings or a comma-seperated string
* @param {boolean} [params.error] Set to `true` if an error occurred during creation call, omitted if no error occurred
*/
constructor({ agent, segment, transaction, runId, input, output, toolName, aiAgentName, description, metadata = {}, tags = '', error }) {
super({ agent, segment, transaction, vendor: 'langchain', runId, input, output, toolName, aiAgentName, error })

if (agent.config.ai_monitoring.record_content.enabled === true) {
this.input = params.input
this.output = params.output
}
// `metadata.<key>`, `tags`, and `description` do not
// appear in the AIM spec, but were a requirement for
// the initial LangChain instrumentation.
this.description = description
attachAttributes({ target: this, metadata, tags })
}
}

module.exports = LangChainTool
Loading
Loading