newrelic 13.9.0 → 13.9.1

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 CHANGED
@@ -1,3 +1,14 @@
1
+ ### v13.9.1 (2026-01-12)
2
+
3
+ #### Bug fixes
4
+
5
+ * 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))
6
+ * 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))
7
+
8
+ #### Documentation
9
+
10
+ * Updated compatibility report ([#3643](https://github.com/newrelic/node-newrelic/pull/3643)) ([8929ab3](https://github.com/newrelic/node-newrelic/commit/8929ab3ae6cc28edbef4bee41a2084154361d6e0))
11
+
1
12
  ### v13.9.0 (2026-01-08)
2
13
 
3
14
  #### Features
@@ -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
- this.getHostnameSafe = function getCachedHostname() {
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: this.moduleVersion,
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
- // Check ai_monitoring config
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
- // Input error occurred which means a stream was not created.
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
- // if result.value is a AIMessageChunk
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "13.9.0",
3
+ "version": "13.9.1",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [