newrelic 12.24.0 → 12.25.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 +26 -0
- package/THIRD_PARTY_NOTICES.md +39 -39
- package/esm-loader.mjs +4 -1
- package/lib/grpc/connection.js +2 -2
- package/lib/grpc/endpoints/infinite-tracing/Readme.md +10 -0
- package/lib/grpc/endpoints/infinite-tracing/v1.json +106 -0
- package/lib/instrumentation/aws-sdk/v3/bedrock.js +51 -12
- package/lib/instrumentation/openai.js +2 -2
- package/lib/instrumentation/when/index.js +0 -1
- package/lib/llm-events/aws-bedrock/bedrock-command.js +97 -53
- package/lib/llm-events/aws-bedrock/bedrock-response.js +68 -52
- package/lib/llm-events/aws-bedrock/chat-completion-message.js +1 -1
- package/lib/llm-events/aws-bedrock/chat-completion-summary.js +6 -8
- package/lib/llm-events/aws-bedrock/converse-stream-handler.js +155 -0
- package/lib/llm-events/aws-bedrock/index.js +2 -1
- package/lib/llm-events/aws-bedrock/utils.js +38 -1
- package/lib/shim/shim.js +1 -1
- package/package.json +2 -2
package/NEWS.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
### v12.25.1 (2026-02-10)
|
|
2
|
+
|
|
3
|
+
#### Security improvements
|
|
4
|
+
|
|
5
|
+
* Bumped minimum version of security agent ([#3713](https://github.com/newrelic/node-newrelic/pull/3713)) ([88b2334](https://github.com/newrelic/node-newrelic/commit/88b2334294f5b62a56599c48dc7cacb85a3e0bc2))
|
|
6
|
+
|
|
7
|
+
### v12.25.0 (2025-07-09)
|
|
8
|
+
|
|
9
|
+
#### Features
|
|
10
|
+
|
|
11
|
+
* Instrument AWS Bedrock Converse API ([#3191](https://github.com/newrelic/node-newrelic/pull/3191)) ([16ac684](https://github.com/newrelic/node-newrelic/commit/16ac6845a82506bbdd0e51f3f9a6d05ac8016246))
|
|
12
|
+
|
|
13
|
+
#### Bug fixes
|
|
14
|
+
|
|
15
|
+
* `eventSegment.addAttribute` will not crash if null ([#3215](https://github.com/newrelic/node-newrelic/pull/3215)) ([8955f37](https://github.com/newrelic/node-newrelic/commit/8955f3737e686b4bf6beab2d4e53a1f5eb221166))
|
|
16
|
+
* `openai` Responses API support changed to >=v4.87.0 ([#3219](https://github.com/newrelic/node-newrelic/pull/3219)) ([19c0c70](https://github.com/newrelic/node-newrelic/commit/19c0c7011c8c877098c5a57063354f01f5f83295))
|
|
17
|
+
|
|
18
|
+
#### Documentation
|
|
19
|
+
|
|
20
|
+
* Updated compatibility report ([#3220](https://github.com/newrelic/node-newrelic/pull/3220)) ([b4350c7](https://github.com/newrelic/node-newrelic/commit/b4350c7e3a718e47d066c5c2c1f4f5f20f43e52c))
|
|
21
|
+
|
|
22
|
+
#### Miscellaneous chores
|
|
23
|
+
|
|
24
|
+
* Converted .proto to .json for bundling ([#3212](https://github.com/newrelic/node-newrelic/pull/3212)) ([1e208d4](https://github.com/newrelic/node-newrelic/commit/1e208d43acc1811674126b6aa987c895178f4fc3))
|
|
25
|
+
|
|
1
26
|
### v12.24.0 (2025-07-07)
|
|
2
27
|
|
|
3
28
|
#### Features
|
|
@@ -7673,3 +7698,4 @@ Special thanks to Ryan Copley (@RyanCopley) for the contribution.
|
|
|
7673
7698
|
* The agent reports transaction trace data.
|
|
7674
7699
|
|
|
7675
7700
|
[mdn-async-function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
|
7701
|
+
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -82,7 +82,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
82
82
|
|
|
83
83
|
**[optionalDependencies](#optionalDependencies)**
|
|
84
84
|
|
|
85
|
-
* [@
|
|
85
|
+
* [@newrelic/fn-inspect](#newrelicfn-inspect)
|
|
86
86
|
* [@newrelic/native-metrics](#newrelicnative-metrics)
|
|
87
87
|
* [@prisma/prisma-fmt-wasm](#prismaprisma-fmt-wasm)
|
|
88
88
|
|
|
@@ -95,7 +95,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
95
95
|
|
|
96
96
|
### @grpc/grpc-js
|
|
97
97
|
|
|
98
|
-
This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.
|
|
98
|
+
This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.14.3](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/tree/v1.14.3)), distributed under the [Apache-2.0 License](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/blob/v1.14.3/LICENSE):
|
|
99
99
|
|
|
100
100
|
```
|
|
101
101
|
Apache License
|
|
@@ -513,7 +513,7 @@ This product includes source derived from [@grpc/proto-loader](https://github.co
|
|
|
513
513
|
|
|
514
514
|
### @newrelic/security-agent
|
|
515
515
|
|
|
516
|
-
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v2.4.
|
|
516
|
+
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v2.4.4](https://github.com/newrelic/csec-node-agent/tree/v2.4.4)), distributed under the [UNKNOWN License](https://github.com/newrelic/csec-node-agent/blob/v2.4.4/LICENSE):
|
|
517
517
|
|
|
518
518
|
```
|
|
519
519
|
## New Relic Software License v1.0
|
|
@@ -768,7 +768,7 @@ This product includes source derived from [@opentelemetry/api](https://github.co
|
|
|
768
768
|
|
|
769
769
|
### @opentelemetry/core
|
|
770
770
|
|
|
771
|
-
This product includes source derived from [@opentelemetry/core](https://github.com/open-telemetry/opentelemetry-js) ([v2.0
|
|
771
|
+
This product includes source derived from [@opentelemetry/core](https://github.com/open-telemetry/opentelemetry-js) ([v2.5.0](https://github.com/open-telemetry/opentelemetry-js/tree/v2.5.0)), distributed under the [Apache-2.0 License](https://github.com/open-telemetry/opentelemetry-js/blob/v2.5.0/LICENSE):
|
|
772
772
|
|
|
773
773
|
```
|
|
774
774
|
Apache License
|
|
@@ -1186,7 +1186,7 @@ This product includes source derived from [@opentelemetry/exporter-metrics-otlp-
|
|
|
1186
1186
|
|
|
1187
1187
|
### @opentelemetry/resources
|
|
1188
1188
|
|
|
1189
|
-
This product includes source derived from [@opentelemetry/resources](https://github.com/open-telemetry/opentelemetry-js) ([v2.0
|
|
1189
|
+
This product includes source derived from [@opentelemetry/resources](https://github.com/open-telemetry/opentelemetry-js) ([v2.5.0](https://github.com/open-telemetry/opentelemetry-js/tree/v2.5.0)), distributed under the [Apache-2.0 License](https://github.com/open-telemetry/opentelemetry-js/blob/v2.5.0/LICENSE):
|
|
1190
1190
|
|
|
1191
1191
|
```
|
|
1192
1192
|
Apache License
|
|
@@ -1395,7 +1395,7 @@ This product includes source derived from [@opentelemetry/resources](https://git
|
|
|
1395
1395
|
|
|
1396
1396
|
### @opentelemetry/sdk-metrics
|
|
1397
1397
|
|
|
1398
|
-
This product includes source derived from [@opentelemetry/sdk-metrics](https://github.com/open-telemetry/opentelemetry-js) ([v2.0
|
|
1398
|
+
This product includes source derived from [@opentelemetry/sdk-metrics](https://github.com/open-telemetry/opentelemetry-js) ([v2.5.0](https://github.com/open-telemetry/opentelemetry-js/tree/v2.5.0)), distributed under the [Apache-2.0 License](https://github.com/open-telemetry/opentelemetry-js/blob/v2.5.0/LICENSE):
|
|
1399
1399
|
|
|
1400
1400
|
```
|
|
1401
1401
|
Apache License
|
|
@@ -1604,7 +1604,7 @@ This product includes source derived from [@opentelemetry/sdk-metrics](https://g
|
|
|
1604
1604
|
|
|
1605
1605
|
### @opentelemetry/sdk-trace-base
|
|
1606
1606
|
|
|
1607
|
-
This product includes source derived from [@opentelemetry/sdk-trace-base](https://github.com/open-telemetry/opentelemetry-js) ([v2.0
|
|
1607
|
+
This product includes source derived from [@opentelemetry/sdk-trace-base](https://github.com/open-telemetry/opentelemetry-js) ([v2.5.0](https://github.com/open-telemetry/opentelemetry-js/tree/v2.5.0)), distributed under the [Apache-2.0 License](https://github.com/open-telemetry/opentelemetry-js/blob/v2.5.0/LICENSE):
|
|
1608
1608
|
|
|
1609
1609
|
```
|
|
1610
1610
|
Apache License
|
|
@@ -1902,7 +1902,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
1902
1902
|
|
|
1903
1903
|
### import-in-the-middle
|
|
1904
1904
|
|
|
1905
|
-
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.
|
|
1905
|
+
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.15.0](https://github.com/nodejs/import-in-the-middle/tree/v1.15.0)), distributed under the [Apache-2.0 License](https://github.com/nodejs/import-in-the-middle/blob/v1.15.0/LICENSE):
|
|
1906
1906
|
|
|
1907
1907
|
```
|
|
1908
1908
|
Apache License
|
|
@@ -2277,7 +2277,7 @@ SOFTWARE.
|
|
|
2277
2277
|
|
|
2278
2278
|
### semver
|
|
2279
2279
|
|
|
2280
|
-
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.7.
|
|
2280
|
+
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.7.3](https://github.com/npm/node-semver/tree/v7.7.3)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.7.3/LICENSE):
|
|
2281
2281
|
|
|
2282
2282
|
```
|
|
2283
2283
|
The ISC License
|
|
@@ -2333,7 +2333,7 @@ SOFTWARE.
|
|
|
2333
2333
|
|
|
2334
2334
|
### @aws-sdk/client-s3
|
|
2335
2335
|
|
|
2336
|
-
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
2336
|
+
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.982.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.982.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.982.0/LICENSE):
|
|
2337
2337
|
|
|
2338
2338
|
```
|
|
2339
2339
|
Apache License
|
|
@@ -2542,7 +2542,7 @@ This product includes source derived from [@aws-sdk/client-s3](https://github.co
|
|
|
2542
2542
|
|
|
2543
2543
|
### @aws-sdk/s3-request-presigner
|
|
2544
2544
|
|
|
2545
|
-
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
2545
|
+
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.982.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.982.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.982.0/LICENSE):
|
|
2546
2546
|
|
|
2547
2547
|
```
|
|
2548
2548
|
Apache License
|
|
@@ -3226,7 +3226,7 @@ This product includes source derived from [@newrelic/newrelic-oss-cli](https://g
|
|
|
3226
3226
|
|
|
3227
3227
|
### @newrelic/test-utilities
|
|
3228
3228
|
|
|
3229
|
-
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v9.
|
|
3229
|
+
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v9.2.0](https://github.com/newrelic/node-test-utilities/tree/v9.2.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v9.2.0/LICENSE):
|
|
3230
3230
|
|
|
3231
3231
|
```
|
|
3232
3232
|
Apache License
|
|
@@ -3969,7 +3969,7 @@ THE SOFTWARE.
|
|
|
3969
3969
|
|
|
3970
3970
|
### aws-sdk
|
|
3971
3971
|
|
|
3972
|
-
This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.
|
|
3972
|
+
This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1693.0](https://github.com/aws/aws-sdk-js/tree/v2.1693.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1693.0/LICENSE.txt):
|
|
3973
3973
|
|
|
3974
3974
|
```
|
|
3975
3975
|
|
|
@@ -4370,7 +4370,7 @@ SOFTWARE.
|
|
|
4370
4370
|
|
|
4371
4371
|
### eslint-plugin-jsdoc
|
|
4372
4372
|
|
|
4373
|
-
This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v50.
|
|
4373
|
+
This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v50.8.0](https://github.com/gajus/eslint-plugin-jsdoc/tree/v50.8.0)), distributed under the [BSD-3-Clause License](https://github.com/gajus/eslint-plugin-jsdoc/blob/v50.8.0/LICENSE):
|
|
4374
4374
|
|
|
4375
4375
|
```
|
|
4376
4376
|
Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/)
|
|
@@ -4402,7 +4402,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
4402
4402
|
|
|
4403
4403
|
### eslint
|
|
4404
4404
|
|
|
4405
|
-
This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v9.
|
|
4405
|
+
This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v9.39.2](https://github.com/eslint/eslint/tree/v9.39.2)), distributed under the [MIT License](https://github.com/eslint/eslint/blob/v9.39.2/LICENSE):
|
|
4406
4406
|
|
|
4407
4407
|
```
|
|
4408
4408
|
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
|
@@ -4429,7 +4429,7 @@ THE SOFTWARE.
|
|
|
4429
4429
|
|
|
4430
4430
|
### express
|
|
4431
4431
|
|
|
4432
|
-
This product includes source derived from [express](https://github.com/expressjs/express) ([v5.1
|
|
4432
|
+
This product includes source derived from [express](https://github.com/expressjs/express) ([v5.2.1](https://github.com/expressjs/express/tree/v5.2.1)), distributed under the [MIT License](https://github.com/expressjs/express/blob/v5.2.1/LICENSE):
|
|
4433
4433
|
|
|
4434
4434
|
```
|
|
4435
4435
|
(The MIT License)
|
|
@@ -4565,7 +4565,7 @@ SOFTWARE.
|
|
|
4565
4565
|
|
|
4566
4566
|
### jsdoc
|
|
4567
4567
|
|
|
4568
|
-
This product includes source derived from [jsdoc](https://github.com/jsdoc/jsdoc) ([v4.0.
|
|
4568
|
+
This product includes source derived from [jsdoc](https://github.com/jsdoc/jsdoc) ([v4.0.5](https://github.com/jsdoc/jsdoc/tree/v4.0.5)), distributed under the [Apache-2.0 License](https://github.com/jsdoc/jsdoc/blob/v4.0.5/LICENSE.md):
|
|
4569
4569
|
|
|
4570
4570
|
```
|
|
4571
4571
|
# License
|
|
@@ -4682,19 +4682,19 @@ MIT License
|
|
|
4682
4682
|
|
|
4683
4683
|
Copyright (c) <year> <copyright holders>
|
|
4684
4684
|
|
|
4685
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
4686
|
-
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
4687
|
-
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
4688
|
-
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
4685
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
4686
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
4687
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
4688
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
4689
4689
|
following conditions:
|
|
4690
4690
|
|
|
4691
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
4691
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
4692
4692
|
portions of the Software.
|
|
4693
4693
|
|
|
4694
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
4695
|
-
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
4696
|
-
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
4697
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
4694
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
4695
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
4696
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
4697
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
4698
4698
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
4699
4699
|
```
|
|
4700
4700
|
|
|
@@ -4729,7 +4729,7 @@ THE SOFTWARE.
|
|
|
4729
4729
|
|
|
4730
4730
|
### koa
|
|
4731
4731
|
|
|
4732
|
-
This product includes source derived from [koa](https://github.com/koajs/koa) ([v2.16.
|
|
4732
|
+
This product includes source derived from [koa](https://github.com/koajs/koa) ([v2.16.3](https://github.com/koajs/koa/tree/v2.16.3)), distributed under the [MIT License](https://github.com/koajs/koa/blob/v2.16.3/LICENSE):
|
|
4733
4733
|
|
|
4734
4734
|
```
|
|
4735
4735
|
(The MIT License)
|
|
@@ -5015,7 +5015,7 @@ SOFTWARE.
|
|
|
5015
5015
|
|
|
5016
5016
|
### protobufjs
|
|
5017
5017
|
|
|
5018
|
-
This product includes source derived from [protobufjs](https://github.com/protobufjs/protobuf.js) ([v7.5.
|
|
5018
|
+
This product includes source derived from [protobufjs](https://github.com/protobufjs/protobuf.js) ([v7.5.4](https://github.com/protobufjs/protobuf.js/tree/v7.5.4)), distributed under the [BSD-3-Clause License](https://github.com/protobufjs/protobuf.js/blob/v7.5.4/LICENSE):
|
|
5019
5019
|
|
|
5020
5020
|
```
|
|
5021
5021
|
This license applies to all parts of protobuf.js except those files
|
|
@@ -5123,19 +5123,19 @@ MIT License
|
|
|
5123
5123
|
|
|
5124
5124
|
Copyright (c) <year> <copyright holders>
|
|
5125
5125
|
|
|
5126
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
5127
|
-
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
5128
|
-
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
5129
|
-
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
5126
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
5127
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
5128
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
5129
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
5130
5130
|
following conditions:
|
|
5131
5131
|
|
|
5132
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
5132
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
5133
5133
|
portions of the Software.
|
|
5134
5134
|
|
|
5135
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
5136
|
-
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
5137
|
-
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
5138
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
5135
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
5136
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
5137
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
5138
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
5139
5139
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
5140
5140
|
```
|
|
5141
5141
|
|
|
@@ -5235,9 +5235,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
5235
5235
|
|
|
5236
5236
|
## optionalDependencies
|
|
5237
5237
|
|
|
5238
|
-
### @
|
|
5238
|
+
### @newrelic/fn-inspect
|
|
5239
5239
|
|
|
5240
|
-
This product includes source derived from [@
|
|
5240
|
+
This product includes source derived from [@newrelic/fn-inspect](https://github.com/newrelic-forks/node-fn-inspect) ([v4.4.0](https://github.com/newrelic-forks/node-fn-inspect/tree/v4.4.0)), distributed under the [MIT License](https://github.com/newrelic-forks/node-fn-inspect/blob/v4.4.0/LICENSE):
|
|
5241
5241
|
|
|
5242
5242
|
```
|
|
5243
5243
|
Copyright 2022 Contrast Security, Inc
|
package/esm-loader.mjs
CHANGED
|
@@ -3,4 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
7
|
+
import { register } from 'node:module'
|
|
8
|
+
|
|
9
|
+
register('import-in-the-middle/hook.mjs', import.meta.url, {})
|
package/lib/grpc/connection.js
CHANGED
|
@@ -22,7 +22,7 @@ const connectionStates = require('./connection/states')
|
|
|
22
22
|
|
|
23
23
|
const PROTO_OPTIONS = { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }
|
|
24
24
|
|
|
25
|
-
const
|
|
25
|
+
const PROTO_DEFINITION = require('./endpoints/infinite-tracing/v1.json')
|
|
26
26
|
|
|
27
27
|
const DEFAULT_RECONNECT_DELAY_MS = 15 * 1000
|
|
28
28
|
|
|
@@ -369,7 +369,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
369
369
|
const endpoint = this._endpoint
|
|
370
370
|
logger.trace('Creating gRPC client for: ', endpoint)
|
|
371
371
|
|
|
372
|
-
const packageDefinition = protoLoader.
|
|
372
|
+
const packageDefinition = protoLoader.fromJSON(PROTO_DEFINITION, PROTO_OPTIONS)
|
|
373
373
|
|
|
374
374
|
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition)
|
|
375
375
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
The `.proto` files in this directory are provided by New Relic internal
|
|
2
|
+
specifications.
|
|
3
|
+
|
|
4
|
+
The `.json` files in this directory are JSON descriptor files derived from
|
|
5
|
+
the equivalent `.proto` files. This is accomplished by utilizing the CLI
|
|
6
|
+
tool provided by `protobufjs`. As an example:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npx --package=protobufjs-cli -c 'pbjs --keep-case v1.proto' > v1.json
|
|
10
|
+
```
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nested": {
|
|
3
|
+
"com": {
|
|
4
|
+
"nested": {
|
|
5
|
+
"newrelic": {
|
|
6
|
+
"nested": {
|
|
7
|
+
"trace": {
|
|
8
|
+
"nested": {
|
|
9
|
+
"v1": {
|
|
10
|
+
"nested": {
|
|
11
|
+
"IngestService": {
|
|
12
|
+
"methods": {
|
|
13
|
+
"RecordSpan": {
|
|
14
|
+
"requestType": "Span",
|
|
15
|
+
"requestStream": true,
|
|
16
|
+
"responseType": "RecordStatus",
|
|
17
|
+
"responseStream": true
|
|
18
|
+
},
|
|
19
|
+
"RecordSpanBatch": {
|
|
20
|
+
"requestType": "SpanBatch",
|
|
21
|
+
"requestStream": true,
|
|
22
|
+
"responseType": "RecordStatus",
|
|
23
|
+
"responseStream": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"SpanBatch": {
|
|
28
|
+
"fields": {
|
|
29
|
+
"spans": {
|
|
30
|
+
"rule": "repeated",
|
|
31
|
+
"type": "Span",
|
|
32
|
+
"id": 1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"Span": {
|
|
37
|
+
"fields": {
|
|
38
|
+
"trace_id": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"id": 1
|
|
41
|
+
},
|
|
42
|
+
"intrinsics": {
|
|
43
|
+
"keyType": "string",
|
|
44
|
+
"type": "AttributeValue",
|
|
45
|
+
"id": 2
|
|
46
|
+
},
|
|
47
|
+
"user_attributes": {
|
|
48
|
+
"keyType": "string",
|
|
49
|
+
"type": "AttributeValue",
|
|
50
|
+
"id": 3
|
|
51
|
+
},
|
|
52
|
+
"agent_attributes": {
|
|
53
|
+
"keyType": "string",
|
|
54
|
+
"type": "AttributeValue",
|
|
55
|
+
"id": 4
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"AttributeValue": {
|
|
60
|
+
"oneofs": {
|
|
61
|
+
"value": {
|
|
62
|
+
"oneof": [
|
|
63
|
+
"string_value",
|
|
64
|
+
"bool_value",
|
|
65
|
+
"int_value",
|
|
66
|
+
"double_value"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"fields": {
|
|
71
|
+
"string_value": {
|
|
72
|
+
"type": "string",
|
|
73
|
+
"id": 1
|
|
74
|
+
},
|
|
75
|
+
"bool_value": {
|
|
76
|
+
"type": "bool",
|
|
77
|
+
"id": 2
|
|
78
|
+
},
|
|
79
|
+
"int_value": {
|
|
80
|
+
"type": "int64",
|
|
81
|
+
"id": 3
|
|
82
|
+
},
|
|
83
|
+
"double_value": {
|
|
84
|
+
"type": "double",
|
|
85
|
+
"id": 4
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"RecordStatus": {
|
|
90
|
+
"fields": {
|
|
91
|
+
"messages_seen": {
|
|
92
|
+
"type": "uint64",
|
|
93
|
+
"id": 1
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -19,9 +19,27 @@ const { AI } = require('../../../metrics/names')
|
|
|
19
19
|
const { RecorderSpec } = require('../../../shim/specs')
|
|
20
20
|
const InstrumentationDescriptor = require('../../../instrumentation-descriptor')
|
|
21
21
|
const { extractLlmContext } = require('../../../util/llm-utils')
|
|
22
|
+
const ConverseStreamHandler = require('../../../llm-events/aws-bedrock/converse-stream-handler')
|
|
22
23
|
|
|
23
24
|
let TRACKING_METRIC
|
|
24
25
|
|
|
26
|
+
const INSTRUMENTED_COMMANDS = new Set([
|
|
27
|
+
'InvokeModelCommand',
|
|
28
|
+
'InvokeModelWithResponseStreamCommand',
|
|
29
|
+
'ConverseCommand',
|
|
30
|
+
'ConverseStreamCommand'
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
const STREAMING_COMMANDS = new Set([
|
|
34
|
+
'InvokeModelWithResponseStreamCommand',
|
|
35
|
+
'ConverseStreamCommand'
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
const CONVERSE_COMMANDS = new Set([
|
|
39
|
+
'ConverseCommand',
|
|
40
|
+
'ConverseStreamCommand'
|
|
41
|
+
])
|
|
42
|
+
|
|
25
43
|
/**
|
|
26
44
|
* Helper to determine if we should instrument the bedrock middleware call
|
|
27
45
|
*
|
|
@@ -42,7 +60,7 @@ function shouldSkipInstrumentation(config) {
|
|
|
42
60
|
*/
|
|
43
61
|
function isStreamingEnabled({ commandName, config }) {
|
|
44
62
|
return (
|
|
45
|
-
commandName
|
|
63
|
+
STREAMING_COMMANDS.has(commandName) &&
|
|
46
64
|
config.ai_monitoring?.streaming?.enabled
|
|
47
65
|
)
|
|
48
66
|
}
|
|
@@ -242,6 +260,7 @@ function createBedrockResponse({ bedrockCommand, response, err }) {
|
|
|
242
260
|
function getBedrockSpec({ commandName }, shim, _original, _name, args) {
|
|
243
261
|
const { agent } = shim
|
|
244
262
|
const { input } = args[0]
|
|
263
|
+
const isConverse = CONVERSE_COMMANDS.has(commandName)
|
|
245
264
|
const bedrockCommand = new BedrockCommand(input)
|
|
246
265
|
const { modelType } = bedrockCommand
|
|
247
266
|
|
|
@@ -261,17 +280,33 @@ function getBedrockSpec({ commandName }, shim, _original, _name, args) {
|
|
|
261
280
|
|
|
262
281
|
if (err && !response) {
|
|
263
282
|
handleResponse(passThroughParams)
|
|
264
|
-
} else if (response.output.body instanceof Uint8Array) {
|
|
283
|
+
} else if (response.output.body instanceof Uint8Array || 'output' in response.output) {
|
|
265
284
|
// non-streamed response
|
|
266
285
|
handleResponse(passThroughParams)
|
|
267
286
|
} else if (isStreamingEnabled({ commandName, config: agent.config })) {
|
|
268
287
|
// stream response
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
288
|
+
if (isConverse) {
|
|
289
|
+
const handler = new ConverseStreamHandler({
|
|
290
|
+
stream: response.output.stream,
|
|
291
|
+
onComplete: handleResponse,
|
|
292
|
+
passThroughParams
|
|
293
|
+
})
|
|
294
|
+
response.output = {
|
|
295
|
+
...response.output ?? {},
|
|
296
|
+
output: {
|
|
297
|
+
message: {
|
|
298
|
+
content: handler.generator(handleResponse)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
const handler = new StreamHandler({
|
|
304
|
+
stream: response.output.body,
|
|
305
|
+
onComplete: handleResponse,
|
|
306
|
+
passThroughParams
|
|
307
|
+
})
|
|
308
|
+
response.output.body = handler.generator(handleResponse)
|
|
309
|
+
}
|
|
275
310
|
} else if (!isStreamingEnabled({ commandName, config: agent.config })) {
|
|
276
311
|
shim.logger.warn(
|
|
277
312
|
'ai_monitoring.streaming.enabled is set to `false`, stream will not be instrumented.'
|
|
@@ -285,6 +320,11 @@ function getBedrockSpec({ commandName }, shim, _original, _name, args) {
|
|
|
285
320
|
|
|
286
321
|
function handleResponse({ shim, err, response, segment, transaction, bedrockCommand, modelType }) {
|
|
287
322
|
const { agent } = shim
|
|
323
|
+
// For the ConverseStreamHandler only, response.output does not
|
|
324
|
+
// contain stopReason yet, so we set it here.
|
|
325
|
+
if (response?.output && this?.stopReason) {
|
|
326
|
+
response.output.stopReason = this.stopReason
|
|
327
|
+
}
|
|
288
328
|
const bedrockResponse = createBedrockResponse({ bedrockCommand, response, err })
|
|
289
329
|
|
|
290
330
|
addLlmMeta({ agent, segment, transaction })
|
|
@@ -319,13 +359,12 @@ function handleResponse({ shim, err, response, segment, transaction, bedrockComm
|
|
|
319
359
|
* @param {object} config AWS configuration object
|
|
320
360
|
* @param {function} next the next middleware function in stack
|
|
321
361
|
* @param {object} context AWS client context info
|
|
362
|
+
*
|
|
363
|
+
* @returns {function} the next middleware function in stack
|
|
322
364
|
*/
|
|
323
365
|
function bedrockMiddleware(shim, config, next, context) {
|
|
324
366
|
const { commandName } = context
|
|
325
|
-
if (
|
|
326
|
-
commandName === 'InvokeModelCommand' ||
|
|
327
|
-
commandName === 'InvokeModelWithResponseStreamCommand'
|
|
328
|
-
) {
|
|
367
|
+
if (INSTRUMENTED_COMMANDS.has(commandName)) {
|
|
329
368
|
return shim.record(next, getBedrockSpec.bind(null, { commandName }))
|
|
330
369
|
}
|
|
331
370
|
|
|
@@ -394,10 +394,10 @@ module.exports = function initialize(agent, openai, moduleName, shim) {
|
|
|
394
394
|
}
|
|
395
395
|
)
|
|
396
396
|
|
|
397
|
-
// New API introduced in openai@
|
|
397
|
+
// New API introduced in openai@4.87.0
|
|
398
398
|
// Also instruments chat completion creation
|
|
399
399
|
// and creates the LLM events
|
|
400
|
-
if (semver.gte(shim.pkgVersion, '
|
|
400
|
+
if (semver.gte(shim.pkgVersion, '4.87.0')) {
|
|
401
401
|
shim.record(openaiClient.Responses.prototype, 'create', function wrapCreate(shim, create, name, args) {
|
|
402
402
|
const [request] = args
|
|
403
403
|
|
|
@@ -296,7 +296,6 @@ module.exports = function initialize(shim, when) {
|
|
|
296
296
|
ret = agent.tracer.bindFunction(fn, context, true).apply(this, arguments)
|
|
297
297
|
} finally {
|
|
298
298
|
if (ret && typeof ret.then === 'function') {
|
|
299
|
-
// eslint-disable-next-line sonarjs/no-dead-store
|
|
300
299
|
ret = ctx.next[symbols.context].continue(ret)
|
|
301
300
|
}
|
|
302
301
|
}
|
|
@@ -5,25 +5,43 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const { stringifyClaudeChunkedMessage } = require('./utils')
|
|
8
|
+
const { stringifyClaudeChunkedMessage, stringifyConverseChunkedMessage } = require('./utils')
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Parses an AWS
|
|
11
|
+
* Parses an AWS Bedrock command instance into a re-usable entity,
|
|
12
|
+
* unifying logic for both InvokeModel and Converse commands.
|
|
12
13
|
*/
|
|
13
14
|
class BedrockCommand {
|
|
14
15
|
#input
|
|
15
|
-
#body
|
|
16
16
|
#modelId
|
|
17
|
+
#body
|
|
18
|
+
#messages
|
|
19
|
+
#isConverseCommand
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
|
-
* @param {object} input The `input` property from an InvokeModelCommand
|
|
20
|
-
* InvokeModelWithResponseStreamCommand
|
|
21
|
-
*
|
|
22
|
+
* @param {object} input The `input` property from an InvokeModelCommand,
|
|
23
|
+
* InvokeModelWithResponseStreamCommand, ConverseCommand, or
|
|
24
|
+
* ConverseStreamCommand instance.
|
|
22
25
|
*/
|
|
23
26
|
constructor(input) {
|
|
24
27
|
this.#input = input
|
|
25
|
-
this.#body = JSON.parse(this.#input.body)
|
|
26
28
|
this.#modelId = this.#input.modelId?.toLowerCase() ?? ''
|
|
29
|
+
|
|
30
|
+
if (Object.hasOwn(input, 'body') === true) {
|
|
31
|
+
this.#body = JSON.parse(this.#input.body)
|
|
32
|
+
this.#isConverseCommand = false
|
|
33
|
+
} else if (Object.hasOwn(input, 'messages') === true) {
|
|
34
|
+
this.#messages = input.messages
|
|
35
|
+
this.#isConverseCommand = true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @returns {boolean} True if the command is from the Converse API.
|
|
42
|
+
*/
|
|
43
|
+
get isConverse() {
|
|
44
|
+
return this.#isConverseCommand
|
|
27
45
|
}
|
|
28
46
|
|
|
29
47
|
/**
|
|
@@ -32,17 +50,24 @@ class BedrockCommand {
|
|
|
32
50
|
* @returns {number|undefined}
|
|
33
51
|
*/
|
|
34
52
|
get maxTokens() {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} else
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
if (this.#isConverseCommand) {
|
|
54
|
+
// Logic for Converse
|
|
55
|
+
return this.#input?.inferenceConfig?.maxTokens
|
|
56
|
+
} else {
|
|
57
|
+
// Logic for InvokeModel
|
|
58
|
+
if (this.isClaude() === true) {
|
|
59
|
+
return this.#body.max_tokens_to_sample
|
|
60
|
+
}
|
|
61
|
+
if (this.isClaude3() === true || this.isCohere() === true) {
|
|
62
|
+
return this.#body.max_tokens
|
|
63
|
+
}
|
|
64
|
+
if (this.isLlama() === true) {
|
|
65
|
+
return this.#body.max_gen_length
|
|
66
|
+
}
|
|
67
|
+
if (this.isTitan() === true) {
|
|
68
|
+
return this.#body.textGenerationConfig?.maxTokenCount
|
|
69
|
+
}
|
|
44
70
|
}
|
|
45
|
-
return result
|
|
46
71
|
}
|
|
47
72
|
|
|
48
73
|
/**
|
|
@@ -60,40 +85,53 @@ class BedrockCommand {
|
|
|
60
85
|
* @returns {string} One of `embedding` or `completion`.
|
|
61
86
|
*/
|
|
62
87
|
get modelType() {
|
|
63
|
-
//
|
|
64
|
-
// complex identifier, we can implement a more complicated check.
|
|
88
|
+
// This logic is common to both command types
|
|
65
89
|
return this.#modelId.toLowerCase().includes('embed') ? 'embedding' : 'completion'
|
|
66
90
|
}
|
|
67
91
|
|
|
68
92
|
/**
|
|
69
93
|
* The question posed to the LLM.
|
|
70
94
|
*
|
|
71
|
-
* @returns {object[]}
|
|
95
|
+
* @returns {string|string[]|object[]}
|
|
72
96
|
*/
|
|
73
97
|
get prompt() {
|
|
74
|
-
if (this
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
if (this.#isConverseCommand) {
|
|
99
|
+
// Logic for Converse
|
|
100
|
+
const result = []
|
|
101
|
+
for (const message of this.#messages) {
|
|
102
|
+
// The `message.content` field is an array of ContentBlock objects.
|
|
103
|
+
// For text messages, the structure is: content: [{ text: '...' }]
|
|
104
|
+
if (Array.isArray(message?.content) === true) {
|
|
105
|
+
result.push({
|
|
106
|
+
role: message.role,
|
|
107
|
+
content: stringifyConverseChunkedMessage(message.content)
|
|
108
|
+
})
|
|
79
109
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
|
|
110
|
+
}
|
|
111
|
+
return result
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Logic for InvokeModel
|
|
115
|
+
if (this.isTitan() || this.isTitanEmbed()) {
|
|
116
|
+
return [{ role: 'user', content: this.#body.inputText }]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this.isCohereEmbed()) {
|
|
120
|
+
return [{ role: 'user', content: this.#body.texts.join(' ') }]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (
|
|
124
|
+
this.isClaudeTextCompletionApi(this.#body) ||
|
|
125
|
+
this.isCohere() ||
|
|
126
|
+
this.isLlama()
|
|
92
127
|
) {
|
|
93
128
|
return [{ role: 'user', content: this.#body.prompt }]
|
|
94
|
-
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this.isClaudeMessagesApi(this.#body)) {
|
|
95
132
|
return normalizeClaude3Messages(this.#body?.messages)
|
|
96
133
|
}
|
|
134
|
+
|
|
97
135
|
return []
|
|
98
136
|
}
|
|
99
137
|
|
|
@@ -101,20 +139,25 @@ class BedrockCommand {
|
|
|
101
139
|
* @returns {number|undefined}
|
|
102
140
|
*/
|
|
103
141
|
get temperature() {
|
|
104
|
-
|
|
142
|
+
if (this.#isConverseCommand) {
|
|
143
|
+
// Logic for Converse
|
|
144
|
+
return this.#input?.inferenceConfig?.temperature
|
|
145
|
+
}
|
|
146
|
+
// Logic for InvokeModel
|
|
105
147
|
if (this.isTitan() === true) {
|
|
106
|
-
|
|
107
|
-
}
|
|
148
|
+
return this.#body.textGenerationConfig?.temperature
|
|
149
|
+
}
|
|
150
|
+
if (
|
|
108
151
|
this.isClaude() === true ||
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
152
|
+
this.isClaude3() === true ||
|
|
153
|
+
this.isCohere() === true ||
|
|
154
|
+
this.isLlama() === true
|
|
112
155
|
) {
|
|
113
|
-
|
|
156
|
+
return this.#body.temperature
|
|
114
157
|
}
|
|
115
|
-
return result
|
|
116
158
|
}
|
|
117
159
|
|
|
160
|
+
// Helper methods that depend on modelId (common to both types)
|
|
118
161
|
isClaude() {
|
|
119
162
|
return this.#modelId.split('.').slice(-2).join('.').startsWith('anthropic.claude-v')
|
|
120
163
|
}
|
|
@@ -143,21 +186,22 @@ class BedrockCommand {
|
|
|
143
186
|
return this.#modelId.startsWith('amazon.titan-embed')
|
|
144
187
|
}
|
|
145
188
|
|
|
146
|
-
isClaudeMessagesApi() {
|
|
147
|
-
return (this.isClaude3() === true || this.isClaude() === true) && 'messages' in
|
|
189
|
+
isClaudeMessagesApi(body) {
|
|
190
|
+
return (this.isClaude3() === true || this.isClaude() === true) && 'messages' in body
|
|
148
191
|
}
|
|
149
192
|
|
|
150
|
-
isClaudeTextCompletionApi() {
|
|
151
|
-
return this.isClaude() === true && 'prompt' in
|
|
193
|
+
isClaudeTextCompletionApi(body) {
|
|
194
|
+
return this.isClaude() === true && 'prompt' in body
|
|
152
195
|
}
|
|
153
196
|
}
|
|
154
197
|
|
|
155
198
|
/**
|
|
156
|
-
* Claude v3 requests in Bedrock can have two different "chat" flavors.
|
|
199
|
+
* Claude v3 requests in Bedrock can have two different "chat" flavors.
|
|
200
|
+
* This function normalizes them into a consistent
|
|
157
201
|
* format per the AIM agent spec
|
|
158
202
|
*
|
|
159
|
-
* @param messages - The raw array of messages passed to the invoke API
|
|
160
|
-
* @returns {
|
|
203
|
+
* @param {Array<object>} messages - The raw array of messages passed to the invoke API
|
|
204
|
+
* @returns {Array<object>} - The normalized messages
|
|
161
205
|
*/
|
|
162
206
|
function normalizeClaude3Messages(messages) {
|
|
163
207
|
const result = []
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const { stringifyClaudeChunkedMessage } = require('./utils')
|
|
8
|
+
const { stringifyClaudeChunkedMessage, stringifyConverseChunkedMessage } = require('./utils')
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {object} AwsBedrockMiddlewareResponse
|
|
@@ -18,60 +18,49 @@ const { stringifyClaudeChunkedMessage } = require('./utils')
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Represents a response from the Bedrock API
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* an abstraction that normalizes responses into a known interface and
|
|
25
|
-
* simplifies accessing desired fields.
|
|
21
|
+
* Represents a response from the Bedrock API, handling both standard and Converse API responses.
|
|
22
|
+
* This object provides an abstraction that normalizes responses into a known interface and
|
|
23
|
+
* simplifies accessing desired fields, accommodating the varied shapes of Bedrock API responses.
|
|
26
24
|
*/
|
|
27
25
|
class BedrockResponse {
|
|
26
|
+
#originalResponse
|
|
28
27
|
#innerResponse
|
|
29
28
|
#innerOutput
|
|
30
29
|
#parsedBody
|
|
30
|
+
#output
|
|
31
31
|
#command
|
|
32
32
|
#completions = []
|
|
33
33
|
#id
|
|
34
|
+
#isConverse
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* @param {object} params
|
|
37
38
|
* @param {AwsBedrockMiddlewareResponse} params.response
|
|
38
39
|
* @param {BedrockCommand} params.bedrockCommand
|
|
39
|
-
* @param params.isError
|
|
40
|
+
* @param {boolean} params.isError
|
|
40
41
|
*/
|
|
41
42
|
constructor({ response, bedrockCommand, isError = false }) {
|
|
43
|
+
this.#originalResponse = response
|
|
42
44
|
this.#innerResponse = isError ? response.$response : response.response
|
|
43
45
|
this.#command = bedrockCommand
|
|
44
46
|
this.isError = isError
|
|
47
|
+
this.#isConverse = this.#command.isConverse ?? false
|
|
45
48
|
|
|
46
49
|
if (this.isError) {
|
|
47
50
|
return
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
this.#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
body
|
|
60
|
-
|
|
61
|
-
if (body?.type === 'message_stop') {
|
|
62
|
-
// Streamed response
|
|
63
|
-
this.#completions = body.completions
|
|
64
|
-
} else {
|
|
65
|
-
this.#completions = [stringifyClaudeChunkedMessage(body?.content)]
|
|
66
|
-
}
|
|
67
|
-
this.#id = body.id
|
|
68
|
-
} else if (cmd.isCohere() === true) {
|
|
69
|
-
this.#completions = body.generations?.map((g) => g.text) ?? []
|
|
70
|
-
this.#id = body.id
|
|
71
|
-
} else if (cmd.isLlama() === true) {
|
|
72
|
-
body.generation && this.#completions.push(body.generation)
|
|
73
|
-
} else if (cmd.isTitan() === true) {
|
|
74
|
-
this.#completions = body.results?.map((r) => r.outputText) ?? []
|
|
53
|
+
if (this.#isConverse) {
|
|
54
|
+
this.#innerOutput = response.output.output
|
|
55
|
+
this.#output = this.#innerOutput.message
|
|
56
|
+
} else {
|
|
57
|
+
this.#innerOutput = response.output
|
|
58
|
+
const json = new TextDecoder().decode(this.#innerOutput.body)
|
|
59
|
+
this.#parsedBody = JSON.parse(json)
|
|
60
|
+
|
|
61
|
+
const cmd = this.#command
|
|
62
|
+
const body = this.#parsedBody
|
|
63
|
+
this.#extractCompletionsAndId(cmd, body)
|
|
75
64
|
}
|
|
76
65
|
}
|
|
77
66
|
|
|
@@ -82,32 +71,40 @@ class BedrockResponse {
|
|
|
82
71
|
* prompt.
|
|
83
72
|
*/
|
|
84
73
|
get completions() {
|
|
85
|
-
|
|
74
|
+
if (this.#isConverse === false) {
|
|
75
|
+
return this.#completions
|
|
76
|
+
}
|
|
77
|
+
const content = this.#output?.content
|
|
78
|
+
if (!content) return []
|
|
79
|
+
return [typeof content === 'string' ? content : stringifyConverseChunkedMessage(content)]
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
/**
|
|
89
83
|
* The reason the model has given for finishing the response.
|
|
90
84
|
*
|
|
91
|
-
* @returns {string
|
|
85
|
+
* @returns {string|undefined}
|
|
92
86
|
*/
|
|
93
87
|
get finishReason() {
|
|
94
|
-
let result
|
|
95
|
-
|
|
96
88
|
if (this.isError) {
|
|
97
|
-
return
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
if (this.#isConverse) {
|
|
92
|
+
return this.#originalResponse.output.stopReason
|
|
98
93
|
}
|
|
99
|
-
|
|
100
94
|
const cmd = this.#command
|
|
101
95
|
if (cmd.isClaude() === true || cmd.isClaude3() === true) {
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
return this.#parsedBody.stop_reason
|
|
97
|
+
}
|
|
98
|
+
if (cmd.isCohere() === true) {
|
|
99
|
+
return this.#parsedBody.generations?.find((r) => r.finish_reason !== null)?.finish_reason
|
|
100
|
+
}
|
|
101
|
+
if (cmd.isLlama() === true) {
|
|
102
|
+
return this.#parsedBody.stop_reason
|
|
109
103
|
}
|
|
110
|
-
|
|
104
|
+
if (cmd.isTitan() === true) {
|
|
105
|
+
return this.#parsedBody.results?.find((r) => r.completionReason !== null)?.completionReason
|
|
106
|
+
}
|
|
107
|
+
return undefined
|
|
111
108
|
}
|
|
112
109
|
|
|
113
110
|
/**
|
|
@@ -125,7 +122,8 @@ class BedrockResponse {
|
|
|
125
122
|
* @returns {string|undefined}
|
|
126
123
|
*/
|
|
127
124
|
get id() {
|
|
128
|
-
|
|
125
|
+
// For Converse API, the requestId serves as the id.
|
|
126
|
+
return this.#isConverse ? this.requestId : this.#id
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
/**
|
|
@@ -146,12 +144,30 @@ class BedrockResponse {
|
|
|
146
144
|
return this.#innerResponse.statusCode
|
|
147
145
|
}
|
|
148
146
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Extracts and sets #completions and #id from the InvokeModel response body.
|
|
149
|
+
* @param {BedrockCommand} cmd
|
|
150
|
+
* @param {*} body
|
|
151
|
+
*/
|
|
152
|
+
#extractCompletionsAndId(cmd, body) {
|
|
153
|
+
if (cmd.isClaude() === true) {
|
|
154
|
+
body.completion && this.#completions.push(body.completion)
|
|
155
|
+
} else if (cmd.isClaude3() === true) {
|
|
156
|
+
if (body?.type === 'message_stop') {
|
|
157
|
+
// Streamed response
|
|
158
|
+
this.#completions = body.completions
|
|
159
|
+
} else {
|
|
160
|
+
this.#completions = [stringifyClaudeChunkedMessage(body?.content)]
|
|
161
|
+
}
|
|
162
|
+
this.#id = body.id
|
|
163
|
+
} else if (cmd.isCohere() === true) {
|
|
164
|
+
this.#completions = body.generations?.map((g) => g.text) ?? []
|
|
165
|
+
this.#id = body.id
|
|
166
|
+
} else if (cmd.isLlama() === true) {
|
|
167
|
+
body.generation && this.#completions.push(body.generation)
|
|
168
|
+
} else if (cmd.isTitan() === true) {
|
|
169
|
+
this.#completions = body.results?.map((r) => r.outputText) ?? []
|
|
153
170
|
}
|
|
154
|
-
return undefined
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
173
|
|
|
@@ -57,7 +57,7 @@ class LlmChatCompletionMessage extends LlmEvent {
|
|
|
57
57
|
|
|
58
58
|
#setId(index) {
|
|
59
59
|
const cmd = this.bedrockCommand
|
|
60
|
-
if (cmd.isTitan() === true || cmd.isClaude() === true) {
|
|
60
|
+
if (cmd.isConverse || cmd.isTitan() === true || cmd.isClaude() === true) {
|
|
61
61
|
this.id = `${this.id}-${index}`
|
|
62
62
|
} else if (cmd.isCohere() === true) {
|
|
63
63
|
this.id = `${this.bedrockResponse.id || this.id}-${index}`
|
|
@@ -27,16 +27,14 @@ class LlmChatCompletionSummary extends LlmEvent {
|
|
|
27
27
|
const { segment, isError } = params
|
|
28
28
|
this.error = isError
|
|
29
29
|
this.duration = segment.getDurationInMillis()
|
|
30
|
-
this['request.max_tokens'] = this.bedrockCommand.maxTokens
|
|
31
|
-
|
|
32
|
-
const nm = 'response.number_of_messages'
|
|
33
|
-
const cfr = 'response.choices.finish_reason'
|
|
34
|
-
const rt = 'request.temperature'
|
|
35
30
|
|
|
36
31
|
const cmd = this.bedrockCommand
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this[
|
|
32
|
+
const res = this.bedrockResponse
|
|
33
|
+
|
|
34
|
+
this['request.max_tokens'] = cmd.maxTokens
|
|
35
|
+
this['response.choices.finish_reason'] = res.finishReason
|
|
36
|
+
this['request.temperature'] = cmd.temperature
|
|
37
|
+
this['response.number_of_messages'] = (cmd.prompt.length ?? 0) + (res.completions.length ?? 0)
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A stream handler processes a streamed response from the Bedrock API by
|
|
10
|
+
* intercepting each stream event, passing that event unmodified up to the
|
|
11
|
+
* consuming client, and then collecting the information into an "API response"
|
|
12
|
+
* object that satisfies the requirements of {@link BedrockResponse}. Once the
|
|
13
|
+
* stream has reached its end, the handler applies some finalizations to the
|
|
14
|
+
* compiled response object, updates the pass through parameters with the new
|
|
15
|
+
* object, and then invokes the final response handler passed in through
|
|
16
|
+
* `onComplete`.
|
|
17
|
+
*/
|
|
18
|
+
class ConverseStreamHandler {
|
|
19
|
+
// We have to make most of the properties of this object public so that
|
|
20
|
+
// the at-construction-time attached generator function can access them
|
|
21
|
+
// through the `this` reference. See https://jrfom.com/posts/2023/10/31/js-classes/
|
|
22
|
+
// for details on why this is necessary.
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The parameters to pass through to the `onComplete` function once the
|
|
26
|
+
* stream has been processed. The `response` property on this object will
|
|
27
|
+
* be overwritten with the response object that has been compiled by the
|
|
28
|
+
* stream handler.
|
|
29
|
+
*/
|
|
30
|
+
passThroughParams
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The original async iterable returned from the AWS SDK.
|
|
34
|
+
*/
|
|
35
|
+
stream
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The New Relic agent's internal trace segment. The `.touch` method will be
|
|
39
|
+
* used to mark the end time of the stream processing.
|
|
40
|
+
*/
|
|
41
|
+
segment
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* For streaming messages, we want to capture the effective message chunks like we would see in the non-streaming API
|
|
45
|
+
*/
|
|
46
|
+
observedChunks = []
|
|
47
|
+
|
|
48
|
+
stopReason
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Represents an API response object as {@link BedrockResponse} expects.
|
|
52
|
+
* It will be updated by the stream handler with information received
|
|
53
|
+
* during processing of the stream. Upon stream completion, this object
|
|
54
|
+
* will replace the `response` property of `passThroughParams`.
|
|
55
|
+
*
|
|
56
|
+
* @type {object}
|
|
57
|
+
*/
|
|
58
|
+
response = {
|
|
59
|
+
response: {
|
|
60
|
+
headers: {},
|
|
61
|
+
statusCode: 200
|
|
62
|
+
},
|
|
63
|
+
output: {
|
|
64
|
+
output: {
|
|
65
|
+
message: {
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The function that will be invoked once the stream processing has finished.
|
|
74
|
+
* It will receive `this.passThroughParams` as the only parameter.
|
|
75
|
+
*/
|
|
76
|
+
onComplete
|
|
77
|
+
|
|
78
|
+
constructor({ stream, passThroughParams, onComplete }) {
|
|
79
|
+
this.passThroughParams = passThroughParams
|
|
80
|
+
this.stream = stream
|
|
81
|
+
this.onComplete = onComplete
|
|
82
|
+
this.segment = passThroughParams.segment
|
|
83
|
+
this.generator = handleConverse
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Encodes the output body into a Uint8Array, updates the pass through
|
|
88
|
+
* parameters with the compiled response object, and invokes the response
|
|
89
|
+
* handler. The trace segment is also updated to mark the end of the stream
|
|
90
|
+
* processing and account for the time it took to process the stream within
|
|
91
|
+
* the trace.
|
|
92
|
+
*/
|
|
93
|
+
finish() {
|
|
94
|
+
this.passThroughParams.response = this.response
|
|
95
|
+
this.onComplete(this.passThroughParams)
|
|
96
|
+
|
|
97
|
+
this.segment.touch()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* If the given event is the last event in the stream, update the response
|
|
102
|
+
* headers with the metrics data from the event.
|
|
103
|
+
*
|
|
104
|
+
* @param {object} parsedEvent
|
|
105
|
+
*/
|
|
106
|
+
updateHeaders(parsedEvent) {
|
|
107
|
+
this.response.response.headers = {
|
|
108
|
+
'x-amzn-requestid': this.passThroughParams.response.response.headers['x-amzn-requestid']
|
|
109
|
+
}
|
|
110
|
+
delete parsedEvent['amazon-bedrock-invocationMetrics']
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
115
|
+
async function * handleConverse() {
|
|
116
|
+
let activeChunk = null
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
for await (const event of this.stream) {
|
|
120
|
+
yield event
|
|
121
|
+
this.updateHeaders(event)
|
|
122
|
+
if (event.messageStart?.role) {
|
|
123
|
+
this.role = 'assistant'
|
|
124
|
+
} else if (event.contentBlockStart?.start) {
|
|
125
|
+
// Handles a Content block start event. Tool use only.
|
|
126
|
+
const blockStartData = event.contentBlockStart.start
|
|
127
|
+
if (blockStartData.toolUse) {
|
|
128
|
+
activeChunk = { toolUse: { name: blockStartData.toolUse.name } }
|
|
129
|
+
}
|
|
130
|
+
} else if (event.contentBlockStop) {
|
|
131
|
+
if (activeChunk !== null) {
|
|
132
|
+
this.observedChunks.push(activeChunk)
|
|
133
|
+
activeChunk = null
|
|
134
|
+
}
|
|
135
|
+
} else if (event.contentBlockDelta?.delta) {
|
|
136
|
+
if (event.contentBlockDelta.delta.text) {
|
|
137
|
+
// It seems like the first streamed chunk does not always start with a contentBlockStart message
|
|
138
|
+
// If the stream starts with a delta, assume the current chunk is text
|
|
139
|
+
if (activeChunk === null) {
|
|
140
|
+
activeChunk = { text: '' }
|
|
141
|
+
}
|
|
142
|
+
activeChunk.text += event.contentBlockDelta.delta.text
|
|
143
|
+
}
|
|
144
|
+
// There are also deltas for tool use (stringified inputs) but we don't currently record them so we just ignore for now
|
|
145
|
+
} else if (event.messageStop) {
|
|
146
|
+
this.stopReason = event.messageStop?.stopReason
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} finally {
|
|
150
|
+
this.response.output.output.message.content = this.observedChunks
|
|
151
|
+
this.finish()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = ConverseStreamHandler
|
|
@@ -13,5 +13,6 @@ module.exports = {
|
|
|
13
13
|
LlmEmbedding: require('./embedding'),
|
|
14
14
|
LlmEvent: require('./event'),
|
|
15
15
|
LlmError: require('./error'),
|
|
16
|
-
StreamHandler: require('./stream-handler')
|
|
16
|
+
StreamHandler: require('./stream-handler'),
|
|
17
|
+
ConverseStreamHandler: require('./converse-stream-handler')
|
|
17
18
|
}
|
|
@@ -31,6 +31,43 @@ function stringifyClaudeChunkedMessage(chunks) {
|
|
|
31
31
|
return stringifiedChunks.join('\n\n')
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param {object[]} chunks - The "chunks" that make up a single conceptual message. In a multi-modal scenario, a single message
|
|
37
|
+
* might have a number of different-typed chunks interspersed
|
|
38
|
+
* @returns {string} - A stringified version of the message. We make a best-effort effort attempt to represent non-text chunks. In the future
|
|
39
|
+
* we may want to extend the agent to support these non-text chunks in a richer way. Placeholders are represented in an XML-like format but
|
|
40
|
+
* are NOT intended to be parsed as valid XML
|
|
41
|
+
*/
|
|
42
|
+
function stringifyConverseChunkedMessage(chunks) {
|
|
43
|
+
const stringifiedChunks = chunks.map((chunk) => {
|
|
44
|
+
if ('text' in chunk) {
|
|
45
|
+
return chunk.text
|
|
46
|
+
} else if ('image' in chunk) {
|
|
47
|
+
return '<image>'
|
|
48
|
+
} else if ('document' in chunk) {
|
|
49
|
+
return `<document>${chunk.document.name ?? ''}</document>`
|
|
50
|
+
} else if ('toolUse' in chunk) {
|
|
51
|
+
return `<tool_use>${chunk.toolUse?.name ?? ''}</tool_use>`
|
|
52
|
+
} else if ('json' in chunk) {
|
|
53
|
+
return `<json>${JSON.stringify(chunk.json)}</json>`
|
|
54
|
+
} else if ('toolResult' in chunk) {
|
|
55
|
+
// Tool results can have their own chunks. For now we intentionally don't recurse in for non-text tool results
|
|
56
|
+
return `<tool_result>${
|
|
57
|
+
stringifyConverseChunkedMessage(
|
|
58
|
+
(chunk.toolResult.content ?? [])
|
|
59
|
+
.filter(subChunk => !('toolUse' in subChunk || 'toolResult' in subChunk))
|
|
60
|
+
)
|
|
61
|
+
}</tool_result>`
|
|
62
|
+
} else if ('guardContent' in chunk) {
|
|
63
|
+
return `<guard_content>${chunk.guardContent?.text ?? ''}</guard_content>`
|
|
64
|
+
}
|
|
65
|
+
return '<unknown_chunk>'
|
|
66
|
+
})
|
|
67
|
+
return stringifiedChunks.join('\n\n')
|
|
68
|
+
}
|
|
69
|
+
|
|
34
70
|
module.exports = {
|
|
35
|
-
stringifyClaudeChunkedMessage
|
|
71
|
+
stringifyClaudeChunkedMessage,
|
|
72
|
+
stringifyConverseChunkedMessage
|
|
36
73
|
}
|
package/lib/shim/shim.js
CHANGED
|
@@ -2030,7 +2030,7 @@ function wrapStreamEmit({ stream, shim, segment, specEvent, shouldCreateSegment,
|
|
|
2030
2030
|
const newContext = context.enterSegment({ segment: eventSegment })
|
|
2031
2031
|
eventBoundEmit = shim.bindContext({ nodule: emit, full: true, context: newContext })
|
|
2032
2032
|
}
|
|
2033
|
-
eventSegment.addAttribute('count', ++emitCount)
|
|
2033
|
+
if (eventSegment) eventSegment.addAttribute('count', ++emitCount)
|
|
2034
2034
|
emitToCall = eventBoundEmit
|
|
2035
2035
|
}
|
|
2036
2036
|
if (evnt === 'end' || evnt === 'error') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.25.1",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"dependencies": {
|
|
204
204
|
"@grpc/grpc-js": "^1.13.2",
|
|
205
205
|
"@grpc/proto-loader": "^0.7.5",
|
|
206
|
-
"@newrelic/security-agent": "^2.4.
|
|
206
|
+
"@newrelic/security-agent": "^2.4.4",
|
|
207
207
|
"@opentelemetry/api": "^1.9.0",
|
|
208
208
|
"@opentelemetry/core": "^2.0.0",
|
|
209
209
|
"@opentelemetry/exporter-metrics-otlp-proto": "^0.201.1",
|