diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7fa14471..1b29c928 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+### Bug Fixes
+
+- **anthropic:** support streaming for completion API ([#191](https://github.com/traceloop/openllmetry-js/issues/191)) ([0efb330](https://github.com/traceloop/openllmetry-js/commit/0efb3302f9ff767cba29519265c13ca4f02cf612))
+
+### Features
+
+- **anthropic:** instrumentation ([#188](https://github.com/traceloop/openllmetry-js/issues/188)) ([f40df74](https://github.com/traceloop/openllmetry-js/commit/f40df747143279a9a153db58020bf4531b5c171f))
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
### Bug Fixes
diff --git a/README.md b/README.md
index d6cffd95..f9d2103f 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ OpenLLMetry-JS can instrument everything that [OpenTelemetry already instruments
- ✅ OpenAI
- ✅ Azure OpenAI
-- ⏳ Anthropic
+- ✅ Anthropic
- ✅ Cohere
- ⏳ Replicate
- ⏳ HuggingFace
diff --git a/lerna.json b/lerna.json
index 4da0e867..4f9c5074 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,6 +1,6 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
- "version": "0.5.29",
+ "version": "0.6.0",
"packages": ["packages/*"],
"useNx": true
}
diff --git a/package-lock.json b/package-lock.json
index 1750503d..6110f9b1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7412,6 +7412,10 @@
"resolved": "packages/ai-semantic-conventions",
"link": true
},
+ "node_modules/@traceloop/instrumentation-anthropic": {
+ "resolved": "packages/instrumentation-anthropic",
+ "link": true
+ },
"node_modules/@traceloop/instrumentation-azure": {
"resolved": "packages/instrumentation-azure",
"link": true
@@ -21979,7 +21983,7 @@
},
"packages/ai-semantic-conventions": {
"name": "@traceloop/ai-semantic-conventions",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/api": "^1.7.0"
@@ -21988,15 +21992,92 @@
"node": ">=14"
}
},
+ "packages/instrumentation-anthropic": {
+ "name": "@traceloop/instrumentation-anthropic",
+ "version": "0.6.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "^1.22.0",
+ "@opentelemetry/instrumentation": "^0.49.0",
+ "@opentelemetry/semantic-conventions": "^1.22.0",
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
+ },
+ "devDependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
+ "@pollyjs/adapter-node-http": "^6.0.6",
+ "@pollyjs/core": "^6.0.6",
+ "@pollyjs/persister-fs": "^6.0.6",
+ "@types/mocha": "^10.0.6",
+ "ts-mocha": "^10.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "packages/instrumentation-anthropic/node_modules/@anthropic-ai/sdk": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.20.1.tgz",
+ "integrity": "sha512-isoelcNvCC0dKJ9cXPIpHaHjrW4EQlXIp4f/3zT3jMZDqSHCx5PVnfsgOiERM5NUTpdKGMDURewoKYK4a9Wu3w==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "^18.11.18",
+ "@types/node-fetch": "^2.6.4",
+ "abort-controller": "^3.0.0",
+ "agentkeepalive": "^4.2.1",
+ "form-data-encoder": "1.7.2",
+ "formdata-node": "^4.3.2",
+ "node-fetch": "^2.6.7",
+ "web-streams-polyfill": "^3.2.1"
+ }
+ },
+ "packages/instrumentation-anthropic/node_modules/@opentelemetry/instrumentation": {
+ "version": "0.49.1",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz",
+ "integrity": "sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ==",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.49.1",
+ "@types/shimmer": "^1.0.2",
+ "import-in-the-middle": "1.7.1",
+ "require-in-the-middle": "^7.1.1",
+ "semver": "^7.5.2",
+ "shimmer": "^1.2.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "packages/instrumentation-anthropic/node_modules/@types/node": {
+ "version": "18.19.29",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
+ "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "packages/instrumentation-anthropic/node_modules/import-in-the-middle": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz",
+ "integrity": "sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==",
+ "dependencies": {
+ "acorn": "^8.8.2",
+ "acorn-import-assertions": "^1.9.0",
+ "cjs-module-lexer": "^1.2.2",
+ "module-details-from-path": "^1.0.3"
+ }
+ },
"packages/instrumentation-azure": {
"name": "@traceloop/instrumentation-azure",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@azure/openai": "^1.0.0-beta.10",
@@ -22040,13 +22121,13 @@
},
"packages/instrumentation-bedrock": {
"name": "@traceloop/instrumentation-bedrock",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
@@ -22088,13 +22169,13 @@
},
"packages/instrumentation-cohere": {
"name": "@traceloop/instrumentation-cohere",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.44.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@pollyjs/adapter-node-http": "^6.0.6",
@@ -22108,13 +22189,13 @@
},
"packages/instrumentation-langchain": {
"name": "@traceloop/instrumentation-langchain",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@langchain/community": "^0.0.34",
@@ -22696,13 +22777,13 @@
},
"packages/instrumentation-llamaindex": {
"name": "@traceloop/instrumentation-llamaindex",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
"lodash": "^4.17.21"
},
"devDependencies": {
@@ -22747,13 +22828,13 @@
},
"packages/instrumentation-openai": {
"name": "@traceloop/instrumentation-openai",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
"tiktoken": "^1.0.13"
},
"devDependencies": {
@@ -22799,13 +22880,13 @@
},
"packages/instrumentation-pinecone": {
"name": "@traceloop/instrumentation-pinecone",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@pinecone-database/pinecone": "^2.0.1",
@@ -22847,13 +22928,13 @@
},
"packages/instrumentation-vertexai": {
"name": "@traceloop/instrumentation-vertexai",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@google-cloud/aiplatform": "^3.10.0",
@@ -22895,6 +22976,7 @@
"version": "0.0.1",
"license": "Apache-2.0",
"dependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
"@azure/openai": "^1.0.0-beta.11",
"@google-cloud/aiplatform": "^3.10.0",
@@ -22911,6 +22993,21 @@
"node": ">=14"
}
},
+ "packages/sample-app/node_modules/@anthropic-ai/sdk": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.20.1.tgz",
+ "integrity": "sha512-isoelcNvCC0dKJ9cXPIpHaHjrW4EQlXIp4f/3zT3jMZDqSHCx5PVnfsgOiERM5NUTpdKGMDURewoKYK4a9Wu3w==",
+ "dependencies": {
+ "@types/node": "^18.11.18",
+ "@types/node-fetch": "^2.6.4",
+ "abort-controller": "^3.0.0",
+ "agentkeepalive": "^4.2.1",
+ "form-data-encoder": "1.7.2",
+ "formdata-node": "^4.3.2",
+ "node-fetch": "^2.6.7",
+ "web-streams-polyfill": "^3.2.1"
+ }
+ },
"packages/sample-app/node_modules/@aws-crypto/sha256-js": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
@@ -23294,6 +23391,14 @@
}
}
},
+ "packages/sample-app/node_modules/@types/node": {
+ "version": "18.19.29",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
+ "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
"packages/sample-app/node_modules/replicate": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/replicate/-/replicate-0.18.1.tgz",
@@ -23309,20 +23414,21 @@
},
"packages/traceloop-sdk": {
"name": "@traceloop/node-server-sdk",
- "version": "0.5.29",
+ "version": "0.6.0",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/exporter-trace-otlp-proto": "^0.49.1",
"@opentelemetry/sdk-node": "^0.49.1",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
- "@traceloop/instrumentation-azure": "^0.5.29",
- "@traceloop/instrumentation-bedrock": "^0.5.29",
- "@traceloop/instrumentation-cohere": "^0.5.29",
- "@traceloop/instrumentation-langchain": "^0.5.29",
- "@traceloop/instrumentation-llamaindex": "^0.5.29",
- "@traceloop/instrumentation-openai": "^0.5.29",
- "@traceloop/instrumentation-pinecone": "^0.5.29",
- "@traceloop/instrumentation-vertexai": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
+ "@traceloop/instrumentation-anthropic": "^0.6.0",
+ "@traceloop/instrumentation-azure": "^0.6.0",
+ "@traceloop/instrumentation-bedrock": "^0.6.0",
+ "@traceloop/instrumentation-cohere": "^0.6.0",
+ "@traceloop/instrumentation-langchain": "^0.6.0",
+ "@traceloop/instrumentation-llamaindex": "^0.6.0",
+ "@traceloop/instrumentation-openai": "^0.6.0",
+ "@traceloop/instrumentation-pinecone": "^0.6.0",
+ "@traceloop/instrumentation-vertexai": "^0.6.0",
"@types/nunjucks": "^3.2.5",
"cross-fetch": "^4.0.0",
"fetch-retry": "^5.0.6",
@@ -23332,6 +23438,7 @@
"uuid": "^9.0.1"
},
"devDependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
"@azure/openai": "^1.0.0-beta.11",
"@google-cloud/aiplatform": "^3.10.0",
@@ -23354,6 +23461,31 @@
"node": ">=14"
}
},
+ "packages/traceloop-sdk/node_modules/@anthropic-ai/sdk": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.20.1.tgz",
+ "integrity": "sha512-isoelcNvCC0dKJ9cXPIpHaHjrW4EQlXIp4f/3zT3jMZDqSHCx5PVnfsgOiERM5NUTpdKGMDURewoKYK4a9Wu3w==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "^18.11.18",
+ "@types/node-fetch": "^2.6.4",
+ "abort-controller": "^3.0.0",
+ "agentkeepalive": "^4.2.1",
+ "form-data-encoder": "1.7.2",
+ "formdata-node": "^4.3.2",
+ "node-fetch": "^2.6.7",
+ "web-streams-polyfill": "^3.2.1"
+ }
+ },
+ "packages/traceloop-sdk/node_modules/@anthropic-ai/sdk/node_modules/@types/node": {
+ "version": "18.19.29",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
+ "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
"packages/traceloop-sdk/node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
diff --git a/packages/ai-semantic-conventions/CHANGELOG.md b/packages/ai-semantic-conventions/CHANGELOG.md
index e029fea5..e7a49fa2 100644
--- a/packages/ai-semantic-conventions/CHANGELOG.md
+++ b/packages/ai-semantic-conventions/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/ai-semantic-conventions
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
### Bug Fixes
diff --git a/packages/ai-semantic-conventions/package.json b/packages/ai-semantic-conventions/package.json
index 7df77f78..4b94f056 100644
--- a/packages/ai-semantic-conventions/package.json
+++ b/packages/ai-semantic-conventions/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/ai-semantic-conventions",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "OpenTelemetry ai-specific semantic conventions",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
diff --git a/packages/instrumentation-anthropic/.eslintignore b/packages/instrumentation-anthropic/.eslintignore
new file mode 100644
index 00000000..b512c09d
--- /dev/null
+++ b/packages/instrumentation-anthropic/.eslintignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/packages/instrumentation-anthropic/.eslintrc.json b/packages/instrumentation-anthropic/.eslintrc.json
new file mode 100644
index 00000000..9d9c0db5
--- /dev/null
+++ b/packages/instrumentation-anthropic/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/packages/instrumentation-anthropic/.prettierignore b/packages/instrumentation-anthropic/.prettierignore
new file mode 100644
index 00000000..258e27f6
--- /dev/null
+++ b/packages/instrumentation-anthropic/.prettierignore
@@ -0,0 +1,2 @@
+/dist
+/coverage
\ No newline at end of file
diff --git a/packages/instrumentation-anthropic/CHANGELOG.md b/packages/instrumentation-anthropic/CHANGELOG.md
new file mode 100644
index 00000000..c84a8b69
--- /dev/null
+++ b/packages/instrumentation-anthropic/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+### Bug Fixes
+
+- **anthropic:** support streaming for completion API ([#191](https://github.com/traceloop/openllmetry-js/issues/191)) ([0efb330](https://github.com/traceloop/openllmetry-js/commit/0efb3302f9ff767cba29519265c13ca4f02cf612))
+
+### Features
+
+- **anthropic:** instrumentation ([#188](https://github.com/traceloop/openllmetry-js/issues/188)) ([f40df74](https://github.com/traceloop/openllmetry-js/commit/f40df747143279a9a153db58020bf4531b5c171f))
diff --git a/packages/instrumentation-anthropic/README.md b/packages/instrumentation-anthropic/README.md
new file mode 100644
index 00000000..fdf5bc1b
--- /dev/null
+++ b/packages/instrumentation-anthropic/README.md
@@ -0,0 +1,55 @@
+# OpenTelemetry Anthropic instrumentation for Node.js
+
+[![NPM Published Version][npm-img]][npm-url]
+[![Apache License][license-image]][license-image]
+
+This module provides automatic instrumentation for [`Anthropic Typescript SDK`](https://github.com/anthropics/anthropic-sdk-typescript) module, which may be loaded using the [`@opentelemetry/sdk-trace-node`](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package and is included in the [`@traceloop/node-server-sdk`](https://www.npmjs.com/package/@traceloop/node-server-sdk) bundle.
+
+If total installation size is not constrained, it is recommended to use the [`@traceloop/node-server-sdk`](https://www.npmjs.com/package/@traceloop/node-server-sdk) bundle for the most seamless instrumentation experience.
+
+Compatible with OpenTelemetry JS API and SDK `1.0+`.
+
+## Installation
+
+```bash
+npm install --save @traceloop/instrumentation-anthropic
+```
+
+## Supported Versions
+
+- `>=0.9.1`
+
+## Usage
+
+To load a specific plugin, specify it in the registerInstrumentations's configuration:
+
+```js
+const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
+const {
+ AnthropicInstrumentation,
+} = require("@traceloop/instrumentation-anthropic");
+const { registerInstrumentations } = require("@opentelemetry/instrumentation");
+
+const provider = new NodeTracerProvider();
+provider.register();
+
+registerInstrumentations({
+ instrumentations: [new AnthropicInstrumentation()],
+});
+```
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us on [Slack][slack-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[slack-url]: https://traceloop.com/slack
+[license-url]: https://github.com/traceloop/openllmetry-js/blob/main/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[npm-url]: https://www.npmjs.com/package/@traceloop/instrumentation-anthropic
+[npm-img]: https://badge.fury.io/js/%40traceloop%2Finstrumentation-anthropic.svg
diff --git a/packages/instrumentation-anthropic/package.json b/packages/instrumentation-anthropic/package.json
new file mode 100644
index 00000000..07ad0411
--- /dev/null
+++ b/packages/instrumentation-anthropic/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "@traceloop/instrumentation-anthropic",
+ "version": "0.6.0",
+ "description": "Anthropic Instrumentaion",
+ "main": "dist/index.js",
+ "module": "dist/index.mjs",
+ "types": "dist/index.d.ts",
+ "repository": "traceloop/openllmetry-js",
+ "scripts": {
+ "build": "rollup -c",
+ "lint": "eslint . --ext .ts",
+ "lint:fix": "eslint . --ext .ts --fix",
+ "test": "ts-mocha -p tsconfig.json 'test/**/*.test.ts'"
+ },
+ "keywords": [
+ "opentelemetry",
+ "nodejs",
+ "tracing",
+ "openai",
+ "anthropic"
+ ],
+ "author": "Traceloop",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=14"
+ },
+ "files": [
+ "dist/**/*.js",
+ "dist/**/*.js.map",
+ "dist/**/*.d.ts",
+ "doc",
+ "LICENSE",
+ "README.md",
+ "package.json"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "@opentelemetry/core": "^1.22.0",
+ "@opentelemetry/instrumentation": "^0.49.0",
+ "@opentelemetry/semantic-conventions": "^1.22.0",
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
+ },
+ "devDependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
+ "@pollyjs/adapter-node-http": "^6.0.6",
+ "@pollyjs/core": "^6.0.6",
+ "@pollyjs/persister-fs": "^6.0.6",
+ "@types/mocha": "^10.0.6",
+ "ts-mocha": "^10.0.0"
+ },
+ "homepage": "https://github.com/traceloop/openllmetry-js/tree/main/packages/instrumentation-anthropic"
+}
diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har
new file mode 100644
index 00000000..bf3d5d6c
--- /dev/null
+++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har
@@ -0,0 +1,166 @@
+{
+ "log": {
+ "_recordingName": "Test Anthropic instrumentation/should set attributes in span for completions (streaming)",
+ "creator": {
+ "comment": "persister:fs",
+ "name": "Polly.JS",
+ "version": "6.0.6"
+ },
+ "entries": [
+ {
+ "_id": "411df901c53641005b599f973e8b2068",
+ "_order": 0,
+ "cache": {},
+ "request": {
+ "bodySize": 149,
+ "cookies": [],
+ "headers": [
+ {
+ "_fromType": "array",
+ "name": "content-length",
+ "value": "149"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "user-agent",
+ "value": "Anthropic/JS 0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-lang",
+ "value": "js"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-package-version",
+ "value": "0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-os",
+ "value": "MacOS"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-arch",
+ "value": "arm64"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime",
+ "value": "node"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime-version",
+ "value": "v18.17.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "anthropic-version",
+ "value": "2023-06-01"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept-encoding",
+ "value": "gzip,deflate"
+ },
+ {
+ "name": "host",
+ "value": "api.anthropic.com"
+ }
+ ],
+ "headersSize": 548,
+ "httpVersion": "HTTP/1.1",
+ "method": "POST",
+ "postData": {
+ "mimeType": "application/json",
+ "params": [],
+ "text": "{\n \"model\": \"claude-2\",\n \"max_tokens_to_sample\": 300,\n \"prompt\": \"\\n\\nHuman: Tell me a joke about OpenTelemetry\\n\\nAssistant:\",\n \"stream\": true\n}"
+ },
+ "queryString": [],
+ "url": "https://api.anthropic.com/v1/complete"
+ },
+ "response": {
+ "bodySize": 6983,
+ "content": {
+ "mimeType": "text/event-stream; charset=utf-8",
+ "size": 6983,
+ "text": "event: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Here\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"'s\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: ping\r\ndata: {\"type\": \"ping\"}\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" a\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" silly\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" joke\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" about\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Open\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"Tele\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"metry\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\":\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"\\n\\nWhat\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" do\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" you\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" call\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" an\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Open\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"Tele\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"metry\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" collector\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" that\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" keeps\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" getting\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" distracted\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"?\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" A\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" span\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"-\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"t\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"ention\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" deficit\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" tracer\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"!\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"\",\"stop_reason\":\"stop_sequence\",\"model\":\"claude-2.1\",\"stop\":\"\\n\\nHuman:\",\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\n"
+ },
+ "cookies": [],
+ "headers": [
+ {
+ "name": "date",
+ "value": "Fri, 05 Apr 2024 11:20:12 GMT"
+ },
+ {
+ "name": "content-type",
+ "value": "text/event-stream; charset=utf-8"
+ },
+ {
+ "name": "transfer-encoding",
+ "value": "chunked"
+ },
+ {
+ "name": "connection",
+ "value": "keep-alive"
+ },
+ {
+ "name": "cache-control",
+ "value": "no-cache"
+ },
+ {
+ "name": "request-id",
+ "value": "req_01QgLb4tbuUR3myMtpiyaSZX"
+ },
+ {
+ "name": "via",
+ "value": "1.1 google"
+ },
+ {
+ "name": "cf-cache-status",
+ "value": "DYNAMIC"
+ },
+ {
+ "name": "server",
+ "value": "cloudflare"
+ },
+ {
+ "name": "cf-ray",
+ "value": "86f925c39fd7a268-FCO"
+ }
+ ],
+ "headersSize": 299,
+ "httpVersion": "HTTP/1.1",
+ "redirectURL": "",
+ "status": 200,
+ "statusText": "OK"
+ },
+ "startedDateTime": "2024-04-05T11:20:12.047Z",
+ "time": 2070,
+ "timings": {
+ "blocked": -1,
+ "connect": -1,
+ "dns": -1,
+ "receive": 0,
+ "send": 0,
+ "ssl": -1,
+ "wait": 2070
+ }
+ }
+ ],
+ "pages": [],
+ "version": "1.2"
+ }
+}
diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har
new file mode 100644
index 00000000..9a9ef085
--- /dev/null
+++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har
@@ -0,0 +1,171 @@
+{
+ "log": {
+ "_recordingName": "Test Anthropic instrumentation/should set attributes in span for completions",
+ "creator": {
+ "comment": "persister:fs",
+ "name": "Polly.JS",
+ "version": "6.0.6"
+ },
+ "entries": [
+ {
+ "_id": "3d54b7ae72fa4dc3272d8f7c5bcddf6d",
+ "_order": 0,
+ "cache": {},
+ "request": {
+ "bodySize": 131,
+ "cookies": [],
+ "headers": [
+ {
+ "_fromType": "array",
+ "name": "content-length",
+ "value": "131"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "user-agent",
+ "value": "Anthropic/JS 0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-lang",
+ "value": "js"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-package-version",
+ "value": "0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-os",
+ "value": "MacOS"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-arch",
+ "value": "arm64"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime",
+ "value": "node"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime-version",
+ "value": "v18.17.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "anthropic-version",
+ "value": "2023-06-01"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept-encoding",
+ "value": "gzip,deflate"
+ },
+ {
+ "name": "host",
+ "value": "api.anthropic.com"
+ }
+ ],
+ "headersSize": 548,
+ "httpVersion": "HTTP/1.1",
+ "method": "POST",
+ "postData": {
+ "mimeType": "application/json",
+ "params": [],
+ "text": "{\n \"model\": \"claude-2\",\n \"max_tokens_to_sample\": 300,\n \"prompt\": \"\\n\\nHuman: Tell me a joke about OpenTelemetry\\n\\nAssistant:\"\n}"
+ },
+ "queryString": [],
+ "url": "https://api.anthropic.com/v1/complete"
+ },
+ "response": {
+ "bodySize": 600,
+ "content": {
+ "encoding": "base64",
+ "mimeType": "application/json",
+ "size": 600,
+ "text": "[\"H4sIAAAAAAAAA4xSwWobMRD9lWddfNmY2s0h+BLS9hBDIJdAWjCYyWpqqdZqttIoW7X034s2DSQlh14EmuG9efPm/TJaRzZb08swBlYv0XTG2+fK4d366qOupw2fX1R7MX7m8/c3m3u2pnsJ2Rpcc+JlBiF41cBo3aKc4MogCfQgRXE7crzjwANrqtt93Md7VzFRhjp+3YUm6hklOhrHeokP3FPJDK9wZBEFeaSYF43kNXDiqFCZKa302qZHi0zedtibT3Opww7qfDxhB0ePDBXBQLGil6j8Q/Nib9DI7yb5R1l7fZ8xUTjBRxUQHiitcBsZmWp+ni7qOLWZX6TgFGXqMDESUwgVPmZNZWhi+ZFTbWqOoCQlWjhOvNibJ4dIYQVVCnoKARTfdEod6TLjKJHRJ/pZL3GFWFTr7NRs1A5ORp6pgj+xxVCRfVNDqjyMmkGKb3Li/NbFVrhhxcDzLvBfG9HSzlRtZcfUrK4YJDGUexclyLGeqeOB7VMSFqYzWWU8JKY8R2f+Zf5eOPZsOjOI5dACGKhYPtus1n8hZjsbcl0GilvTmSDHw/9E9fcfAAAA//8DAOxCDkfmAgAA\"]"
+ },
+ "cookies": [],
+ "headers": [
+ {
+ "name": "date",
+ "value": "Fri, 05 Apr 2024 11:20:12 GMT"
+ },
+ {
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "name": "transfer-encoding",
+ "value": "chunked"
+ },
+ {
+ "name": "connection",
+ "value": "keep-alive"
+ },
+ {
+ "name": "request-id",
+ "value": "req_01MF9Mk2Pm5K7idAdKGVuKtn"
+ },
+ {
+ "name": "x-cloud-trace-context",
+ "value": "bfd63b2c08c48c70d3ba04406af4864c"
+ },
+ {
+ "name": "via",
+ "value": "1.1 google"
+ },
+ {
+ "name": "cf-cache-status",
+ "value": "DYNAMIC"
+ },
+ {
+ "name": "server",
+ "value": "cloudflare"
+ },
+ {
+ "name": "cf-ray",
+ "value": "86f925a33e42a268-FCO"
+ },
+ {
+ "name": "content-encoding",
+ "value": "gzip"
+ }
+ ],
+ "headersSize": 339,
+ "httpVersion": "HTTP/1.1",
+ "redirectURL": "",
+ "status": 200,
+ "statusText": "OK"
+ },
+ "startedDateTime": "2024-04-05T11:20:06.759Z",
+ "time": 5267,
+ "timings": {
+ "blocked": -1,
+ "connect": -1,
+ "dns": -1,
+ "receive": 0,
+ "send": 0,
+ "ssl": -1,
+ "wait": 5267
+ }
+ }
+ ],
+ "pages": [],
+ "version": "1.2"
+ }
+}
diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har
new file mode 100644
index 00000000..90b95cab
--- /dev/null
+++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har
@@ -0,0 +1,171 @@
+{
+ "log": {
+ "_recordingName": "Test Anthropic instrumentation/should set attributes in span for messages (streaming)",
+ "creator": {
+ "comment": "persister:fs",
+ "name": "Polly.JS",
+ "version": "6.0.6"
+ },
+ "entries": [
+ {
+ "_id": "169f6f7c83e96867124983806f6d7be4",
+ "_order": 0,
+ "cache": {},
+ "request": {
+ "bodySize": 188,
+ "cookies": [],
+ "headers": [
+ {
+ "_fromType": "array",
+ "name": "content-length",
+ "value": "188"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "user-agent",
+ "value": "Anthropic/JS 0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-lang",
+ "value": "js"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-package-version",
+ "value": "0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-os",
+ "value": "MacOS"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-arch",
+ "value": "arm64"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime",
+ "value": "node"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime-version",
+ "value": "v18.17.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "anthropic-version",
+ "value": "2023-06-01"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-helper-method",
+ "value": "stream"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept-encoding",
+ "value": "gzip,deflate"
+ },
+ {
+ "name": "host",
+ "value": "api.anthropic.com"
+ }
+ ],
+ "headersSize": 583,
+ "httpVersion": "HTTP/1.1",
+ "method": "POST",
+ "postData": {
+ "mimeType": "application/json",
+ "params": [],
+ "text": "{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Tell me a joke about OpenTelemetry\"\n }\n ],\n \"model\": \"claude-3-opus-20240229\",\n \"stream\": true\n}"
+ },
+ "queryString": [],
+ "url": "https://api.anthropic.com/v1/messages"
+ },
+ "response": {
+ "bodySize": 19048,
+ "content": {
+ "mimeType": "text/event-stream; charset=utf-8",
+ "size": 19048,
+ "text": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_01B1V5rsrrCx1gdMW82NDgHk\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"claude-3-opus-20240229\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":17,\"output_tokens\":1}} }\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"} }\n\nevent: ping\ndata: {\"type\": \"ping\"}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Sure\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"!\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Here\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"'s\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" joke\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" about\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\":\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\n\\nWhy\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" did\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" developer\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" love\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" using\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"?\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\nBecause\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" it\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" made\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tr\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"acing\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" their\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" code\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"-\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"t\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"astic\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" experience\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"!\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\n\\nExplanation\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\":\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" is\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" set\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" of\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" APIs\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" SD\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"K\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"s\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tools\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" used\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" for\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" collecting\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" ex\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"porting\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tel\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" data\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" (\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"like\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" traces\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" metrics\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" logs\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\")\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" to\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" help\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" observe\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" monitor\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" distributed\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" systems\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" In\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" represents\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" single\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" operation\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" or\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" unit\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" of\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" work\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" within\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" trace\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" The\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" joke\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" plays\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" on\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" similarity\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" between\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" word\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"fantastic\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" impl\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ying\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" that\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" using\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" makes\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tr\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"acing\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" code\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" great\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" experience\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" for\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" developers\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0 }\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"usage\":{\"output_tokens\":151}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\" }\n\n"
+ },
+ "cookies": [],
+ "headers": [
+ {
+ "name": "date",
+ "value": "Fri, 05 Apr 2024 11:20:24 GMT"
+ },
+ {
+ "name": "content-type",
+ "value": "text/event-stream; charset=utf-8"
+ },
+ {
+ "name": "transfer-encoding",
+ "value": "chunked"
+ },
+ {
+ "name": "connection",
+ "value": "keep-alive"
+ },
+ {
+ "name": "cache-control",
+ "value": "no-cache"
+ },
+ {
+ "name": "request-id",
+ "value": "req_01MSkAn89zj7EbecovHP9E65"
+ },
+ {
+ "name": "via",
+ "value": "1.1 google"
+ },
+ {
+ "name": "cf-cache-status",
+ "value": "DYNAMIC"
+ },
+ {
+ "name": "server",
+ "value": "cloudflare"
+ },
+ {
+ "name": "cf-ray",
+ "value": "86f926063927a268-FCO"
+ }
+ ],
+ "headersSize": 299,
+ "httpVersion": "HTTP/1.1",
+ "redirectURL": "",
+ "status": 200,
+ "statusText": "OK"
+ },
+ "startedDateTime": "2024-04-05T11:20:22.711Z",
+ "time": 9590,
+ "timings": {
+ "blocked": -1,
+ "connect": -1,
+ "dns": -1,
+ "receive": 0,
+ "send": 0,
+ "ssl": -1,
+ "wait": 9590
+ }
+ }
+ ],
+ "pages": [],
+ "version": "1.2"
+ }
+}
diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har
new file mode 100644
index 00000000..a86aea9c
--- /dev/null
+++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har
@@ -0,0 +1,171 @@
+{
+ "log": {
+ "_recordingName": "Test Anthropic instrumentation/should set attributes in span for messages",
+ "creator": {
+ "comment": "persister:fs",
+ "name": "Polly.JS",
+ "version": "6.0.6"
+ },
+ "entries": [
+ {
+ "_id": "736e4bfd3852112815402bf773b26d6e",
+ "_order": 0,
+ "cache": {},
+ "request": {
+ "bodySize": 170,
+ "cookies": [],
+ "headers": [
+ {
+ "_fromType": "array",
+ "name": "content-length",
+ "value": "170"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "_fromType": "array",
+ "name": "user-agent",
+ "value": "Anthropic/JS 0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-lang",
+ "value": "js"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-package-version",
+ "value": "0.20.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-os",
+ "value": "MacOS"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-arch",
+ "value": "arm64"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime",
+ "value": "node"
+ },
+ {
+ "_fromType": "array",
+ "name": "x-stainless-runtime-version",
+ "value": "v18.17.1"
+ },
+ {
+ "_fromType": "array",
+ "name": "anthropic-version",
+ "value": "2023-06-01"
+ },
+ {
+ "_fromType": "array",
+ "name": "accept-encoding",
+ "value": "gzip,deflate"
+ },
+ {
+ "name": "host",
+ "value": "api.anthropic.com"
+ }
+ ],
+ "headersSize": 548,
+ "httpVersion": "HTTP/1.1",
+ "method": "POST",
+ "postData": {
+ "mimeType": "application/json",
+ "params": [],
+ "text": "{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Tell me a joke about OpenTelemetry\"\n }\n ],\n \"model\": \"claude-3-opus-20240229\"\n}"
+ },
+ "queryString": [],
+ "url": "https://api.anthropic.com/v1/messages"
+ },
+ "response": {
+ "bodySize": 736,
+ "content": {
+ "encoding": "base64",
+ "mimeType": "application/json",
+ "size": 736,
+ "text": "[\"H4sIAAAAAAAAA1RSX2vbMBD/Kle95MUpbdZR5pexQseS0Q220nUsI8jWJdYs37m6U10T+t2HnJWsT4a7+/2V98Y7U5pOdpuz8+un1erx56dvl6vP9/cPVzd0dacfr01hdOwxX6GI3aEpTOSQB1bEi1pSU5iaSZHUlL/2L/eKT3kzfUrzPUUsoMGIMwELf7hFsBUnha890i0G7FDjWK5pTR/A4SMG7jHCYEMr4EkZLFQ2giUHHB3GTOOip/YUbhvMO0VyGMFKKwWszQ9OwcHICYJvEZRB4wicIhAOr2XnlRV0IKModu9hqVBbAo22xkwQD4qwjdyBNggdd0g6cfchH3md+I8rrzMBwfiI7mRtcqps8pgrYh88Tj6/ZKClbHoJfcQtRujGQzbJtBVCosmMm+InclynLIPuFJbgmGYKgyXNuIplQrXEAzQ8QJfqBpazDqRHcp52wAQ21NxwAJdingwcW2g4RfnP7bHSYNOukUlc7Di5XsIuoUjuYBYRiBUiWjfCliNwlaPbygevI3g6lDglymqNrbwKjKincGPHCkHU1+1LhRzcfGul8UzoYLAj8PbwAhn8r5fspeE+T7JixlUoerI25vl3YTp2GExp6mCTw/mbOfdJ5ouzxcXZYvHOFEaU+01EK0ymNEhuoynSy0LwISHVaEpKIRQmTb9+uTee+qQb5RZJTHl+WRhO+mr09uL5+S8AAAD//wMACb+NKFkDAAA=\"]"
+ },
+ "cookies": [],
+ "headers": [
+ {
+ "name": "date",
+ "value": "Fri, 05 Apr 2024 11:20:22 GMT"
+ },
+ {
+ "name": "content-type",
+ "value": "application/json"
+ },
+ {
+ "name": "transfer-encoding",
+ "value": "chunked"
+ },
+ {
+ "name": "connection",
+ "value": "keep-alive"
+ },
+ {
+ "name": "request-id",
+ "value": "req_0182vaPgMhnXsMnBS73p6Yqd"
+ },
+ {
+ "name": "x-cloud-trace-context",
+ "value": "42ba21496f6152a6803a8a29a8855cd7"
+ },
+ {
+ "name": "via",
+ "value": "1.1 google"
+ },
+ {
+ "name": "cf-cache-status",
+ "value": "DYNAMIC"
+ },
+ {
+ "name": "server",
+ "value": "cloudflare"
+ },
+ {
+ "name": "cf-ray",
+ "value": "86f925d0bb53a268-FCO"
+ },
+ {
+ "name": "content-encoding",
+ "value": "gzip"
+ }
+ ],
+ "headersSize": 339,
+ "httpVersion": "HTTP/1.1",
+ "redirectURL": "",
+ "status": 200,
+ "statusText": "OK"
+ },
+ "startedDateTime": "2024-04-05T11:20:14.137Z",
+ "time": 8561,
+ "timings": {
+ "blocked": -1,
+ "connect": -1,
+ "dns": -1,
+ "receive": 0,
+ "send": 0,
+ "ssl": -1,
+ "wait": 8561
+ }
+ }
+ ],
+ "pages": [],
+ "version": "1.2"
+ }
+}
diff --git a/packages/instrumentation-anthropic/rollup.config.js b/packages/instrumentation-anthropic/rollup.config.js
new file mode 100644
index 00000000..691c0ca5
--- /dev/null
+++ b/packages/instrumentation-anthropic/rollup.config.js
@@ -0,0 +1,37 @@
+const dts = require("rollup-plugin-dts");
+const typescript = require("@rollup/plugin-typescript");
+const json = require("@rollup/plugin-json");
+
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const name = require("./package.json").main.replace(/\.js$/, "");
+
+const bundle = (config) => ({
+ ...config,
+ input: "src/index.ts",
+ external: (id) => !/^[./]/.test(id),
+});
+
+exports.default = [
+ bundle({
+ plugins: [typescript.default(), json.default()],
+ output: [
+ {
+ file: `${name}.js`,
+ format: "cjs",
+ sourcemap: true,
+ },
+ {
+ file: `${name}.mjs`,
+ format: "es",
+ sourcemap: true,
+ },
+ ],
+ }),
+ bundle({
+ plugins: [dts.default()],
+ output: {
+ file: `${name}.d.ts`,
+ format: "es",
+ },
+ }),
+];
diff --git a/packages/instrumentation-anthropic/src/index.ts b/packages/instrumentation-anthropic/src/index.ts
new file mode 100644
index 00000000..ec28d1d9
--- /dev/null
+++ b/packages/instrumentation-anthropic/src/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Traceloop
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from "./instrumentation";
+export * from "./types";
diff --git a/packages/instrumentation-anthropic/src/instrumentation.ts b/packages/instrumentation-anthropic/src/instrumentation.ts
new file mode 100644
index 00000000..00880d2d
--- /dev/null
+++ b/packages/instrumentation-anthropic/src/instrumentation.ts
@@ -0,0 +1,428 @@
+/*
+ * Copyright Traceloop
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {
+ context,
+ trace,
+ Span,
+ Attributes,
+ SpanKind,
+ SpanStatusCode,
+} from "@opentelemetry/api";
+import {
+ InstrumentationBase,
+ InstrumentationModuleDefinition,
+ InstrumentationNodeModuleDefinition,
+ safeExecuteInTheMiddle,
+} from "@opentelemetry/instrumentation";
+import {
+ CONTEXT_KEY_ALLOW_TRACE_CONTENT,
+ SpanAttributes,
+} from "@traceloop/ai-semantic-conventions";
+import { AnthropicInstrumentationConfig } from "./types";
+import { version } from "../package.json";
+import type * as anthropic from "@anthropic-ai/sdk";
+import type {
+ CompletionCreateParamsNonStreaming,
+ CompletionCreateParamsStreaming,
+ Completion,
+} from "@anthropic-ai/sdk/resources/completions";
+import type {
+ MessageCreateParamsNonStreaming,
+ MessageCreateParamsStreaming,
+ Message,
+ MessageStreamEvent,
+} from "@anthropic-ai/sdk/resources/messages";
+import type { Stream } from "@anthropic-ai/sdk/streaming";
+
+export class AnthropicInstrumentation extends InstrumentationBase {
+ protected declare _config: AnthropicInstrumentationConfig;
+
+ constructor(config: AnthropicInstrumentationConfig = {}) {
+ super("@traceloop/instrumentation-anthropic", version, config);
+ }
+
+ public override setConfig(config: AnthropicInstrumentationConfig = {}) {
+ super.setConfig(config);
+ }
+
+ public manuallyInstrument(module: typeof anthropic) {
+ this._diag.debug(`Patching @anthropic-ai/sdk manually`);
+
+ this._wrap(
+ module.Anthropic.Completions.prototype,
+ "create",
+ this.patchAnthropic("completion"),
+ );
+ this._wrap(
+ module.Anthropic.Messages.prototype,
+ "create",
+ this.patchAnthropic("chat"),
+ );
+ }
+
+ protected init(): InstrumentationModuleDefinition {
+ const module = new InstrumentationNodeModuleDefinition(
+ "@anthropic-ai/sdk",
+ [">=0.9.1"],
+ this.patch.bind(this),
+ this.unpatch.bind(this),
+ );
+ return module;
+ }
+
+ private patch(moduleExports: typeof anthropic, moduleVersion?: string) {
+ this._diag.debug(`Patching @anthropic-ai/sdk@${moduleVersion}`);
+
+ this._wrap(
+ moduleExports.Anthropic.Completions.prototype,
+ "create",
+ this.patchAnthropic("completion"),
+ );
+ this._wrap(
+ moduleExports.Anthropic.Messages.prototype,
+ "create",
+ this.patchAnthropic("chat"),
+ );
+ return moduleExports;
+ }
+
+ private unpatch(
+ moduleExports: typeof anthropic,
+ moduleVersion?: string,
+ ): void {
+ this._diag.debug(`Unpatching @azure/openai@${moduleVersion}`);
+
+ this._unwrap(moduleExports.Anthropic.Completions.prototype, "create");
+ this._unwrap(moduleExports.Anthropic.Messages.prototype, "create");
+ }
+
+ private patchAnthropic(type: "chat" | "completion") {
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
+ const plugin = this;
+ // eslint-disable-next-line @typescript-eslint/ban-types
+ return (original: Function) => {
+ return function method(this: any, ...args: unknown[]) {
+ const span =
+ type === "chat"
+ ? plugin.startSpan({
+ type,
+ params: args[0] as MessageCreateParamsNonStreaming & {
+ extraAttributes?: Record;
+ },
+ })
+ : plugin.startSpan({
+ type,
+ params: args[0] as CompletionCreateParamsNonStreaming & {
+ extraAttributes?: Record;
+ },
+ });
+
+ const execContext = trace.setSpan(context.active(), span);
+ const execPromise = safeExecuteInTheMiddle(
+ () => {
+ return context.with(execContext, () => {
+ if ((args?.[0] as any)?.extraAttributes) {
+ delete (args[0] as any).extraAttributes;
+ }
+ return original.apply(this, args);
+ });
+ },
+ (e) => {
+ if (e) {
+ plugin._diag.error("Error in Anthropic instrumentation", e);
+ }
+ },
+ );
+
+ if (
+ (
+ args[0] as
+ | MessageCreateParamsStreaming
+ | CompletionCreateParamsStreaming
+ ).stream &&
+ type === "completion" // For some reason, this causes an exception with chat, so disabled for now
+ ) {
+ return context.bind(
+ execContext,
+ plugin._streamingWrapPromise({
+ span,
+ type,
+ promise: execPromise,
+ }),
+ );
+ }
+
+ const wrappedPromise = plugin._wrapPromise(type, span, execPromise);
+
+ return context.bind(execContext, wrappedPromise as any);
+ };
+ };
+ }
+
+ private startSpan({
+ type,
+ params,
+ }:
+ | {
+ type: "chat";
+ params: MessageCreateParamsNonStreaming & {
+ extraAttributes?: Record;
+ };
+ }
+ | {
+ type: "completion";
+ params: CompletionCreateParamsNonStreaming & {
+ extraAttributes?: Record;
+ };
+ }): Span {
+ const attributes: Attributes = {
+ [SpanAttributes.LLM_VENDOR]: "Anthropic",
+ [SpanAttributes.LLM_REQUEST_TYPE]: type,
+ };
+
+ attributes[SpanAttributes.LLM_REQUEST_MODEL] = params.model;
+ attributes[SpanAttributes.LLM_TEMPERATURE] = params.temperature;
+ attributes[SpanAttributes.LLM_TOP_P] = params.top_p;
+ attributes[SpanAttributes.LLM_TOP_K] = params.top_k;
+
+ if (type === "completion") {
+ attributes[SpanAttributes.LLM_REQUEST_MAX_TOKENS] =
+ params.max_tokens_to_sample;
+ } else {
+ attributes[SpanAttributes.LLM_REQUEST_MAX_TOKENS] = params.max_tokens;
+ }
+
+ if (
+ params.extraAttributes !== undefined &&
+ typeof params.extraAttributes === "object"
+ ) {
+ Object.keys(params.extraAttributes).forEach((key: string) => {
+ attributes[key] = params.extraAttributes![key];
+ });
+ }
+
+ if (this._shouldSendPrompts()) {
+ if (type === "chat") {
+ params.messages.forEach((message, index) => {
+ attributes[`${SpanAttributes.LLM_PROMPTS}.${index}.role`] =
+ message.role;
+ if (typeof message.content === "string") {
+ attributes[`${SpanAttributes.LLM_PROMPTS}.${index}.content`] =
+ (message.content as string) || "";
+ } else {
+ attributes[`${SpanAttributes.LLM_PROMPTS}.${index}.content`] =
+ JSON.stringify(message.content);
+ }
+ });
+ } else {
+ attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`] = "user";
+ attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`] = params.prompt;
+ }
+ }
+
+ return this.tracer.startSpan(`anthropic.${type}`, {
+ kind: SpanKind.CLIENT,
+ attributes,
+ });
+ }
+
+ private async *_streamingWrapPromise({
+ span,
+ type,
+ promise,
+ }:
+ | {
+ span: Span;
+ type: "chat";
+ promise: Promise>;
+ }
+ | {
+ span: Span;
+ type: "completion";
+ promise: Promise>;
+ }) {
+ if (type === "chat") {
+ const result: Message = {
+ id: "0",
+ type: "message",
+ model: "",
+ role: "assistant",
+ stop_reason: null,
+ stop_sequence: null,
+ usage: { input_tokens: 0, output_tokens: 0 },
+ content: [],
+ };
+ for await (const chunk of await promise) {
+ yield chunk;
+
+ switch (chunk.type) {
+ case "content_block_start":
+ if (result.content.length <= chunk.index) {
+ result.content.push(chunk.content_block);
+ }
+ break;
+
+ case "content_block_delta":
+ if (chunk.index < result.content.length) {
+ result.content[chunk.index] = {
+ type: "text",
+ text: result.content[chunk.index].text + chunk.delta.text,
+ };
+ }
+ }
+ }
+
+ this._endSpan({ span, type, result });
+ } else {
+ const result: Completion = {
+ id: "0",
+ type: "completion",
+ model: "",
+ completion: "",
+ stop_reason: null,
+ };
+ for await (const chunk of await promise) {
+ yield chunk;
+
+ result.id = chunk.id;
+ result.model = chunk.model;
+
+ if (chunk.stop_reason) {
+ result.stop_reason = chunk.stop_reason;
+ }
+ if (chunk.model) {
+ result.model = chunk.model;
+ }
+ if (chunk.completion) {
+ result.completion += chunk.completion;
+ }
+ }
+
+ this._endSpan({ span, type, result });
+ }
+ }
+
+ private _wrapPromise(
+ type: "chat" | "completion",
+ span: Span,
+ promise: Promise,
+ ): Promise {
+ return promise
+ .then((result) => {
+ return new Promise((resolve) => {
+ if (type === "chat") {
+ this._endSpan({
+ type,
+ span,
+ result: result as Message,
+ });
+ } else {
+ this._endSpan({
+ type,
+ span,
+ result: result as Completion,
+ });
+ }
+
+ resolve(result);
+ });
+ })
+ .catch((error: Error) => {
+ return new Promise((_, reject) => {
+ span.setStatus({
+ code: SpanStatusCode.ERROR,
+ message: error.message,
+ });
+ span.recordException(error);
+ span.end();
+
+ reject(error);
+ });
+ });
+ }
+
+ private _endSpan({
+ span,
+ type,
+ result,
+ }:
+ | { span: Span; type: "chat"; result: Message }
+ | {
+ span: Span;
+ type: "completion";
+ result: Completion;
+ }) {
+ span.setAttribute(SpanAttributes.LLM_RESPONSE_MODEL, result.model);
+ if (type === "chat" && result.usage) {
+ span.setAttribute(
+ SpanAttributes.LLM_USAGE_TOTAL_TOKENS,
+ result.usage?.input_tokens + result.usage?.output_tokens,
+ );
+ span.setAttribute(
+ SpanAttributes.LLM_USAGE_COMPLETION_TOKENS,
+ result.usage?.output_tokens,
+ );
+ span.setAttribute(
+ SpanAttributes.LLM_USAGE_PROMPT_TOKENS,
+ result.usage?.input_tokens,
+ );
+ }
+
+ result.stop_reason &&
+ span.setAttribute(
+ `${SpanAttributes.LLM_COMPLETIONS}.0.finish_reason`,
+ result.stop_reason,
+ );
+
+ if (this._shouldSendPrompts()) {
+ if (type === "chat") {
+ span.setAttribute(
+ `${SpanAttributes.LLM_COMPLETIONS}.0.role`,
+ "assistant",
+ );
+ span.setAttribute(
+ `${SpanAttributes.LLM_COMPLETIONS}.0.content`,
+ JSON.stringify(result.content),
+ );
+ } else {
+ span.setAttribute(
+ `${SpanAttributes.LLM_COMPLETIONS}.0.role`,
+ "assistant",
+ );
+ span.setAttribute(
+ `${SpanAttributes.LLM_COMPLETIONS}.0.content`,
+ result.completion,
+ );
+ }
+ }
+
+ span.end();
+ }
+
+ private _shouldSendPrompts() {
+ const contextShouldSendPrompts = context
+ .active()
+ .getValue(CONTEXT_KEY_ALLOW_TRACE_CONTENT);
+
+ if (contextShouldSendPrompts !== undefined) {
+ return contextShouldSendPrompts;
+ }
+
+ return this._config.traceContent !== undefined
+ ? this._config.traceContent
+ : true;
+ }
+}
diff --git a/packages/instrumentation-anthropic/src/types.ts b/packages/instrumentation-anthropic/src/types.ts
new file mode 100644
index 00000000..2fbf4036
--- /dev/null
+++ b/packages/instrumentation-anthropic/src/types.ts
@@ -0,0 +1,9 @@
+import { InstrumentationConfig } from "@opentelemetry/instrumentation";
+
+export interface AnthropicInstrumentationConfig extends InstrumentationConfig {
+ /**
+ * Whether to log prompts, completions and embeddings on traces.
+ * @default true
+ */
+ traceContent?: boolean;
+}
diff --git a/packages/instrumentation-anthropic/test/instrumentation.test.ts b/packages/instrumentation-anthropic/test/instrumentation.test.ts
new file mode 100644
index 00000000..04caec91
--- /dev/null
+++ b/packages/instrumentation-anthropic/test/instrumentation.test.ts
@@ -0,0 +1,292 @@
+/*
+ * Copyright Traceloop
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as assert from "assert";
+
+import { context } from "@opentelemetry/api";
+import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
+import {
+ BasicTracerProvider,
+ InMemorySpanExporter,
+ SimpleSpanProcessor,
+} from "@opentelemetry/sdk-trace-base";
+
+import * as AnthropicModule from "@anthropic-ai/sdk";
+
+import { AnthropicInstrumentation } from "../src/instrumentation";
+
+import { Polly, setupMocha as setupPolly } from "@pollyjs/core";
+import NodeHttpAdapter from "@pollyjs/adapter-node-http";
+import FSPersister from "@pollyjs/persister-fs";
+import { SpanAttributes } from "@traceloop/ai-semantic-conventions";
+
+const memoryExporter = new InMemorySpanExporter();
+
+Polly.register(NodeHttpAdapter);
+Polly.register(FSPersister);
+
+describe("Test Anthropic instrumentation", async function () {
+ const provider = new BasicTracerProvider();
+ let instrumentation: AnthropicInstrumentation;
+ let contextManager: AsyncHooksContextManager;
+ let anthropic: AnthropicModule.Anthropic;
+
+ setupPolly({
+ adapters: ["node-http"],
+ persister: "fs",
+ recordIfMissing: process.env.RECORD_MODE === "NEW",
+ matchRequestsBy: {
+ headers: false,
+ },
+ });
+
+ before(async () => {
+ if (process.env.RECORD_MODE !== "NEW") {
+ process.env.ANTHROPIC_API_KEY = "test-key";
+ }
+ provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
+ instrumentation = new AnthropicInstrumentation();
+ instrumentation.setTracerProvider(provider);
+
+ const anthropicModule: typeof AnthropicModule = await import(
+ "@anthropic-ai/sdk"
+ );
+ anthropic = new anthropicModule.Anthropic();
+ });
+
+ beforeEach(function () {
+ contextManager = new AsyncHooksContextManager().enable();
+ context.setGlobalContextManager(contextManager);
+
+ const { server } = this.polly as Polly;
+ server.any().on("beforePersist", (_req, recording) => {
+ recording.request.headers = recording.request.headers.filter(
+ ({ name }: { name: string }) => name !== "x-api-key",
+ );
+ });
+ });
+
+ afterEach(async () => {
+ memoryExporter.reset();
+ context.disable();
+ });
+
+ it("should set attributes in span for completions", async () => {
+ const result = await anthropic.completions.create({
+ model: "claude-2",
+ max_tokens_to_sample: 300,
+ prompt: `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`,
+ });
+
+ const spans = memoryExporter.getFinishedSpans();
+ const completionSpan = spans.find(
+ (span) => span.name === "anthropic.completion",
+ );
+
+ assert.ok(result);
+ assert.ok(completionSpan);
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`],
+ "claude-2",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`],
+ 300,
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`],
+ "claude-2.1",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`],
+ "user",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`],
+ `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`,
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`],
+ "assistant",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`],
+ result.completion,
+ );
+ }).timeout(30000);
+
+ it("should set attributes in span for completions (streaming)", async () => {
+ const result = await anthropic.completions.create({
+ model: "claude-2",
+ max_tokens_to_sample: 300,
+ prompt: `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`,
+ stream: true,
+ });
+
+ let completion = "";
+ for await (const chunk of result) {
+ assert.ok(chunk);
+ completion += chunk.completion;
+ }
+
+ const spans = memoryExporter.getFinishedSpans();
+ const completionSpan = spans.find(
+ (span) => span.name === "anthropic.completion",
+ );
+
+ assert.ok(completionSpan);
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`],
+ "claude-2",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`],
+ 300,
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`],
+ "claude-2.1",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`],
+ "user",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`],
+ `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`,
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`],
+ "assistant",
+ );
+ assert.strictEqual(
+ completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`],
+ completion,
+ );
+ }).timeout(30000);
+
+ it("should set attributes in span for messages", async () => {
+ const message = await anthropic.messages.create({
+ max_tokens: 1024,
+ messages: [
+ { role: "user", content: "Tell me a joke about OpenTelemetry" },
+ ],
+ model: "claude-3-opus-20240229",
+ });
+
+ const spans = memoryExporter.getFinishedSpans();
+ const chatSpan = spans.find((span) => span.name === "anthropic.chat");
+
+ assert.ok(message);
+ assert.ok(chatSpan);
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`],
+ "claude-3-opus-20240229",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`],
+ "claude-3-opus-20240229",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`],
+ 1024,
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`],
+ "user",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`],
+ `Tell me a joke about OpenTelemetry`,
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`],
+ "assistant",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`],
+ JSON.stringify(message.content),
+ );
+ assert.equal(
+ chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`],
+ 17,
+ );
+ assert.equal(
+ +chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`]! +
+ +chatSpan.attributes[`${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`]!,
+ chatSpan.attributes[`${SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`],
+ );
+ }).timeout(30000);
+
+ it.skip(
+ "should set attributes in span for messages (streaming)",
+ async () => {
+ const stream = anthropic.messages.stream({
+ max_tokens: 1024,
+ messages: [
+ { role: "user", content: "Tell me a joke about OpenTelemetry" },
+ ],
+ model: "claude-3-opus-20240229",
+ });
+ const message = await stream.finalMessage();
+
+ const spans = memoryExporter.getFinishedSpans();
+ const chatSpan = spans.find((span) => span.name === "anthropic.chat");
+
+ assert.ok(message);
+ assert.ok(chatSpan);
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`],
+ "claude-3-opus-20240229",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`],
+ "claude-3-opus-20240229",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`],
+ 1024,
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`],
+ "user",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`],
+ `Tell me a joke about OpenTelemetry`,
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`],
+ "assistant",
+ );
+ assert.strictEqual(
+ chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`],
+ JSON.stringify(message.content),
+ );
+ assert.equal(
+ chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`],
+ 17,
+ );
+ assert.equal(
+ +chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`]! +
+ +chatSpan.attributes[
+ `${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`
+ ]!,
+ chatSpan.attributes[`${SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`],
+ );
+ },
+ ).timeout(30000);
+});
diff --git a/packages/instrumentation-anthropic/tsconfig.json b/packages/instrumentation-anthropic/tsconfig.json
new file mode 100644
index 00000000..559aaa89
--- /dev/null
+++ b/packages/instrumentation-anthropic/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "."
+ },
+ "files": [],
+ "include": ["src/**/*.ts", "test/**/*.ts", "package.json"],
+ "references": []
+}
diff --git a/packages/instrumentation-azure/CHANGELOG.md b/packages/instrumentation-azure/CHANGELOG.md
index 7e311ec4..c5a3e194 100644
--- a/packages/instrumentation-azure/CHANGELOG.md
+++ b/packages/instrumentation-azure/CHANGELOG.md
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+### Features
+
+- **anthropic:** instrumentation ([#188](https://github.com/traceloop/openllmetry-js/issues/188)) ([f40df74](https://github.com/traceloop/openllmetry-js/commit/f40df747143279a9a153db58020bf4531b5c171f))
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
### Bug Fixes
diff --git a/packages/instrumentation-azure/README.md b/packages/instrumentation-azure/README.md
index 1c0b22a6..7d26695e 100644
--- a/packages/instrumentation-azure/README.md
+++ b/packages/instrumentation-azure/README.md
@@ -49,5 +49,5 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[slack-url]: https://traceloop.com/slack
[license-url]: https://github.com/traceloop/openllmetry-js/blob/main/LICENSE
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
-[npm-url]: https://www.npmjs.com/package/@traceloop/instrumentation-openai
-[npm-img]: https://badge.fury.io/js/%40traceloop%2Finstrumentation-openai.svg
+[npm-url]: https://www.npmjs.com/package/@traceloop/instrumentation-azure
+[npm-img]: https://badge.fury.io/js/%40traceloop%2Finstrumentation-azure.svg
diff --git a/packages/instrumentation-azure/package.json b/packages/instrumentation-azure/package.json
index 4bbcd66c..e7cdb719 100644
--- a/packages/instrumentation-azure/package.json
+++ b/packages/instrumentation-azure/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-azure",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Azure OpenAI Instrumentaion",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -40,7 +40,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@azure/openai": "^1.0.0-beta.10",
diff --git a/packages/instrumentation-bedrock/CHANGELOG.md b/packages/instrumentation-bedrock/CHANGELOG.md
index 30a7bdf6..4e824a33 100644
--- a/packages/instrumentation-bedrock/CHANGELOG.md
+++ b/packages/instrumentation-bedrock/CHANGELOG.md
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+### Features
+
+- **anthropic:** instrumentation ([#188](https://github.com/traceloop/openllmetry-js/issues/188)) ([f40df74](https://github.com/traceloop/openllmetry-js/commit/f40df747143279a9a153db58020bf4531b5c171f))
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-bedrock
diff --git a/packages/instrumentation-bedrock/README.md b/packages/instrumentation-bedrock/README.md
index fd153d27..d3370a66 100644
--- a/packages/instrumentation-bedrock/README.md
+++ b/packages/instrumentation-bedrock/README.md
@@ -1,4 +1,4 @@
-# OpenTelemetry VertexAI instrumentation for Node.js
+# OpenTelemetry Bedrock instrumentation for Node.js
[![NPM Published Version][npm-img]][npm-url]
[![Apache License][license-image]][license-image]
diff --git a/packages/instrumentation-bedrock/package.json b/packages/instrumentation-bedrock/package.json
index 1da127d4..dda343c2 100644
--- a/packages/instrumentation-bedrock/package.json
+++ b/packages/instrumentation-bedrock/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-bedrock",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Amazon Bedrock Instrumentation",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -40,7 +40,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
diff --git a/packages/instrumentation-cohere/CHANGELOG.md b/packages/instrumentation-cohere/CHANGELOG.md
index 5bdf9fb1..b8c5d8ff 100644
--- a/packages/instrumentation-cohere/CHANGELOG.md
+++ b/packages/instrumentation-cohere/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-cohere
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-cohere
diff --git a/packages/instrumentation-cohere/package.json b/packages/instrumentation-cohere/package.json
index 2bcf9cb3..2ef4c2b9 100644
--- a/packages/instrumentation-cohere/package.json
+++ b/packages/instrumentation-cohere/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-cohere",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Cohere Instrumentation",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -40,7 +40,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.44.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@pollyjs/adapter-node-http": "^6.0.6",
diff --git a/packages/instrumentation-langchain/CHANGELOG.md b/packages/instrumentation-langchain/CHANGELOG.md
index ad4f7dd5..ad087caf 100644
--- a/packages/instrumentation-langchain/CHANGELOG.md
+++ b/packages/instrumentation-langchain/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-langchain
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-langchain
diff --git a/packages/instrumentation-langchain/package.json b/packages/instrumentation-langchain/package.json
index 3f55d6c5..7aa7568b 100644
--- a/packages/instrumentation-langchain/package.json
+++ b/packages/instrumentation-langchain/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-langchain",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "OpenTelemetry instrumentation for LangchainJS",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -40,7 +40,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@langchain/community": "^0.0.34",
diff --git a/packages/instrumentation-llamaindex/CHANGELOG.md b/packages/instrumentation-llamaindex/CHANGELOG.md
index ee42bced..54f89534 100644
--- a/packages/instrumentation-llamaindex/CHANGELOG.md
+++ b/packages/instrumentation-llamaindex/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-llamaindex
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-llamaindex
diff --git a/packages/instrumentation-llamaindex/package.json b/packages/instrumentation-llamaindex/package.json
index 7f6989ce..876bdb89 100644
--- a/packages/instrumentation-llamaindex/package.json
+++ b/packages/instrumentation-llamaindex/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-llamaindex",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Llamaindex Instrumentation",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -39,7 +39,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
"lodash": "^4.17.21"
},
"devDependencies": {
diff --git a/packages/instrumentation-openai/CHANGELOG.md b/packages/instrumentation-openai/CHANGELOG.md
index 0801fa15..cb191dde 100644
--- a/packages/instrumentation-openai/CHANGELOG.md
+++ b/packages/instrumentation-openai/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-openai
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
### Bug Fixes
diff --git a/packages/instrumentation-openai/package.json b/packages/instrumentation-openai/package.json
index e814e13d..9881bb66 100644
--- a/packages/instrumentation-openai/package.json
+++ b/packages/instrumentation-openai/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-openai",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "OpenAI Instrumentaion",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -39,7 +39,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
"tiktoken": "^1.0.13"
},
"devDependencies": {
diff --git a/packages/instrumentation-pinecone/CHANGELOG.md b/packages/instrumentation-pinecone/CHANGELOG.md
index 49e8ab2d..6740aa05 100644
--- a/packages/instrumentation-pinecone/CHANGELOG.md
+++ b/packages/instrumentation-pinecone/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-pinecone
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-pinecone
diff --git a/packages/instrumentation-pinecone/package.json b/packages/instrumentation-pinecone/package.json
index 1557623b..692c79bc 100644
--- a/packages/instrumentation-pinecone/package.json
+++ b/packages/instrumentation-pinecone/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-pinecone",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "OpenTelemetry instrumentation for pinecone vector DB",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -40,7 +40,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@pinecone-database/pinecone": "^2.0.1",
diff --git a/packages/instrumentation-vertexai/CHANGELOG.md b/packages/instrumentation-vertexai/CHANGELOG.md
index 0af2fbd1..0ddd1be8 100644
--- a/packages/instrumentation-vertexai/CHANGELOG.md
+++ b/packages/instrumentation-vertexai/CHANGELOG.md
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+**Note:** Version bump only for package @traceloop/instrumentation-vertexai
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
**Note:** Version bump only for package @traceloop/instrumentation-vertexai
diff --git a/packages/instrumentation-vertexai/package.json b/packages/instrumentation-vertexai/package.json
index 516d0875..6a5aad7a 100644
--- a/packages/instrumentation-vertexai/package.json
+++ b/packages/instrumentation-vertexai/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/instrumentation-vertexai",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Google's VertexAI Instrumentation",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -39,7 +39,7 @@
"@opentelemetry/core": "^1.22.0",
"@opentelemetry/instrumentation": "^0.49.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
- "@traceloop/ai-semantic-conventions": "^0.5.29"
+ "@traceloop/ai-semantic-conventions": "^0.6.0"
},
"devDependencies": {
"@google-cloud/aiplatform": "^3.10.0",
diff --git a/packages/sample-app/package.json b/packages/sample-app/package.json
index a9bdadcf..71e004b2 100644
--- a/packages/sample-app/package.json
+++ b/packages/sample-app/package.json
@@ -4,6 +4,7 @@
"description": "Sample app for using Traceloop SDK",
"scripts": {
"build": "tsc --build tsconfig.json",
+ "run:anthropic": "npm run build && node dist/src/sample_anthropic.js",
"run:cohere": "npm run build && node dist/src/sample_cohere.js",
"run:bedrock:ai21": "npm run build && node dist/src/bedrock/ai21.js",
"run:bedrock:amazon": "npm run build && node dist/src/bedrock/amazon.js",
@@ -30,6 +31,7 @@
"node": ">=14"
},
"dependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
"@azure/openai": "^1.0.0-beta.11",
"@google-cloud/aiplatform": "^3.10.0",
diff --git a/packages/sample-app/src/sample_anthropic.ts b/packages/sample-app/src/sample_anthropic.ts
new file mode 100644
index 00000000..24581855
--- /dev/null
+++ b/packages/sample-app/src/sample_anthropic.ts
@@ -0,0 +1,25 @@
+import * as traceloop from "@traceloop/node-server-sdk";
+import Anthropic from "@anthropic-ai/sdk";
+
+traceloop.initialize({
+ appName: "sample_anthropic",
+ apiKey: process.env.TRACELOOP_API_KEY,
+ disableBatch: true,
+});
+const anthropic = new Anthropic({});
+
+async function main() {
+ const completion = await anthropic.messages.create({
+ max_tokens: 1024,
+ model: "claude-3-opus-20240229",
+ messages: [
+ {
+ role: "user",
+ content: "How does a court case get to the Supreme Court?",
+ },
+ ],
+ });
+ console.log(completion.content);
+}
+
+main();
diff --git a/packages/traceloop-sdk/CHANGELOG.md b/packages/traceloop-sdk/CHANGELOG.md
index 4d981738..e43ebb25 100644
--- a/packages/traceloop-sdk/CHANGELOG.md
+++ b/packages/traceloop-sdk/CHANGELOG.md
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [0.6.0](https://github.com/traceloop/openllmetry-js/compare/v0.5.29...v0.6.0) (2024-04-05)
+
+### Features
+
+- **anthropic:** instrumentation ([#188](https://github.com/traceloop/openllmetry-js/issues/188)) ([f40df74](https://github.com/traceloop/openllmetry-js/commit/f40df747143279a9a153db58020bf4531b5c171f))
+
## [0.5.29](https://github.com/traceloop/openllmetry-js/compare/v0.5.28...v0.5.29) (2024-04-03)
### Bug Fixes
diff --git a/packages/traceloop-sdk/README b/packages/traceloop-sdk/README
new file mode 100644
index 00000000..0cba606c
--- /dev/null
+++ b/packages/traceloop-sdk/README
@@ -0,0 +1,43 @@
+# OpenLLMetry SDK for Node.js
+
+[![NPM Published Version][npm-img]][npm-url]
+[![Apache License][license-image]][license-image]
+
+OpenLLMetry-JS is a set of extensions built on top of [OpenTelemetry](https://opentelemetry.io/) that gives you complete observability over your LLM application. Because it uses OpenTelemetry under the hood, it can be connected to your existing observability solutions - Datadog, Honeycomb, and others.
+
+## 🚀 Getting Started
+
+The easiest way to get started is to use our SDK.
+For a complete guide, go to our [docs](https://traceloop.com/docs/openllmetry/getting-started-ts).
+
+Install the SDK:
+
+```shell
+npm install --save @traceloop/node-server-sdk
+```
+
+Then, to start instrumenting your code, just add these 2 lines to your code:
+
+```js
+import * as traceloop from "@traceloop/node-server-sdk";
+
+traceloop.initialize();
+```
+
+Make sure to `import` the SDK before importing any LLM module.
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us on [Slack][slack-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[slack-url]: https://traceloop.com/slack
+[license-url]: https://github.com/traceloop/openllmetry-js/blob/main/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[npm-url]: https://www.npmjs.com/package/@traceloop/node-server-sdk
+[npm-img]: https://badge.fury.io/js/%40traceloop%2Fnode-server-sdk.svg
diff --git a/packages/traceloop-sdk/package.json b/packages/traceloop-sdk/package.json
index ef3c6536..4dba8530 100644
--- a/packages/traceloop-sdk/package.json
+++ b/packages/traceloop-sdk/package.json
@@ -1,6 +1,6 @@
{
"name": "@traceloop/node-server-sdk",
- "version": "0.5.29",
+ "version": "0.6.0",
"description": "Traceloop Software Development Kit (SDK) for Node.js",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -37,15 +37,16 @@
"dependencies": {
"@opentelemetry/exporter-trace-otlp-proto": "^0.49.1",
"@opentelemetry/sdk-node": "^0.49.1",
- "@traceloop/ai-semantic-conventions": "^0.5.29",
- "@traceloop/instrumentation-azure": "^0.5.29",
- "@traceloop/instrumentation-bedrock": "^0.5.29",
- "@traceloop/instrumentation-cohere": "^0.5.29",
- "@traceloop/instrumentation-langchain": "^0.5.29",
- "@traceloop/instrumentation-llamaindex": "^0.5.29",
- "@traceloop/instrumentation-openai": "^0.5.29",
- "@traceloop/instrumentation-pinecone": "^0.5.29",
- "@traceloop/instrumentation-vertexai": "^0.5.29",
+ "@traceloop/ai-semantic-conventions": "^0.6.0",
+ "@traceloop/instrumentation-anthropic": "^0.6.0",
+ "@traceloop/instrumentation-azure": "^0.6.0",
+ "@traceloop/instrumentation-bedrock": "^0.6.0",
+ "@traceloop/instrumentation-cohere": "^0.6.0",
+ "@traceloop/instrumentation-langchain": "^0.6.0",
+ "@traceloop/instrumentation-llamaindex": "^0.6.0",
+ "@traceloop/instrumentation-openai": "^0.6.0",
+ "@traceloop/instrumentation-pinecone": "^0.6.0",
+ "@traceloop/instrumentation-vertexai": "^0.6.0",
"@types/nunjucks": "^3.2.5",
"cross-fetch": "^4.0.0",
"fetch-retry": "^5.0.6",
@@ -57,6 +58,7 @@
"homepage": "https://github.com/traceloop/openllmetry-js/tree/main/packages/traceloop-sdk",
"gitHead": "ef1e70d6037f7b5c061056ef2be16e3f55f02ed5",
"devDependencies": {
+ "@anthropic-ai/sdk": "^0.20.1",
"@aws-sdk/client-bedrock-runtime": "^3.499.0",
"@azure/openai": "^1.0.0-beta.11",
"@google-cloud/aiplatform": "^3.10.0",
diff --git a/packages/traceloop-sdk/src/lib/interfaces/initialize-options.interface.ts b/packages/traceloop-sdk/src/lib/interfaces/initialize-options.interface.ts
index f4a0cb77..f0e8ebff 100644
--- a/packages/traceloop-sdk/src/lib/interfaces/initialize-options.interface.ts
+++ b/packages/traceloop-sdk/src/lib/interfaces/initialize-options.interface.ts
@@ -1,6 +1,7 @@
import { SpanExporter } from "@opentelemetry/sdk-trace-base";
import type * as openai from "openai";
+import type * as anthropic from "@anthropic-ai/sdk";
import type * as azure from "@azure/openai";
import type * as cohere from "cohere-ai";
import type * as bedrock from "@aws-sdk/client-bedrock-runtime";
@@ -70,6 +71,7 @@ export interface InitializeOptions {
*/
instrumentModules?: {
openAI?: typeof openai.OpenAI;
+ anthropic?: typeof anthropic;
azureOpenAI?: typeof azure;
cohere?: typeof cohere;
bedrock?: typeof bedrock;
diff --git a/packages/traceloop-sdk/src/lib/tracing/index.ts b/packages/traceloop-sdk/src/lib/tracing/index.ts
index 88440f16..b9b9cef4 100644
--- a/packages/traceloop-sdk/src/lib/tracing/index.ts
+++ b/packages/traceloop-sdk/src/lib/tracing/index.ts
@@ -17,6 +17,7 @@ import {
CONTEXT_KEY_ALLOW_TRACE_CONTENT,
SpanAttributes,
} from "@traceloop/ai-semantic-conventions";
+import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
import { AzureOpenAIInstrumentation } from "@traceloop/instrumentation-azure";
import { LlamaIndexInstrumentation } from "@traceloop/instrumentation-llamaindex";
@@ -32,6 +33,7 @@ import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
let _sdk: NodeSDK;
let _spanProcessor: SimpleSpanProcessor | BatchSpanProcessor;
let openAIInstrumentation: OpenAIInstrumentation | undefined;
+let anthropicInstrumentation: AnthropicInstrumentation | undefined;
let azureOpenAIInstrumentation: AzureOpenAIInstrumentation | undefined;
let cohereInstrumentation: CohereInstrumentation | undefined;
let vertexaiInstrumentation: VertexAIInstrumentation | undefined;
@@ -47,6 +49,9 @@ export const initInstrumentations = () => {
openAIInstrumentation = new OpenAIInstrumentation();
instrumentations.push(openAIInstrumentation);
+ anthropicInstrumentation = new AnthropicInstrumentation();
+ instrumentations.push(anthropicInstrumentation);
+
azureOpenAIInstrumentation = new AzureOpenAIInstrumentation();
instrumentations.push(azureOpenAIInstrumentation);
@@ -83,6 +88,12 @@ export const manuallyInitInstrumentations = (
openAIInstrumentation.manuallyInstrument(instrumentModules.openAI);
}
+ if (instrumentModules?.anthropic) {
+ anthropicInstrumentation = new AnthropicInstrumentation();
+ instrumentations.push(anthropicInstrumentation);
+ anthropicInstrumentation.manuallyInstrument(instrumentModules.anthropic);
+ }
+
if (instrumentModules?.azureOpenAI) {
const instrumentation = new AzureOpenAIInstrumentation();
instrumentations.push(instrumentation as Instrumentation);