{"_id":"@countly/ai-sdk-anthropic","_rev":"4-acb30fc1bcd41d6945a6094b212eb6dd","name":"@countly/ai-sdk-anthropic","dist-tags":{"latest":"0.0.6"},"versions":{"0.0.3":{"name":"@countly/ai-sdk-anthropic","version":"0.0.3","_id":"@countly/ai-sdk-anthropic@0.0.3","maintainers":[{"name":"mksglu","email":"code.bm.ksglu@gmail.com"}],"dist":{"shasum":"e959d65eadfd32e70bf4a5088933e82012cc5521","tarball":"https://registry.npmjs.org/@countly/ai-sdk-anthropic/-/ai-sdk-anthropic-0.0.3.tgz","fileCount":10,"integrity":"sha512-DgeifeqeioUa0nd2UOXIvJueGj5kBJm58hGRMyUsFR5th9BEJX3ClLTBXZ+SVOWjohmWxRhG5AaJwjZMUQR7Og==","signatures":[{"sig":"MEYCIQC6JRGDZuc5WNNCjZvqjF8XnkNE5yxfcWMtcnq9uMN5bAIhAMvBW54nur8nGdVXKhZg5/KIPbIJMoUFX+Iowl69+PcA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37091},"type":"module","_from":"file:countly-ai-sdk-anthropic-0.0.3.tgz","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --project tsconfig.build.json --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc --project tsconfig.build.json"},"_npmUser":{"name":"mksglu","email":"code.bm.ksglu@gmail.com"},"_resolved":"/private/var/folders/df/nbmn_hp51n177rvbz8zh44sh0000gn/T/2b7db8a2e0e2140448a4abd9e57566a8/countly-ai-sdk-anthropic-0.0.3.tgz","_integrity":"sha512-DgeifeqeioUa0nd2UOXIvJueGj5kBJm58hGRMyUsFR5th9BEJX3ClLTBXZ+SVOWjohmWxRhG5AaJwjZMUQR7Og==","_npmVersion":"11.12.1","description":"Countly AI observability adapter for Anthropic SDK","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@countly/ai-sdk-core":"0.0.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@countly/ai-sdk-tsconfig":"0.0.0"},"peerDependencies":{"@anthropic-ai/sdk":">=0.30.0"},"peerDependenciesMeta":{"@anthropic-ai/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/ai-sdk-anthropic_0.0.3_1783443603768_0.08231006972763133","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@countly/ai-sdk-anthropic","version":"0.0.4","_id":"@countly/ai-sdk-anthropic@0.0.4","maintainers":[{"name":"mksglu","email":"code.bm.ksglu@gmail.com"}],"dist":{"shasum":"bd19c716571fc3f0e742adf187848996ea493f70","tarball":"https://registry.npmjs.org/@countly/ai-sdk-anthropic/-/ai-sdk-anthropic-0.0.4.tgz","fileCount":10,"integrity":"sha512-191SLzgUVQWlU8CQpM/fo26Xgxp5v2v8hqbjJlazz4GUT6n9pXxaU2hrrI3kf4LwC+kNyzc8fpX7wlL6G2ANJw==","signatures":[{"sig":"MEUCIDGBVQ/uI+HiAXpa2ochr12OsusZk04nFf5MQZV5tCaCAiEAr4wSrww/QHZSkXxRk4JFfBTPefwjGtJrngFmJo0gUHM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40621},"type":"module","_from":"file:countly-ai-sdk-anthropic-0.0.4.tgz","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --project tsconfig.build.json --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc --project tsconfig.build.json"},"_npmUser":{"name":"mksglu","email":"code.bm.ksglu@gmail.com"},"_resolved":"/private/var/folders/df/nbmn_hp51n177rvbz8zh44sh0000gn/T/27e58582ac10f473deebb30c09dac052/countly-ai-sdk-anthropic-0.0.4.tgz","_integrity":"sha512-191SLzgUVQWlU8CQpM/fo26Xgxp5v2v8hqbjJlazz4GUT6n9pXxaU2hrrI3kf4LwC+kNyzc8fpX7wlL6G2ANJw==","_npmVersion":"10.8.2","description":"Countly AI observability adapter for Anthropic SDK","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@countly/ai-sdk-core":"0.0.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@countly/ai-sdk-tsconfig":"0.0.0"},"peerDependencies":{"@anthropic-ai/sdk":">=0.30.0"},"peerDependenciesMeta":{"@anthropic-ai/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/ai-sdk-anthropic_0.0.4_1784147100786_0.32879641948292426","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@countly/ai-sdk-anthropic","version":"0.0.5","_id":"@countly/ai-sdk-anthropic@0.0.5","maintainers":[{"name":"mksglu","email":"code.bm.ksglu@gmail.com"}],"dist":{"shasum":"8a807c84acf0f98472701713753904fc6a5163f3","tarball":"https://registry.npmjs.org/@countly/ai-sdk-anthropic/-/ai-sdk-anthropic-0.0.5.tgz","fileCount":10,"integrity":"sha512-rRsK7Df3k8W35amIPcVnpDThWY8dTtjKgLzxFH856hlnsf/+JiyW8eFpTcCSKLt9zk6HMamw+AZMknSFjSg7Mg==","signatures":[{"sig":"MEQCIGEEpV6MT+BcXIYLevP60p6kw/SUUiBJ/CYyqLnuNaz8AiBlJlXfxiPrBMMBIEBpK55bvz3uEr0Lqdh4lP1BoBfGJw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40621},"type":"module","_from":"file:countly-ai-sdk-anthropic-0.0.5.tgz","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --project tsconfig.build.json --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc --project tsconfig.build.json"},"_npmUser":{"name":"mksglu","email":"code.bm.ksglu@gmail.com"},"_resolved":"/private/var/folders/df/nbmn_hp51n177rvbz8zh44sh0000gn/T/5c12cd6c6661cef1a6a3ec4daf22a949/countly-ai-sdk-anthropic-0.0.5.tgz","_integrity":"sha512-rRsK7Df3k8W35amIPcVnpDThWY8dTtjKgLzxFH856hlnsf/+JiyW8eFpTcCSKLt9zk6HMamw+AZMknSFjSg7Mg==","_npmVersion":"10.8.2","description":"Countly AI observability adapter for Anthropic SDK","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@countly/ai-sdk-core":"0.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@countly/ai-sdk-tsconfig":"0.0.0"},"peerDependencies":{"@anthropic-ai/sdk":">=0.30.0"},"peerDependenciesMeta":{"@anthropic-ai/sdk":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/ai-sdk-anthropic_0.0.5_1784810342456_0.8936363407504919","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@countly/ai-sdk-anthropic","version":"0.0.6","description":"Countly AI observability adapter for Anthropic SDK","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"engines":{"node":"^20.19.0 || >=22.12.0"},"publishConfig":{"access":"public"},"dependencies":{"@countly/ai-sdk-core":"0.0.6"},"peerDependencies":{"@anthropic-ai/sdk":">=0.30.0"},"peerDependenciesMeta":{"@anthropic-ai/sdk":{"optional":false}},"devDependencies":{"typescript":"^5.8.3","@countly/ai-sdk-tsconfig":"0.0.0"},"scripts":{"build":"tsc --project tsconfig.build.json","dev":"tsc --project tsconfig.build.json --watch","lint":"tsc --noEmit","test":"vitest run"},"_id":"@countly/ai-sdk-anthropic@0.0.6","_integrity":"sha512-VtCRA0kqfsVZpzpU6M9S3PHUmc0rCHUj9/8hoV+sWR+WYAO5Pf2amhzazwws6c2N7bUIqRRpGiiQ0aeM8LQJRg==","_resolved":"/private/var/folders/df/nbmn_hp51n177rvbz8zh44sh0000gn/T/0ea160a0683a0652de09b288141a9dbe/countly-ai-sdk-anthropic-0.0.6.tgz","_from":"file:countly-ai-sdk-anthropic-0.0.6.tgz","_nodeVersion":"20.19.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-VtCRA0kqfsVZpzpU6M9S3PHUmc0rCHUj9/8hoV+sWR+WYAO5Pf2amhzazwws6c2N7bUIqRRpGiiQ0aeM8LQJRg==","shasum":"973c51a1325669a03448d2fa79c902f5a3426054","tarball":"https://registry.npmjs.org/@countly/ai-sdk-anthropic/-/ai-sdk-anthropic-0.0.6.tgz","fileCount":14,"unpackedSize":61818,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCD3y6JDa+x4h4vAM/UJUPCusANB9Kqfn6/fYHidRZjRgIhAKlGpSWeekCr8+e//ks7CHUDlUyVQEbkb1Rbx0UWissh"}]},"_npmUser":{"name":"mksglu","email":"code.bm.ksglu@gmail.com"},"directories":{},"maintainers":[{"name":"mksglu","email":"code.bm.ksglu@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ai-sdk-anthropic_0.0.6_1785687689687_0.6199311283844133"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-07T17:00:03.576Z","modified":"2026-08-02T16:21:30.038Z","0.0.3":"2026-07-07T17:00:03.917Z","0.0.4":"2026-07-15T20:25:00.945Z","0.0.5":"2026-07-23T12:39:02.606Z","0.0.6":"2026-08-02T16:21:29.868Z"},"description":"Countly AI observability adapter for Anthropic SDK","maintainers":[{"name":"mksglu","email":"code.bm.ksglu@gmail.com"}],"readme":"# @countly/ai-sdk-anthropic\n\n> Countly AI observability adapter for the [Anthropic TypeScript SDK](https://github.com/anthropics/anthropic-sdk-typescript).\n\nPart of the [Countly AI SDK](https://github.com/Countly/countly-ai-sdk) — provider-agnostic LLM observability for every AI stack.\n\n## Install\n\n```bash\nnpm install @countly/ai-sdk-anthropic\n```\n\n`@countly/ai-sdk-core` is pulled in automatically.\n\n## Peer dependency\n\n```\n@anthropic-ai/sdk >= 0.30.0\n```\n\nTested against `@anthropic-ai/sdk` 0.88.x. The declared floor is not yet exercised\nin CI, so treat versions below 0.30 as unsupported and older 0.x versions as\nuntested rather than verified.\n\n## Quick Start\n\n```typescript\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport { observeAnthropic } from \"@countly/ai-sdk-anthropic\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst userStore = new AsyncLocalStorage<{ userId: string }>();\n\napp.use((req, res, next) => {\n  userStore.run({ userId: req.user.id }, next);\n});\n\nconst anthropic = observeAnthropic(new Anthropic(), {\n  appKey: \"YOUR_APP_KEY\",\n  url: \"https://your-countly-server.com\",\n  getDeviceId: () => userStore.getStore()?.userId,\n  observabilityLevel: 1,\n  tags: [\"chatbot\", \"customer-support\"],\n  environment: \"production\",\n});\n\nconst message = await anthropic.messages.create({\n  model: \"claude-sonnet-4-20250514\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"Hello\" }],\n});\n```\n\n## Streaming\n\nBoth streaming surfaces are instrumented, and reporting no longer depends on how\nyou consume the stream:\n\n```typescript\n// messages.stream() — reported however you consume it: finalMessage(),\n// finalText(), done(), plain `for await`, or an .on(\"finalMessage\") handler.\nconst stream = anthropic.messages.stream({\n  model: \"claude-sonnet-4-20250514\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"Hello\" }],\n});\nconst finalMessage = await stream.finalMessage();\n\n// messages.create({stream: true}) — the row is accumulated from the raw event\n// stream (message_start usage, deltas, message_delta stop_reason/output tokens).\n// controller, tee() and toReadableStream() are passed through untouched.\nconst raw = await anthropic.messages.create({ ...params, stream: true });\nfor await (const event of raw) { /* … */ }\n```\n\nA stream you abandon early (`break`) is still recorded, as\n`status: \"incomplete\"` with no usage — output tokens are only reported in\n`message_delta`, and pricing the input alone would present a partial cost as a\ncomplete one.\n\n## What's captured\n\n- Token usage. `usage_input` is the provider's **total** input count, inclusive of\n  both `cache_read_input_tokens` and `cache_creation_input_tokens`, so it\n  reconciles with the Anthropic console; the fresh residual is reported\n  separately as `usage_input_fresh`.\n- Cost, computed from model pricing. When a model is not in the pricing table the\n  cost keys are **omitted** and `cost_priced: \"unpriced_model\"` says why — never $0.\n- Latency (total + TTFT for streaming, measured from the first content event).\n- Tool calls: client `tool_use`, `mcp_tool_use`, and the built-in\n  `server_tool_use` tools (web search / fetch → `retrieval`, the code-execution\n  family → `code_interpreter`), each with its `call_id`.\n- `api_host_type` / `api_host` — which class of endpoint served the call\n  (`vendor_direct`, `azure_openai`, `gateway`, `local_infra`). The hostname only:\n  path, query and credentials are never emitted.\n- Error tracking with categorization; APM traces; per-user aggregation.\n\n### Not captured\n\n- **Client tool outcomes.** A `tool_use` block is the model *requesting* a tool;\n  its result travels in your **next** request, so the tool row carries\n  `status: \"unknown\"` rather than a fabricated success. Server-side and MCP tools\n  do return their result in the same message, so those rows carry the real\n  outcome.\n- **`client.beta.messages`, `client.messages.batches` and `client.completions`.**\n  Generations made through them produce no rows. Set `debug: true` and the SDK\n  warns once when your code touches one of these.\n- Thinking/reasoning text is not emitted as a preview field.\n\n## Configuration\n\n| Field | Default | Description |\n|-------|---------|-------------|\n| `appKey` | *required* | Countly app key |\n| `url` | *required* | Countly server URL |\n| `getDeviceId` | — | Per-request user ID resolver (called at event enqueue time) |\n| `deviceId` | — | Static device ID (fallback) |\n| `observabilityLevel` | `0` | `0` = metrics only, `1` = + tool calls, `2` = + text previews |\n| `tags` | `[]` | Labels for cost attribution |\n| `environment` | `\"production\"` | Environment tag |\n| `costModel` | — | Custom pricing overrides |\n| `getPromptId` | — | Caller-supplied **turn** id resolver (called per interaction; falls back to an auto-generated id when it returns `undefined`). The value becomes the row's `run_id` |\n\n## Caller-supplied turn id\n\nBy default the adapter generates a unique id for every tracked interaction. If you\nalready mint your own request/trace id (e.g. per HTTP request or per chat turn),\nsupply it via `getPromptId` so the row is stamped with your id instead — on both\nthe streaming and non-streaming paths. This lets you correlate the\n`[CLY]_llm_interaction` event with your own logs and, in turn, with feedback\nrecorded under the same id.\n\nYour id lands on the wire as **`run_id`**, the turn identity shared by every row\nthe turn emits. Each row also carries its own `event_id` (the primary key), and a\n`prompt_id` foreign key pointing at the row it belongs to — for an interaction\nthat is its own `event_id`, for a tool row it is the generation that requested\nthe tool.\n\n```typescript\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst requestStore = new AsyncLocalStorage<{ promptId: string }>();\n\nconst anthropic = observeAnthropic(new Anthropic(), {\n  appKey: \"YOUR_APP_KEY\",\n  url: \"https://your-countly-server.com\",\n  getPromptId: () => requestStore.getStore()?.promptId, // undefined → auto-generated fallback\n});\n```\n\nThe resolved id is what you record feedback against (see below) — pass the same value as `prompt_id` to `feedback.track()`.\n\n## Feedback\n\nUser feedback (thumbs up/down, ratings, comments) is not auto-collected — wire it\nfrom your UI. Capture each tracked interaction's identity via the `onPrompt`\ncallback, then record feedback against it with `createFeedbackTracker`\n(re-exported from this package, so no extra install is needed):\n\n```typescript\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport { observeAnthropic, createFeedbackTracker, type PromptInfo } from \"@countly/ai-sdk-anthropic\";\n\nconst countly = { appKey: \"YOUR_APP_KEY\", url: \"https://your-countly-server.com\" };\n\nlet lastPrompt: PromptInfo | undefined;\nconst anthropic = observeAnthropic(new Anthropic(), {\n  ...countly,\n  onPrompt: (info) => { lastPrompt = info; }, // fires after every tracked call\n});\n\nconst feedback = createFeedbackTracker(countly, { sdk_adapter: \"anthropic\" });\n\nconst message = await anthropic.messages.create({\n  model: \"claude-sonnet-4-5\",\n  max_tokens: 1024,\n  messages: [{ role: \"user\", content: \"Explain quantum computing\" }],\n});\n\n// ...later, when the user rates the answer:\nfeedback.track({\n  prompt_id: lastPrompt!.prompt_id,\n  rating: \"thumbs_up\", // or \"thumbs_down\", or any custom string\n  score: 0.9, // optional 0-1 numeric score\n  category: \"helpful\", // optional: hallucination, irrelevant, harmful, ...\n  comment: \"Great answer\", // optional free-form text\n  deviceId: user.id, // attribute to the same user as the interaction\n});\n```\n\n`info.prompt_id` is the turn (identical to `info.run_id`), so the rating above\napplies to the whole turn. To rate **one** generation instead, pass that\ngeneration's row id:\n\n```typescript\nfeedback.track({ prompt_id: lastPrompt!.event_id, run_id: lastPrompt!.run_id, rating: \"thumbs_down\" });\n```\n\nEach `track()` call emits a `[CLY]_llm_interaction_feedback` event that joins back\nto the interaction via `run_id`, with `parent_event_key` recording whether the\nrating is attached to the run or to a single generation — powering prompt →\nfeedback funnels and per-model satisfaction breakdowns in Countly. In a real app,\nstore the id alongside the rendered message (or return it to your client) and read\nit back when the user rates the answer. Feedback is batched like interaction\nevents; call `feedback.flush()` to send immediately, or `feedback.shutdown()` on\nprocess exit.\n\n## Full documentation\n\nSee the [Countly AI SDK repository](https://github.com/Countly/countly-ai-sdk) for the **schema v2 wire contract** (one row per generation, RULE A dimensions, RULE B measures with their `usage_state` / `cost_priced` markers, and the common envelope), the [adapter capability matrix](https://github.com/Countly/countly-ai-sdk/blob/main/docs/capability-matrix.md), observability levels (0/1/2), cost calculation, privacy controls, and Countly plugin integration (Drill, Funnels, Cohorts, APM, Crash Analytics).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}