Skip to content

Commit 674f55f

Browse files
committed
LangChain LLM event refactor
1 parent 0ccad21 commit 674f55f

21 files changed

+284
-487
lines changed
Lines changed: 50 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,62 @@
11
/*
2-
* Copyright 2024 New Relic Corporation. All rights reserved.
2+
* Copyright 2026 New Relic Corporation. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
'use strict'
7+
const LlmChatCompletionMessage = require('../chat-completion-message')
8+
const { isSimpleObject } = require('../../util/objects')
79

8-
const LangChainEvent = require('./event')
9-
const { makeId } = require('../../util/hashes')
10-
11-
/**
12-
* @typedef {object} LangChainCompletionMessageParams
13-
* @augments LangChainEventParams
14-
* @property {string} content The text of the response received from LangChain.
15-
* @property {number} [sequence=0] The order of the message in the response.
16-
* @property {string} [completionId] An identifier for the message.
17-
* @property {boolean|undefined} [isResponse] Indicates if the completion
18-
* message represents a response from the remote service.
19-
*/
2010
/**
21-
* @type {LangChainCompletionMessageParams}
11+
* Encapsulates a LangChain LlmChatCompletionMessage.
2212
*/
23-
const defaultParams = {
24-
content: '',
25-
role: null,
26-
sequence: 0,
27-
completionId: makeId(36),
28-
isResponse: undefined
29-
}
30-
31-
class LangChainCompletionMessage extends LangChainEvent {
32-
content
33-
role
34-
sequence
35-
completion_id
36-
is_response
37-
38-
constructor(params = defaultParams) {
39-
params = Object.assign({}, defaultParams, params)
40-
super(params)
41-
const { agent, runId, segment, sequence, role, content, completionId, isResponse } = params
42-
43-
if (runId) {
44-
this.id = `${runId}-${sequence}`
45-
} else {
46-
this.id = `${this.id}-${sequence}`
47-
}
48-
49-
this.sequence = sequence
50-
this.completion_id = completionId
51-
52-
this.is_response = isResponse ?? false
53-
if (this.is_response === false) {
54-
// `timestamp` is only required for input/request messages.
55-
this.timestamp = segment.timer.start
56-
}
57-
58-
if (role) {
59-
this.role = role
60-
} else {
61-
// As a backup, we can infer the role based on if it
62-
// is a response or not.
63-
this.role = this.is_response ? 'assistant' : 'user'
64-
}
65-
66-
if (agent.config.ai_monitoring.record_content.enabled === true) {
67-
this.content = content
13+
class LangChainLlmChatCompletionMessage extends LlmChatCompletionMessage {
14+
virtual_llm = true
15+
/**
16+
* @param {object} params constructor parameters
17+
* @param {Agent} params.agent New Relic agent instance
18+
* @param {object} params.segment Current segment
19+
* @param {object} params.transaction Current and active transaction
20+
* @param {string} params.runId LangChain run ID (will be used as response ID)
21+
* @param {number} params.sequence Index (beginning at 0) associated with
22+
* each message including the prompt and responses
23+
* @param {string} params.content Content of the message
24+
* @param {string} [params.role] Role of the message creator (e.g. `user`, `assistant`, `tool`)
25+
* @param {string} params.completionId ID of the `LlmChatCompletionSummary` event that
26+
* this message event is connected to
27+
* @param {boolean} [params.isResponse] `true` if a message is the result of a chat
28+
* completion and not an input message - omitted in `false` cases
29+
* @param {object} params.metadata LangChain metadata object
30+
* @param {string[]|string} params.tags LangChain tags, can be an array of strings or a comma-seperated string
31+
*/
32+
constructor({ agent, segment, transaction, runId, sequence, role, content, completionId, isResponse, metadata = {}, tags = '' }) {
33+
super({ agent,
34+
segment,
35+
transaction,
36+
vendor: 'langchain',
37+
responseId: runId,
38+
requestId: runId,
39+
sequence,
40+
content,
41+
role,
42+
completionId,
43+
isResponse })
44+
45+
// Does not appear in AIM spec as of 2/2026, but seemed
46+
// to be a requirement back in 1/2024 (e.g. LangChain CDD).
47+
this.appName = agent.config.applications()[0]
48+
49+
// `metadata.<key>` and `tags` do not appear in
50+
// the AIM spec, but were a requirement for the
51+
// initial LangChain instrumentation.
52+
if (isSimpleObject(metadata)) {
53+
this.langchainMeta = metadata
54+
for (const [key, val] of Object.entries(metadata)) {
55+
this[`metadata.${key}`] = val
56+
}
6857
}
58+
this.tags = Array.isArray(tags) ? tags.join(',') : tags
6959
}
7060
}
7161

72-
module.exports = LangChainCompletionMessage
62+
module.exports = LangChainLlmChatCompletionMessage
Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,41 @@
11
/*
2-
* Copyright 2024 New Relic Corporation. All rights reserved.
2+
* Copyright 2026 New Relic Corporation. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
'use strict'
7+
const LlmChatCompletionSummary = require('../chat-completion-summary')
8+
const { isSimpleObject } = require('../../util/objects')
79

8-
const LangChainEvent = require('./event')
9-
10-
/**
11-
* @typedef {object} LangChainCompletionSummaryParams
12-
* @augments LangChainEventParams
13-
* @property {string[]|string} [tags] A set of tags applied to the LangChain
14-
* event. If provided as a simple string, it should be a comma separated value
15-
* string.
16-
* @property {object[]} messages The set of messages that were returned as the
17-
* LangChain result.
18-
*/
1910
/**
20-
* @type {LangChainCompletionSummaryParams}
11+
* Encapsulates a LangChain LlmChatCompletionSummary.
2112
*/
22-
const defaultParams = {
23-
tags: [],
24-
messages: []
25-
}
26-
27-
class LangChainCompletionSummary extends LangChainEvent {
28-
duration
29-
'response.number_of_messages' = 0
13+
class LangChainLlmChatCompletionSummary extends LlmChatCompletionSummary {
14+
virtual_llm = true
15+
constructor({ agent, segment, transaction, error, numMsgs = 0, runId, metadata = {}, tags = '' }) {
16+
super({ agent,
17+
segment,
18+
transaction,
19+
vendor: 'langchain',
20+
requestId: runId,
21+
error,
22+
numMsgs })
3023

31-
constructor(params = defaultParams) {
32-
params = Object.assign({}, defaultParams, params)
33-
super(params)
34-
const { segment } = params
24+
// Does not appear in AIM spec as of 2/2026, but seemed
25+
// to be a requirement back in 1/2024 (e.g. LangChain CDD).
26+
this.appName = agent.config.applications()[0]
3527

36-
this.duration = segment.getDurationInMillis()
37-
this['response.number_of_messages'] = params.messages?.length
38-
this.timestamp = segment.timer.start
28+
// `metadata.<key>` and `tags` do not appear in
29+
// the AIM spec, but were a requirement for the
30+
// initial LangChain instrumentation.
31+
if (isSimpleObject(metadata)) {
32+
this.langchainMeta = metadata
33+
for (const [key, val] of Object.entries(metadata)) {
34+
this[`metadata.${key}`] = val
35+
}
36+
}
37+
this.tags = Array.isArray(tags) ? tags.join(',') : tags
3938
}
4039
}
4140

42-
module.exports = LangChainCompletionSummary
41+
module.exports = LangChainLlmChatCompletionSummary

lib/llm-events/langchain/event.js

Lines changed: 0 additions & 85 deletions
This file was deleted.

lib/llm-events/langchain/index.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
/*
2-
* Copyright 2024 New Relic Corporation. All rights reserved.
2+
* Copyright 2026 New Relic Corporation. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
'use strict'
7-
86
module.exports = {
9-
LangChainEvent: require('./event'),
10-
LangChainCompletionMessage: require('./chat-completion-message'),
11-
LangChainCompletionSummary: require('./chat-completion-summary'),
12-
LangChainVectorSearch: require('./vector-search'),
13-
LangChainVectorSearchResult: require('./vector-search-result'),
14-
LangChainTool: require('./tool')
7+
LlmChatCompletionMessage: require('./chat-completion-message'),
8+
LlmChatCompletionSummary: require('./chat-completion-summary'),
9+
LlmTool: require('./tool'),
10+
LlmVectorSearch: require('./vector-search'),
11+
LlmVectorSearchResult: require('./vector-search-result')
1512
}

lib/llm-events/langchain/tool.js

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,46 @@
11
/*
2-
* Copyright 2024 New Relic Corporation. All rights reserved.
2+
* Copyright 2026 New Relic Corporation. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
'use strict'
7-
const LangChainEvent = require('./event')
87

9-
class LangChainTool extends LangChainEvent {
10-
constructor(params) {
11-
super(params)
12-
const { agent } = params
8+
const LlmTool = require('../tool')
9+
const { isSimpleObject } = require('../../util/objects')
1310

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

22-
if (agent.config.ai_monitoring.record_content.enabled === true) {
23-
this.input = params.input
24-
this.output = params.output
34+
// `metadata.<key>`, `tags`, and `description` do not
35+
// appear in the AIM spec, but were a requirement for
36+
// the initial LangChain instrumentation.
37+
this.description = description
38+
if (isSimpleObject(metadata)) {
39+
this.langchainMeta = metadata
40+
for (const [key, val] of Object.entries(metadata)) {
41+
this[`metadata.${key}`] = val
42+
}
2543
}
44+
this.tags = Array.isArray(tags) ? tags.join(',') : tags
2645
}
2746
}
28-
29-
module.exports = LangChainTool

0 commit comments

Comments
 (0)