newrelic 13.9.0 → 13.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +30 -0
- package/lib/config/index.js +15 -1
- package/lib/llm-events/langchain/chat-completion-message.js +9 -0
- package/lib/subscribers/langchain/base.js +7 -4
- package/lib/subscribers/langchain/runnable-stream.js +13 -8
- package/lib/subscribers/message-consumer.js +2 -1
- package/package.json +2 -1
package/NEWS.md
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
### v13.9.2 (2026-01-14)
|
|
2
|
+
|
|
3
|
+
#### Bug fixes
|
|
4
|
+
|
|
5
|
+
* Updated message consumer subscribers to properly time the consumption actions ([#3660](https://github.com/newrelic/node-newrelic/pull/3660)) ([ef1b611](https://github.com/newrelic/node-newrelic/commit/ef1b611a7c3b45f5fc8d483661859c1595bbe4ab))
|
|
6
|
+
|
|
7
|
+
#### Documentation
|
|
8
|
+
|
|
9
|
+
* Updated compatibility report ([#3654](https://github.com/newrelic/node-newrelic/pull/3654)) ([ca16dae](https://github.com/newrelic/node-newrelic/commit/ca16daefe4da1c17253e165c68d198d607c72d0b))
|
|
10
|
+
|
|
11
|
+
#### Miscellaneous chores
|
|
12
|
+
|
|
13
|
+
* Update OTEL metrics test ([#3661](https://github.com/newrelic/node-newrelic/pull/3661)) ([ae84b62](https://github.com/newrelic/node-newrelic/commit/ae84b62a3c7ef753d4ace8836f38405b4cbbfd88))
|
|
14
|
+
|
|
15
|
+
#### Tests
|
|
16
|
+
|
|
17
|
+
* Added cross agent tests for sampler configuration and sampling rate scenarios ([#3648](https://github.com/newrelic/node-newrelic/pull/3648)) ([fa0e2d1](https://github.com/newrelic/node-newrelic/commit/fa0e2d1bd78051c7f716ebc65bd7f3842698103e))
|
|
18
|
+
|
|
19
|
+
### v13.9.1 (2026-01-12)
|
|
20
|
+
|
|
21
|
+
#### Bug fixes
|
|
22
|
+
|
|
23
|
+
* Updated `getHostnameSafe` to invalidate the cache is trying to assign the host based on the gcp cloud run id ([#3650](https://github.com/newrelic/node-newrelic/pull/3650)) ([d395c76](https://github.com/newrelic/node-newrelic/commit/d395c76d5612a7e562efa1a807c35e805a38ab14))
|
|
24
|
+
* Updated logic to properly assign content and role in LangChain chat completion messages ([#3638](https://github.com/newrelic/node-newrelic/pull/3638)) ([407bcb6](https://github.com/newrelic/node-newrelic/commit/407bcb66b7e3be1b6f1d28bcf6e3b022a7022c96))
|
|
25
|
+
|
|
26
|
+
#### Documentation
|
|
27
|
+
|
|
28
|
+
* Updated compatibility report ([#3643](https://github.com/newrelic/node-newrelic/pull/3643)) ([8929ab3](https://github.com/newrelic/node-newrelic/commit/8929ab3ae6cc28edbef4bee41a2084154361d6e0))
|
|
29
|
+
|
|
1
30
|
### v13.9.0 (2026-01-08)
|
|
2
31
|
|
|
3
32
|
#### Features
|
|
@@ -8203,3 +8232,4 @@ Special thanks to Ryan Copley (@RyanCopley) for the contribution.
|
|
|
8203
8232
|
|
|
8204
8233
|
|
|
8205
8234
|
|
|
8235
|
+
|
package/lib/config/index.js
CHANGED
|
@@ -993,7 +993,21 @@ Config.prototype.getIPAddresses = function getIPAddresses() {
|
|
|
993
993
|
function getHostnameSafe(gcpId = null) {
|
|
994
994
|
let _hostname
|
|
995
995
|
const config = this
|
|
996
|
-
|
|
996
|
+
/**
|
|
997
|
+
* We cache the result of _hostname unless an argument is passed in.
|
|
998
|
+
* The argument of `gcpId` is only passed in during the collection of
|
|
999
|
+
* facts: see `lib/collector/facts.js`. This needs to take precedence
|
|
1000
|
+
* over whatever the hostname was previously because gcp cloud run instances
|
|
1001
|
+
* report as localhost and we want to use the cloud run id
|
|
1002
|
+
*
|
|
1003
|
+
* @param {string} gcpId GCP metadata ID
|
|
1004
|
+
* @returns {string} host name
|
|
1005
|
+
*/
|
|
1006
|
+
this.getHostnameSafe = function getCachedHostname(gcpId = null) {
|
|
1007
|
+
if (gcpId) {
|
|
1008
|
+
return getHostnameSafe.call(config, gcpId)
|
|
1009
|
+
}
|
|
1010
|
+
|
|
997
1011
|
return _hostname
|
|
998
1012
|
}
|
|
999
1013
|
try {
|
|
@@ -22,6 +22,7 @@ const { makeId } = require('../../util/hashes')
|
|
|
22
22
|
*/
|
|
23
23
|
const defaultParams = {
|
|
24
24
|
content: '',
|
|
25
|
+
role: null,
|
|
25
26
|
sequence: 0,
|
|
26
27
|
completionId: makeId(36),
|
|
27
28
|
isResponse: undefined
|
|
@@ -29,6 +30,7 @@ const defaultParams = {
|
|
|
29
30
|
|
|
30
31
|
class LangChainCompletionMessage extends LangChainEvent {
|
|
31
32
|
content
|
|
33
|
+
role
|
|
32
34
|
sequence
|
|
33
35
|
completion_id
|
|
34
36
|
is_response
|
|
@@ -47,6 +49,13 @@ class LangChainCompletionMessage extends LangChainEvent {
|
|
|
47
49
|
this.sequence = params.sequence
|
|
48
50
|
this.completion_id = params.completionId
|
|
49
51
|
this.is_response = params.isResponse ?? false
|
|
52
|
+
if (params.role) {
|
|
53
|
+
this.role = params.role
|
|
54
|
+
} else {
|
|
55
|
+
// As a backup, we can infer the role based on if it
|
|
56
|
+
// is a response or not.
|
|
57
|
+
this.role = this.is_response ? 'assistant' : 'user'
|
|
58
|
+
}
|
|
50
59
|
|
|
51
60
|
if (agent.config.ai_monitoring.record_content.enabled === true) {
|
|
52
61
|
this.content = params.content
|
|
@@ -46,7 +46,7 @@ class LangchainSubscriber extends Subscriber {
|
|
|
46
46
|
events,
|
|
47
47
|
metadata,
|
|
48
48
|
tags,
|
|
49
|
-
err
|
|
49
|
+
err
|
|
50
50
|
}) {
|
|
51
51
|
const { agent } = this
|
|
52
52
|
segment.end()
|
|
@@ -74,7 +74,8 @@ class LangchainSubscriber extends Subscriber {
|
|
|
74
74
|
events,
|
|
75
75
|
completionSummary,
|
|
76
76
|
segment,
|
|
77
|
-
transaction
|
|
77
|
+
transaction,
|
|
78
|
+
pkgVersion
|
|
78
79
|
})
|
|
79
80
|
|
|
80
81
|
if (err) {
|
|
@@ -100,8 +101,9 @@ class LangchainSubscriber extends Subscriber {
|
|
|
100
101
|
* @param {LangChainCompletionSummary} params.completionSummary LlmChatCompletionSummary event
|
|
101
102
|
* @param {TraceSegment} params.segment active segment
|
|
102
103
|
* @param {Transaction} params.transaction active transaction
|
|
104
|
+
* @param {string} params.pkgVersion module version of the LangChain package
|
|
103
105
|
*/
|
|
104
|
-
recordCompletions({ events, completionSummary, segment, transaction }) {
|
|
106
|
+
recordCompletions({ events, completionSummary, segment, transaction, pkgVersion }) {
|
|
105
107
|
const { agent, logger } = this
|
|
106
108
|
for (let i = 0; i < events.length; i += 1) {
|
|
107
109
|
let msg = events[i]
|
|
@@ -121,6 +123,7 @@ class LangchainSubscriber extends Subscriber {
|
|
|
121
123
|
sequence: i,
|
|
122
124
|
agent,
|
|
123
125
|
content: msgString,
|
|
126
|
+
role: msg?.role,
|
|
124
127
|
completionId: completionSummary.id,
|
|
125
128
|
segment,
|
|
126
129
|
transaction,
|
|
@@ -131,7 +134,7 @@ class LangchainSubscriber extends Subscriber {
|
|
|
131
134
|
|
|
132
135
|
this.recordEvent({
|
|
133
136
|
type: 'LlmChatCompletionMessage',
|
|
134
|
-
pkgVersion
|
|
137
|
+
pkgVersion,
|
|
135
138
|
msg: completionMsg
|
|
136
139
|
})
|
|
137
140
|
}
|
|
@@ -37,7 +37,7 @@ class LangchainRunnableStreamSubscriber extends LangchainSubscriber {
|
|
|
37
37
|
|
|
38
38
|
asyncEnd(data) {
|
|
39
39
|
const { agent, logger } = this
|
|
40
|
-
//
|
|
40
|
+
// Exit early if need be.
|
|
41
41
|
if (!this.enabled) {
|
|
42
42
|
if (!this.streamingEnabled) {
|
|
43
43
|
logger.warn('Langchain streaming instrumentation is disabled, stream will not be instrumented.')
|
|
@@ -48,26 +48,26 @@ class LangchainRunnableStreamSubscriber extends LangchainSubscriber {
|
|
|
48
48
|
.incrementCallCount()
|
|
49
49
|
return
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
// Instrument stream
|
|
53
51
|
const ctx = this.agent.tracer.getContext()
|
|
54
52
|
const { segment, transaction } = ctx
|
|
55
53
|
if (transaction?.isActive() !== true) {
|
|
56
54
|
return
|
|
57
55
|
}
|
|
58
56
|
|
|
57
|
+
// Extract data.
|
|
59
58
|
const request = data?.arguments?.[0]
|
|
60
59
|
const params = data?.arguments?.[1] || {}
|
|
61
60
|
const metadata = params?.metadata ?? {}
|
|
62
61
|
const tags = params?.tags ?? []
|
|
63
62
|
const { result: output, error: err, moduleVersion: pkgVersion } = data
|
|
64
63
|
|
|
65
|
-
//
|
|
66
|
-
// Skip instrumenting streaming and create Llm Events from
|
|
67
|
-
// the data we have
|
|
64
|
+
// Instrument stream.
|
|
68
65
|
if (output?.next) {
|
|
69
66
|
this.wrapNextHandler({ output, segment, request, metadata, tags, transaction, pkgVersion })
|
|
70
67
|
} else {
|
|
68
|
+
// Input error occurred which means a stream was not created.
|
|
69
|
+
// Skip instrumenting streaming and create Llm Events from
|
|
70
|
+
// the data we have
|
|
71
71
|
this.recordChatCompletionEvents({
|
|
72
72
|
transaction,
|
|
73
73
|
segment,
|
|
@@ -115,11 +115,16 @@ class LangchainRunnableStreamSubscriber extends LangchainSubscriber {
|
|
|
115
115
|
pkgVersion
|
|
116
116
|
})
|
|
117
117
|
} else {
|
|
118
|
+
// Concat the streamed content
|
|
118
119
|
if (typeof result?.value?.content === 'string') {
|
|
119
|
-
//
|
|
120
|
+
// LangChain BaseMessageChunk case
|
|
120
121
|
content += result.value.content
|
|
121
|
-
} else {
|
|
122
|
+
} else if (typeof result?.value === 'string') {
|
|
123
|
+
// Base LangChain case
|
|
122
124
|
content += result.value
|
|
125
|
+
} else if (typeof result?.value?.[0] === 'string') {
|
|
126
|
+
// Array parser case
|
|
127
|
+
content += result.value[0]
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
return result
|
|
@@ -105,7 +105,7 @@ class MessageConsumerSubscriber extends Subscriber {
|
|
|
105
105
|
*/
|
|
106
106
|
asyncStart() {
|
|
107
107
|
const ctx = this.agent.tracer.getContext()
|
|
108
|
-
const tx = ctx
|
|
108
|
+
const tx = ctx.transaction
|
|
109
109
|
tx.setPartialName(this.name)
|
|
110
110
|
// Note: this is not using `Subscriber.createSegment`
|
|
111
111
|
// this is because it enters the segment and returns a new ctx
|
|
@@ -117,6 +117,7 @@ class MessageConsumerSubscriber extends Subscriber {
|
|
|
117
117
|
parent: tx.trace.root,
|
|
118
118
|
transaction: tx
|
|
119
119
|
})
|
|
120
|
+
tx.baseSegment.start()
|
|
120
121
|
|
|
121
122
|
this.addConsumeParameters(tx)
|
|
122
123
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "13.9.
|
|
3
|
+
"version": "13.9.2",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -198,6 +198,7 @@
|
|
|
198
198
|
"imports": {
|
|
199
199
|
"#agentlib/*.js": "./lib/*.js",
|
|
200
200
|
"#testlib/*.js": "./test/lib/*.js",
|
|
201
|
+
"#testlib/*.json": "./test/lib/*.json",
|
|
201
202
|
"#test/assert": "./test/lib/custom-assertions/index.js"
|
|
202
203
|
},
|
|
203
204
|
"dependencies": {
|