@amplitude/ai 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -4
- package/README.md +34 -36
- package/amplitude-ai.md +10 -26
- package/bin/amplitude-ai.mjs +16 -4
- package/dist/bound-agent.d.ts.map +1 -1
- package/dist/core/privacy.d.ts.map +1 -1
- package/dist/core/privacy.js +1 -0
- package/dist/core/privacy.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +3 -1
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +11 -2
- package/dist/providers/openai.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/llms-full.txt +4 -1
- package/llms.txt +1 -1
- package/mcp.schema.json +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
Package: `@amplitude/ai` v0.3.
|
|
3
|
+
Package: `@amplitude/ai` v0.3.7
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -53,12 +53,12 @@ Codex auto-reads this `AGENTS.md` file for context.
|
|
|
53
53
|
|
|
54
54
|
## Decision Tree
|
|
55
55
|
|
|
56
|
-
-
|
|
57
|
-
- Already have a provider client: use `wrap()`
|
|
58
|
-
- Need user/session lineage: use `ai.agent(...).session(...)`.
|
|
56
|
+
- **Default: use `ai.agent(...).session(...)` with provider wrappers** — gives you every event type, per-user analytics, session enrichment, quality scoring.
|
|
57
|
+
- Already have a provider client: use `wrap()` to instrument it.
|
|
59
58
|
- Multiple agents collaborating: use `session.runAs(childAgent, fn)` for automatic identity propagation.
|
|
60
59
|
- Need tool telemetry: use `tool()`.
|
|
61
60
|
- Need span/observability: use `observe()`.
|
|
61
|
+
- Cannot modify call sites at all: use `patch()` for aggregate-only monitoring (no per-user analytics).
|
|
62
62
|
- Need agent-assistant guidance: run MCP prompt `instrument_app`.
|
|
63
63
|
|
|
64
64
|
## MCP Surface
|
|
@@ -102,6 +102,8 @@ Prompt:
|
|
|
102
102
|
|
|
103
103
|
## CLI
|
|
104
104
|
|
|
105
|
+
- `amplitude-ai` — Print instrumentation prompt for AI coding agents
|
|
106
|
+
- `amplitude-ai --print-guide` — Print the full amplitude-ai.md guide to stdout
|
|
105
107
|
- `amplitude-ai mcp` — Start the MCP server for AI coding agents
|
|
106
108
|
- `amplitude-ai doctor [--json]` — Validate environment, deps, and event pipeline
|
|
107
109
|
- `amplitude-ai status [--json]` — Show SDK version, installed providers, and env config
|
package/README.md
CHANGED
|
@@ -51,14 +51,19 @@ The CLI prints a prompt to paste into any AI coding agent (Cursor, Claude Code,
|
|
|
51
51
|
|
|
52
52
|
The agent reads the guide, scans your project, discovers your agents and LLM call sites, and instruments everything — provider wrappers, session lifecycle, multi-agent delegation, tool tracking, scoring, and a verification test. You review and approve each step.
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### Manual setup
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
Whether you use a coding agent or set up manually, the goal is the same: **full instrumentation** — agents + sessions + provider wrappers. This gives you every event type, per-user analytics, and server-side enrichment.
|
|
57
|
+
|
|
58
|
+
Follow the [code example above](#amplitude-ai) to get started. The pattern is:
|
|
59
|
+
|
|
60
|
+
1. **Swap your LLM import** — `import { OpenAI } from '@amplitude/ai'` (or `Anthropic`, `Gemini`, etc.)
|
|
61
|
+
2. **Create an agent** — `ai.agent('my-agent')` to name and track your AI component
|
|
62
|
+
3. **Wrap in a session** — `agent.session({ userId, sessionId }).run(async (s) => { ... })` for per-user analytics, funnels, cohorts, and server-side enrichment
|
|
63
|
+
4. **Track user messages** — `s.trackUserMessage(...)` for conversation context
|
|
64
|
+
5. **Score responses** — `s.score(...)` for quality measurement
|
|
60
65
|
|
|
61
|
-
>
|
|
66
|
+
> `patch()` exists for quick verification or legacy codebases where you can't modify call sites, but it only captures `[Agent] AI Response` without user identity — no funnels, no cohorts, no retention. Start with full instrumentation; fall back to `patch()` only if you can't modify call sites.
|
|
62
67
|
|
|
63
68
|
| Property | Value |
|
|
64
69
|
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -100,7 +105,7 @@ The agent reads the guide, scans your project, discovers your agents and LLM cal
|
|
|
100
105
|
- [Auto-Instrumentation CLI](#auto-instrumentation-cli)
|
|
101
106
|
- [Integrations](#integrations)
|
|
102
107
|
- [Data Flow](#data-flow)
|
|
103
|
-
- [
|
|
108
|
+
- [Integration Approaches](#integration-approaches)
|
|
104
109
|
- [Integration Patterns](#integration-patterns)
|
|
105
110
|
- [Serverless Environments](#serverless-environments)
|
|
106
111
|
- [Error Handling and Reliability](#error-handling-and-reliability)
|
|
@@ -137,7 +142,7 @@ Install provider SDKs based on what you use (for example: `openai`, `@anthropic-
|
|
|
137
142
|
|
|
138
143
|
1. **Install:** `npm install @amplitude/ai @amplitude/analytics-node`
|
|
139
144
|
2. **Get your API key:** In Amplitude, go to **Settings > Projects** and copy the API key.
|
|
140
|
-
3. **
|
|
145
|
+
3. **Instrument:** Run `npx amplitude-ai` and paste the printed prompt into your AI coding agent. Or follow the [manual setup](#manual-setup) steps — the goal is the same: agents + sessions + provider wrappers.
|
|
141
146
|
4. **Set your API key** in the generated `.env` file and replace the placeholder `userId`/`sessionId`.
|
|
142
147
|
5. **Run your app.** You should see `[Agent] User Message`, `[Agent] AI Response`, and `[Agent] Session End` within 30 seconds.
|
|
143
148
|
|
|
@@ -504,7 +509,13 @@ const session = agent.session({
|
|
|
504
509
|
});
|
|
505
510
|
```
|
|
506
511
|
|
|
507
|
-
Without this, sessions with long idle periods may be closed and
|
|
512
|
+
Without this, sessions with long idle periods may be closed and enrichment may run earlier than expected. The default is 30 minutes.
|
|
513
|
+
|
|
514
|
+
**Session lifecycle and enrichment.** You do **not** need to call `trackSessionEnd()` for sessions to work. Amplitude's server automatically closes sessions after 30 minutes of inactivity and queues them for enrichment (topic classification, quality scoring, session evaluation) at that point. The only reason to call `trackSessionEnd()` is to **trigger enrichment sooner** — for example, if you know the conversation is over and want evaluation results immediately rather than waiting for the idle timeout.
|
|
515
|
+
|
|
516
|
+
"Closed" is a server-side concept meaning "queued for enrichment" — it does **not** prevent new events from flowing into the same session. If the user resumes a conversation after session end, new messages with the same `sessionId` are still associated with that session.
|
|
517
|
+
|
|
518
|
+
If you use `session.run()`, session end is tracked automatically when the callback completes. For long-lived conversations (chatbots, support agents), you can skip explicit session end entirely and let the server handle it.
|
|
508
519
|
|
|
509
520
|
**Link to Session Replay**: If your frontend uses Amplitude's [Session Replay](https://www.docs.developers.amplitude.com/session-replay/), pass the browser's `deviceId` and `browserSessionId` to link AI sessions to browser recordings:
|
|
510
521
|
|
|
@@ -1643,33 +1654,20 @@ Your Application
|
|
|
1643
1654
|
- The LLM Enrichment Pipeline runs asynchronously after session close (only when `contentMode: 'full'`). It produces server-side events like `[Agent] Session Evaluation` and `[Agent] Score`.
|
|
1644
1655
|
- With `contentMode: 'customer_enriched'`, the enrichment pipeline is skipped — you provide your own enrichments via `trackSessionEnrichment()`.
|
|
1645
1656
|
|
|
1646
|
-
##
|
|
1647
|
-
|
|
1648
|
-
Start
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
│ │
|
|
1661
|
-
Tier 1: Events Do you control
|
|
1662
|
-
Per-call tracking the LLM call site?
|
|
1663
|
-
+ userId │
|
|
1664
|
-
┌── Yes ──┴── No ──┐
|
|
1665
|
-
│ │
|
|
1666
|
-
Tier 2: Sessions Tier 3: OTEL Bridge
|
|
1667
|
-
session.run() Add exporter to
|
|
1668
|
-
Full enrichment existing OTEL pipeline
|
|
1669
|
-
Implicit feedback Limited to OTEL attrs
|
|
1670
|
-
```
|
|
1671
|
-
|
|
1672
|
-
**Rule of thumb:** If you own the LLM call site, start with **Tier 2** (sessions). If you don't (e.g., a third-party framework exports OTEL spans), use **Tier 3** (OTEL bridge). If you just want aggregate cost monitoring without user analytics, **Tier 0** (zero-code) is ready in 60 seconds.
|
|
1657
|
+
## Integration Approaches
|
|
1658
|
+
|
|
1659
|
+
**Start with full instrumentation.** Use agents + sessions + provider wrappers. This is the recommended approach for both coding agent and manual workflows — it gives you every event type, per-user analytics, and server-side enrichment.
|
|
1660
|
+
|
|
1661
|
+
| Approach | When to use | What you get |
|
|
1662
|
+
|---|---|---|
|
|
1663
|
+
| **Full control** (recommended) | Any project, new or existing | `BoundAgent` + `session.run()` + provider wrappers — all event types, per-user funnels, cohorts, retention, quality scoring, enrichments |
|
|
1664
|
+
| **Express/Fastify middleware** | Web app, auto-session per request | Same as full control with automatic session lifecycle via `createAmplitudeAIMiddleware` |
|
|
1665
|
+
| **Swap import** | Existing codebase, incremental adoption | `new OpenAI({ amplitude: ai })` — auto-tracking per call, add sessions when ready |
|
|
1666
|
+
| **Wrap** | You've already created a client | `wrap(client, ai)` — instruments an existing client instance |
|
|
1667
|
+
| **Zero-code / `patch()`** | Verification or legacy codebases only | `patch({ amplitudeAI: ai })` — `[Agent] AI Response` only, no user identity, no funnels |
|
|
1668
|
+
| **OTEL Bridge** | Third-party framework exports OTEL spans | Add exporter to existing OTEL pipeline — limited to OTEL attributes |
|
|
1669
|
+
|
|
1670
|
+
> The first four approaches all support the full event model. Choose based on how you want to integrate — the analytics capabilities are the same. **`patch()` is the exception**: it only captures aggregate `[Agent] AI Response` events without user identity, useful only for verifying the SDK works or for codebases where you can't modify call sites.
|
|
1673
1671
|
|
|
1674
1672
|
## Integration Patterns
|
|
1675
1673
|
|
package/amplitude-ai.md
CHANGED
|
@@ -29,30 +29,21 @@ Detected environment:
|
|
|
29
29
|
Multi-agent signals: [yes/no]
|
|
30
30
|
Streaming: [yes/no]
|
|
31
31
|
Frontend deps: [yes/no]
|
|
32
|
-
Recommended
|
|
32
|
+
Recommended: full instrumentation
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
**
|
|
36
|
-
- **Quick start** — `patch({ amplitudeAI: ai })`, zero code changes, good for getting data flowing
|
|
37
|
-
- **Standard** — Provider wrappers + session middleware (recommended for most apps)
|
|
38
|
-
- **Advanced** — Multi-agent `runAs`, agent descriptions, scoring, tool tracking
|
|
39
|
-
|
|
40
|
-
If multi-agent signals are detected, recommend Advanced.
|
|
35
|
+
**Next step:** Confirm the detection with the developer, then proceed to full instrumentation. Always instrument with agents, sessions, provider wrappers, tool tracking, and scoring. If multi-agent signals are detected, also add child agents and `runAs` delegation.
|
|
41
36
|
|
|
42
37
|
---
|
|
43
38
|
|
|
44
39
|
## Phase 2: Discover Agents and Call Sites
|
|
45
40
|
|
|
46
|
-
For **Quick start** tier, skip to Phase 3 — discovery is just "which providers are imported."
|
|
47
|
-
|
|
48
|
-
For **Standard** and **Advanced** tiers:
|
|
49
|
-
|
|
50
41
|
1. Identify files with LLM call sites (search for `chat.completions.create`, `messages.create`, `generateContent`, `streamText`, `generateText`)
|
|
51
42
|
2. For each file with call sites, read the actual source and review:
|
|
52
43
|
- Is it a route handler / API endpoint?
|
|
53
44
|
- What provider(s) does it use?
|
|
54
45
|
- Does it call other files with LLM call sites? (delegation → multi-agent)
|
|
55
|
-
3.
|
|
46
|
+
3. Identify:
|
|
56
47
|
- Agent boundaries (each distinct orchestration unit = one agent)
|
|
57
48
|
- Delegation patterns (parent calls child → `runAs`)
|
|
58
49
|
- Feedback handlers (thumbs up/down UI components)
|
|
@@ -135,17 +126,10 @@ export const openai = new OpenAI({
|
|
|
135
126
|
// export const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, amplitude: ai });
|
|
136
127
|
```
|
|
137
128
|
|
|
138
|
-
**Alternative: `wrap()` for existing clients.** If the project creates provider clients dynamically:
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
import { wrap } from '@amplitude/ai';
|
|
142
|
-
import OpenAI from 'openai';
|
|
143
|
-
const rawClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
|
|
144
|
-
export const openai = wrap(rawClient, ai);
|
|
145
|
-
```
|
|
146
|
-
|
|
147
129
|
Add `AMPLITUDE_AI_API_KEY` to `.env.example`. Check `.gitignore` includes `.env`.
|
|
148
130
|
|
|
131
|
+
> **Note:** If you cannot modify provider instantiation sites, use `wrap(existingClient, ai)` to instrument an existing client, or `patch({ amplitudeAI: ai })` for zero-code verification. These capture fewer event types — always prefer provider wrappers when possible.
|
|
132
|
+
|
|
149
133
|
### Step 3c: Swap provider imports
|
|
150
134
|
|
|
151
135
|
Replace direct provider instantiation with imports from the bootstrap file:
|
|
@@ -163,7 +147,7 @@ import { openai as client } from '@/lib/amplitude';
|
|
|
163
147
|
|
|
164
148
|
### Step 3d: Add session context
|
|
165
149
|
|
|
166
|
-
|
|
150
|
+
Wrap route handlers with agent + session:
|
|
167
151
|
|
|
168
152
|
```typescript
|
|
169
153
|
import { ai } from '@/lib/amplitude';
|
|
@@ -183,7 +167,7 @@ export async function POST(req: Request) {
|
|
|
183
167
|
}
|
|
184
168
|
```
|
|
185
169
|
|
|
186
|
-
|
|
170
|
+
If multi-agent signals were detected, add delegation with `runAs`:
|
|
187
171
|
|
|
188
172
|
```typescript
|
|
189
173
|
const orchestrator = ai.agent('shopping-agent', { description: 'Orchestrates shopping requests' });
|
|
@@ -220,7 +204,7 @@ s.trackAiMessage(completedMessage.content, 'gpt-4o', 'openai', latencyMs, {
|
|
|
220
204
|
});
|
|
221
205
|
```
|
|
222
206
|
|
|
223
|
-
### Step 3f: Add span tracking for orchestration
|
|
207
|
+
### Step 3f: Add span tracking for orchestration
|
|
224
208
|
|
|
225
209
|
When a parent agent delegates work to a child agent, wrap the delegation call with span tracking to measure latency and capture errors. Look for existing try/catch blocks around sub-agent execution — these are natural places to add span tracking with both success and error paths:
|
|
226
210
|
|
|
@@ -253,9 +237,9 @@ try {
|
|
|
253
237
|
}
|
|
254
238
|
```
|
|
255
239
|
|
|
256
|
-
### Step 3g: Add scoring
|
|
240
|
+
### Step 3g: Add scoring
|
|
257
241
|
|
|
258
|
-
If feedback handlers were detected (thumbs up/down UI),
|
|
242
|
+
If feedback handlers were detected (thumbs up/down UI), add scoring. Check whether the handler receives a `messageId` — if so, target the specific message for finer-grained scoring. Otherwise fall back to session-level scoring:
|
|
259
243
|
|
|
260
244
|
```typescript
|
|
261
245
|
const targetId = messageId ?? sessionId;
|
package/bin/amplitude-ai.mjs
CHANGED
|
@@ -25,9 +25,10 @@ Paste this into your AI coding agent (Cursor, Claude Code, Copilot, etc.):
|
|
|
25
25
|
Instrument this app with @amplitude/ai. Follow node_modules/@amplitude/ai/amplitude-ai.md
|
|
26
26
|
|
|
27
27
|
CLI commands:
|
|
28
|
-
mcp
|
|
29
|
-
doctor
|
|
30
|
-
status
|
|
28
|
+
mcp Start the MCP server (optional, for advanced tooling)
|
|
29
|
+
doctor Validate environment, deps, and event pipeline
|
|
30
|
+
status Show SDK version, installed providers, and env config
|
|
31
|
+
--print-guide Print the full amplitude-ai.md instrumentation guide to stdout
|
|
31
32
|
`
|
|
32
33
|
);
|
|
33
34
|
process.exit(0);
|
|
@@ -39,6 +40,17 @@ if (command === '--version' || command === '-v') {
|
|
|
39
40
|
process.exit(0);
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
if (command === '--print-guide') {
|
|
44
|
+
const guidePath = join(dirname(fileURLToPath(import.meta.url)), '..', 'amplitude-ai.md');
|
|
45
|
+
try {
|
|
46
|
+
process.stdout.write(readFileSync(guidePath, 'utf8'));
|
|
47
|
+
} catch {
|
|
48
|
+
process.stderr.write(`Guide not found at ${guidePath}\n`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
if (command in commandToBin) {
|
|
43
55
|
const binPath = fileURLToPath(new URL(commandToBin[command], import.meta.url));
|
|
44
56
|
const result = spawnSync(process.execPath, [binPath, ...rest], {
|
|
@@ -48,5 +60,5 @@ if (command in commandToBin) {
|
|
|
48
60
|
process.exit(result.status ?? 1);
|
|
49
61
|
}
|
|
50
62
|
|
|
51
|
-
process.stderr.write(`Unknown command: ${command}\nUsage: amplitude-ai <mcp|doctor|status>\n`);
|
|
63
|
+
process.stderr.write(`Unknown command: ${command}\nUsage: amplitude-ai <mcp|doctor|status|--print-guide>\n`);
|
|
52
64
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bound-agent.d.ts","names":[],"sources":["../src/bound-agent.ts"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"bound-agent.d.ts","names":[],"sources":["../src/bound-agent.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"privacy.d.ts","names":[],"sources":["../../src/core/privacy.ts"],"sourcesContent":[],"mappings":";cAaa,0BAAA;AAAA,cACA,4BAAA,GAD0B,oBAAA;AAC1B,cAIA,cAAA,GAJ4B,IAAA;AAI5B,cACA,UAAA,GADc,CAAA;AACd,iBAgBG,eAAA,CAhBO,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAgBP,iBAIA,UAAA,CAJe,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAIf,iBAYA,WAAA,CAZU,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAYV,iBAKA,iBAAA,CALW,OAAA,EAAA,OAAA,CAAA,EAAA,MAAA;AAKX,iBAMA,mBAAA,CANiB,KAAA,EAAA,OAAA,CAAA,EAAA,OAAA;AAMjB,iBAOA,iBAAA,CAPmB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAOnC;AA8CA;AAIA;AAeA;
|
|
1
|
+
{"version":3,"file":"privacy.d.ts","names":[],"sources":["../../src/core/privacy.ts"],"sourcesContent":[],"mappings":";cAaa,0BAAA;AAAA,cACA,4BAAA,GAD0B,oBAAA;AAC1B,cAIA,cAAA,GAJ4B,IAAA;AAI5B,cACA,UAAA,GADc,CAAA;AACd,iBAgBG,eAAA,CAhBO,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAgBP,iBAIA,UAAA,CAJe,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAIf,iBAYA,WAAA,CAZU,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAYV,iBAKA,iBAAA,CALW,OAAA,EAAA,OAAA,CAAA,EAAA,MAAA;AAKX,iBAMA,mBAAA,CANiB,KAAA,EAAA,OAAA,CAAA,EAAA,OAAA;AAMjB,iBAOA,iBAAA,CAPmB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAOnC;AA8CA;AAIA;AAeA;AAqCA;AAkCA;;;;;;AAqEiB,iBA/JD,YAAA,CA+JqB,IAAA,EAAA,MAAA,CAAA,EA/JO,MA+JP,CAAA,MAAA,EAAA,OAAA,CAAA;AASxB,iBApKG,qBAAA,CAoKU,UAAA,EAnKZ,MAmKY,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA;AASH,iBA9JP,kBAAA,CA8JO,OAAA,EAAA,OAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,SAAA,CAAA,EAAA,OAAA,CAAA,EA1JpB,MA0JoB,CAAA,MAAA,EAAA,OAAA,CAAA;AAyEc,iBAlMrB,yBAAA,CAkMqB,OAAA,EAAA,OAAA,EAAA,SAAA,EAAA,OAAA,CAAA,EAAA,OAAA;;;;;AA6EhC,iBA7OW,wBAAA,CA6OX,eAAA,EA5Oc,KA4Od,CA5OoB,MA4OpB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,EA3OF,KA2OE,CA3OI,MA2OJ,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;AAAM,UAxKM,oBAAA,CAwKN;;;;;;;;cA/JE,aAAA;;;;;;;;wBASU;;;;qCAyEc;qDAwBgB;8FAwBhD;2CA4BgB,MAAM,8CACtB"}
|
package/dist/core/privacy.js
CHANGED
|
@@ -103,6 +103,7 @@ function sanitizeAnyContent(content, privacyMode = false, redactPii = true) {
|
|
|
103
103
|
if (typeof content === "string") textContent = content;
|
|
104
104
|
else if (typeof content === "object") textContent = extractTextFromStructuredContent(content);
|
|
105
105
|
else textContent = String(content);
|
|
106
|
+
if (textContent.length === 0) return result;
|
|
106
107
|
if (redactPii) {
|
|
107
108
|
textContent = redactPiiPatterns(textContent);
|
|
108
109
|
const redacted = redactBase64Content(textContent);
|
package/dist/core/privacy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"privacy.js","names":["parts: string[]","result: Record<string, unknown>","textContent: string","sanitized: Record<string, unknown>","normalized: Array<Record<string, unknown>>","modeStr: string | null","sorted: Record<string, unknown>"],"sources":["../../src/core/privacy.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport { getLogger } from '../utils/logger.js';\nimport {\n PROP_HAS_REASONING,\n PROP_REASONING_CONTENT,\n PROP_REASONING_TOKENS,\n PROP_SYSTEM_PROMPT,\n PROP_SYSTEM_PROMPT_LENGTH,\n PROP_TOOL_DEFINITIONS,\n PROP_TOOL_DEFINITIONS_COUNT,\n PROP_TOOL_DEFINITIONS_HASH,\n} from './constants.js';\n\nexport const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';\nexport const REDACTED_CONTENT_PLACEHOLDER = '[content redacted]';\n\n// Legacy chunking constants — kept only so getTextFromLlmMessage() can\n// still read old chunked events. New events always use { text: content }.\nexport const MAX_CHUNK_SIZE = 1024;\nexport const MAX_CHUNKS = 8;\n\nconst VALID_CONTENT_MODES = new Set([\n 'full',\n 'metadata_only',\n 'customer_enriched',\n]);\n\n// PII regex patterns\nconst EMAIL_RE = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\nconst PHONE_RE = /\\b\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})\\b/g;\nconst CREDIT_CARD_RE = /\\b(?:\\d{4}[-\\s]?){3}\\d{4}\\b/g;\nconst SSN_RE = /\\b\\d{3}-\\d{2}-\\d{4}\\b/g;\nconst BASE64_DATA_URL_RE = /^data:([^;]+);base64,/;\nconst RAW_BASE64_RE = /^[A-Za-z0-9+/]+=*$/;\n\nexport function isBase64DataUrl(text: string): boolean {\n return BASE64_DATA_URL_RE.test(text);\n}\n\nexport function isValidUrl(text: string): boolean {\n try {\n const result = new URL(text);\n return Boolean(result.protocol && result.hostname);\n } catch {\n // not a valid absolute URL\n }\n return (\n text.startsWith('/') || text.startsWith('./') || text.startsWith('../')\n );\n}\n\nexport function isRawBase64(text: string): boolean {\n if (isValidUrl(text)) return false;\n return text.length > 20 && RAW_BASE64_RE.test(text);\n}\n\nexport function createContentHash(content: unknown): string {\n if (content == null) return '';\n const contentStr = typeof content === 'string' ? content : String(content);\n return crypto.createHash('sha256').update(contentStr, 'utf8').digest('hex');\n}\n\nexport function redactBase64Content(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n if (isBase64DataUrl(value)) return REDACTED_IMAGE_PLACEHOLDER;\n if (isRawBase64(value)) return REDACTED_IMAGE_PLACEHOLDER;\n return value;\n}\n\nexport function redactPiiPatterns(text: string): string {\n let result = text;\n result = result.replace(EMAIL_RE, '[email]');\n result = result.replace(PHONE_RE, '[phone]');\n result = result.replace(CREDIT_CARD_RE, '[credit_card]');\n result = result.replace(SSN_RE, '[ssn]');\n return result;\n}\n\nfunction extractTextFromStructuredContent(content: unknown): string {\n if (content == null) return '';\n if (typeof content === 'string') return content;\n\n if (typeof content === 'object' && !Array.isArray(content)) {\n const dict = content as Record<string, unknown>;\n for (const field of ['content', 'text', 'message']) {\n if (field in dict) return extractTextFromStructuredContent(dict[field]);\n }\n return String(content);\n }\n\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item === 'string') parts.push(item);\n else if (typeof item === 'object')\n parts.push(extractTextFromStructuredContent(item));\n else parts.push(String(item));\n }\n return parts.join('');\n }\n\n return String(content);\n}\n\n/**\n * Return the `$llm_message` payload for the given text.\n *\n * Content is stored as `{ text: content }` at full length — the Node SDK\n * does not truncate string properties, and Nova already whitelists\n * `$llm_message` server-side.\n *\n * Previous versions split long content into `c0`..`c7` chunks. That format\n * is still readable via {@link getTextFromLlmMessage} for backward\n * compatibility, but is no longer produced.\n */\nexport function chunkContent(text: string): Record<string, unknown> {\n return { text };\n}\n\nexport function getTextFromLlmMessage(\n llmMessage: Record<string, unknown>,\n): string {\n if ('text' in llmMessage) return String(llmMessage.text);\n const n = llmMessage.n;\n if (typeof n === 'number' && n > 0) {\n const parts: string[] = [];\n for (let i = 0; i < n; i++) {\n parts.push(String(llmMessage[`c${i}`] ?? ''));\n }\n return parts.join('');\n }\n return '';\n}\n\nexport function sanitizeAnyContent(\n content: unknown,\n privacyMode = false,\n redactPii = true,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n if (content == null) return result;\n\n let textContent: string;\n if (typeof content === 'string') {\n textContent = content;\n } else if (typeof content === 'object') {\n textContent = extractTextFromStructuredContent(content);\n } else {\n textContent = String(content);\n }\n\n if (redactPii) {\n textContent = redactPiiPatterns(textContent);\n const redacted = redactBase64Content(textContent);\n if (typeof redacted === 'string') textContent = redacted;\n }\n\n if (privacyMode) {\n result.content_hash = createContentHash(textContent);\n } else {\n result.$llm_message = chunkContent(textContent);\n }\n\n return result;\n}\n\nexport function sanitizeStructuredContent(\n content: unknown,\n redactPii: boolean,\n): unknown {\n if (typeof content === 'string') {\n let text = content;\n if (redactPii) text = redactPiiPatterns(text);\n return redactBase64Content(text);\n }\n\n if (\n content != null &&\n typeof content === 'object' &&\n !Array.isArray(content)\n ) {\n const dict = content as Record<string, unknown>;\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(dict)) {\n sanitized[key] = sanitizeStructuredContent(value, redactPii);\n }\n return sanitized;\n }\n\n if (Array.isArray(content)) {\n return content.map((item) => sanitizeStructuredContent(item, redactPii));\n }\n\n return content;\n}\n\n/**\n * Normalize tool definitions from various provider formats into a canonical shape:\n * `[{ name, description, parameters }]`.\n */\nexport function normalizeToolDefinitions(\n toolDefinitions: Array<Record<string, unknown>>,\n): Array<Record<string, unknown>> {\n const normalized: Array<Record<string, unknown>> = [];\n for (const tool of toolDefinitions) {\n if (tool == null || typeof tool !== 'object') continue;\n\n // OpenAI Chat format: { type: \"function\", function: { name, description, parameters } }\n const fn = tool.function;\n if (fn != null && typeof fn === 'object') {\n const f = fn as Record<string, unknown>;\n normalized.push({\n name: f.name ?? '',\n description: f.description ?? '',\n parameters: f.parameters ?? null,\n });\n continue;\n }\n\n // Anthropic format: { name, description, input_schema }\n if ('input_schema' in tool) {\n normalized.push({\n name: tool.name ?? '',\n description: tool.description ?? '',\n parameters: tool.input_schema ?? null,\n });\n continue;\n }\n\n // Bedrock format: { toolSpec: { name, description, inputSchema } }\n const toolSpec = tool.toolSpec;\n if (toolSpec != null && typeof toolSpec === 'object') {\n const ts = toolSpec as Record<string, unknown>;\n normalized.push({\n name: ts.name ?? '',\n description: ts.description ?? '',\n parameters: ts.inputSchema ?? null,\n });\n continue;\n }\n\n // Gemini format: { function_declarations: [{ name, description, parameters }] }\n const fnDecls = tool.function_declarations;\n if (Array.isArray(fnDecls)) {\n for (const decl of fnDecls) {\n if (decl != null && typeof decl === 'object') {\n const d = decl as Record<string, unknown>;\n normalized.push({\n name: d.name ?? '',\n description: d.description ?? '',\n parameters: d.parameters ?? null,\n });\n }\n }\n continue;\n }\n\n // Generic / OpenAI Responses format: { name, description, parameters }\n if ('name' in tool) {\n normalized.push({\n name: tool.name ?? '',\n description: tool.description ?? '',\n parameters: tool.parameters ?? null,\n });\n }\n }\n return normalized;\n}\n\nexport interface PrivacyConfigOptions {\n privacyMode?: boolean;\n redactPii?: boolean;\n customRedactionPatterns?: string[];\n contentMode?: string | null;\n validate?: boolean;\n debug?: boolean;\n}\n\nexport class PrivacyConfig {\n readonly privacyMode: boolean;\n readonly redactPii: boolean;\n readonly validate: boolean;\n readonly debug: boolean;\n readonly customPatterns: string[];\n private readonly _compiledCustomPatterns: RegExp[];\n private readonly _contentMode: string | null;\n\n constructor(options: PrivacyConfigOptions = {}) {\n this.privacyMode = options.privacyMode ?? false;\n this.redactPii = options.redactPii ?? false;\n this.validate = options.validate ?? false;\n this.debug = options.debug ?? false;\n this.customPatterns = options.customRedactionPatterns ?? [];\n this._compiledCustomPatterns = [];\n\n for (const pattern of this.customPatterns) {\n try {\n this._compiledCustomPatterns.push(new RegExp(pattern, 'g'));\n } catch (e) {\n getLogger().warn(\n `Invalid custom redaction regex \"${pattern}\": ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n }\n\n let modeStr: string | null = null;\n if (options.contentMode != null) {\n modeStr = String(options.contentMode);\n if (!VALID_CONTENT_MODES.has(modeStr)) {\n throw new Error(\n `Invalid content_mode \"${options.contentMode}\". ` +\n `Must be one of: ${[...VALID_CONTENT_MODES].sort().join(', ')}`,\n );\n }\n }\n this._contentMode = modeStr;\n }\n\n get contentMode(): string | null {\n return this._contentMode;\n }\n\n private _applyCustomPatterns(text: string): string {\n if (!this._compiledCustomPatterns.length || typeof text !== 'string') {\n return text;\n }\n let result = text;\n for (const pattern of this._compiledCustomPatterns) {\n try {\n result = result.replace(pattern, '[REDACTED]');\n } catch (e) {\n getLogger().warn(\n `Invalid custom redaction regex \"${pattern.source}\": ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n }\n return result;\n }\n\n private _applyCustomPatternsToLlmMessage(\n llmMessage: Record<string, unknown>,\n ): void {\n if ('text' in llmMessage) {\n llmMessage.text = this._applyCustomPatterns(String(llmMessage.text));\n return;\n }\n\n const n = llmMessage.n;\n if (typeof n === 'number' && n > 0) {\n for (let i = 0; i < n; i++) {\n const key = `c${i}`;\n if (key in llmMessage) {\n llmMessage[key] = this._applyCustomPatterns(\n String(llmMessage[key] ?? ''),\n );\n }\n }\n }\n }\n\n sanitizeContent(content: unknown): Record<string, unknown> {\n if (this._contentMode == null) {\n if (this.privacyMode) return {};\n const result = sanitizeAnyContent(content, false, this.redactPii);\n if (this.customPatterns.length && '$llm_message' in result) {\n const msg = result.$llm_message as Record<string, unknown>;\n this._applyCustomPatternsToLlmMessage(msg);\n }\n return result;\n }\n\n if (this._contentMode === 'full') {\n const result = sanitizeAnyContent(content, false, this.redactPii);\n if (this.customPatterns.length && '$llm_message' in result) {\n const msg = result.$llm_message as Record<string, unknown>;\n this._applyCustomPatternsToLlmMessage(msg);\n }\n return result;\n }\n\n // metadata_only, customer_enriched → no content\n return {};\n }\n\n sanitizeSystemPrompt(systemPrompt: string | null): Record<string, unknown> {\n if (!systemPrompt) return {};\n\n const result: Record<string, unknown> = {\n [PROP_SYSTEM_PROMPT_LENGTH]: systemPrompt.length,\n };\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let sanitized = systemPrompt;\n if (this.redactPii) sanitized = redactPiiPatterns(sanitized);\n sanitized = this._applyCustomPatterns(sanitized);\n result[PROP_SYSTEM_PROMPT] =\n sanitized.length > 10000 ? sanitized.slice(0, 10000) : sanitized;\n }\n\n return result;\n }\n\n sanitizeReasoningContent(\n reasoningContent: string | null,\n reasoningTokens?: number | null,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n const hasReasoning =\n Boolean(reasoningContent) ||\n (reasoningTokens != null && reasoningTokens > 0);\n if (!hasReasoning && reasoningTokens == null) return result;\n\n if (hasReasoning) result[PROP_HAS_REASONING] = true;\n if (reasoningTokens != null)\n result[PROP_REASONING_TOKENS] = reasoningTokens;\n if (!hasReasoning || reasoningContent == null) return result;\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let sanitized = reasoningContent;\n if (this.redactPii) sanitized = redactPiiPatterns(sanitized);\n sanitized = this._applyCustomPatterns(sanitized);\n result[PROP_REASONING_CONTENT] =\n sanitized.length > 10000 ? sanitized.slice(0, 10000) : sanitized;\n }\n\n return result;\n }\n\n sanitizeToolDefinitions(\n toolDefinitions: Array<Record<string, unknown>> | null | undefined,\n ): Record<string, unknown> {\n if (!toolDefinitions?.length) return {};\n\n const normalized = normalizeToolDefinitions(toolDefinitions);\n const result: Record<string, unknown> = {\n [PROP_TOOL_DEFINITIONS_COUNT]: normalized.length,\n };\n\n const canonicalSorted = JSON.stringify(\n normalized.map((t) => {\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(t).sort()) sorted[key] = t[key];\n return sorted;\n }),\n );\n result[PROP_TOOL_DEFINITIONS_HASH] = crypto\n .createHash('sha256')\n .update(canonicalSorted)\n .digest('hex')\n .slice(0, 16);\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let serialized = JSON.stringify(normalized);\n if (this.redactPii) serialized = redactPiiPatterns(serialized);\n serialized = this._applyCustomPatterns(serialized);\n result[PROP_TOOL_DEFINITIONS] =\n serialized.length > 10000 ? serialized.slice(0, 10000) : serialized;\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"privacy.js","names":["parts: string[]","result: Record<string, unknown>","textContent: string","sanitized: Record<string, unknown>","normalized: Array<Record<string, unknown>>","modeStr: string | null","sorted: Record<string, unknown>"],"sources":["../../src/core/privacy.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport { getLogger } from '../utils/logger.js';\nimport {\n PROP_HAS_REASONING,\n PROP_REASONING_CONTENT,\n PROP_REASONING_TOKENS,\n PROP_SYSTEM_PROMPT,\n PROP_SYSTEM_PROMPT_LENGTH,\n PROP_TOOL_DEFINITIONS,\n PROP_TOOL_DEFINITIONS_COUNT,\n PROP_TOOL_DEFINITIONS_HASH,\n} from './constants.js';\n\nexport const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';\nexport const REDACTED_CONTENT_PLACEHOLDER = '[content redacted]';\n\n// Legacy chunking constants — kept only so getTextFromLlmMessage() can\n// still read old chunked events. New events always use { text: content }.\nexport const MAX_CHUNK_SIZE = 1024;\nexport const MAX_CHUNKS = 8;\n\nconst VALID_CONTENT_MODES = new Set([\n 'full',\n 'metadata_only',\n 'customer_enriched',\n]);\n\n// PII regex patterns\nconst EMAIL_RE = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\nconst PHONE_RE = /\\b\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})\\b/g;\nconst CREDIT_CARD_RE = /\\b(?:\\d{4}[-\\s]?){3}\\d{4}\\b/g;\nconst SSN_RE = /\\b\\d{3}-\\d{2}-\\d{4}\\b/g;\nconst BASE64_DATA_URL_RE = /^data:([^;]+);base64,/;\nconst RAW_BASE64_RE = /^[A-Za-z0-9+/]+=*$/;\n\nexport function isBase64DataUrl(text: string): boolean {\n return BASE64_DATA_URL_RE.test(text);\n}\n\nexport function isValidUrl(text: string): boolean {\n try {\n const result = new URL(text);\n return Boolean(result.protocol && result.hostname);\n } catch {\n // not a valid absolute URL\n }\n return (\n text.startsWith('/') || text.startsWith('./') || text.startsWith('../')\n );\n}\n\nexport function isRawBase64(text: string): boolean {\n if (isValidUrl(text)) return false;\n return text.length > 20 && RAW_BASE64_RE.test(text);\n}\n\nexport function createContentHash(content: unknown): string {\n if (content == null) return '';\n const contentStr = typeof content === 'string' ? content : String(content);\n return crypto.createHash('sha256').update(contentStr, 'utf8').digest('hex');\n}\n\nexport function redactBase64Content(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n if (isBase64DataUrl(value)) return REDACTED_IMAGE_PLACEHOLDER;\n if (isRawBase64(value)) return REDACTED_IMAGE_PLACEHOLDER;\n return value;\n}\n\nexport function redactPiiPatterns(text: string): string {\n let result = text;\n result = result.replace(EMAIL_RE, '[email]');\n result = result.replace(PHONE_RE, '[phone]');\n result = result.replace(CREDIT_CARD_RE, '[credit_card]');\n result = result.replace(SSN_RE, '[ssn]');\n return result;\n}\n\nfunction extractTextFromStructuredContent(content: unknown): string {\n if (content == null) return '';\n if (typeof content === 'string') return content;\n\n if (typeof content === 'object' && !Array.isArray(content)) {\n const dict = content as Record<string, unknown>;\n for (const field of ['content', 'text', 'message']) {\n if (field in dict) return extractTextFromStructuredContent(dict[field]);\n }\n return String(content);\n }\n\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item === 'string') parts.push(item);\n else if (typeof item === 'object')\n parts.push(extractTextFromStructuredContent(item));\n else parts.push(String(item));\n }\n return parts.join('');\n }\n\n return String(content);\n}\n\n/**\n * Return the `$llm_message` payload for the given text.\n *\n * Content is stored as `{ text: content }` at full length — the Node SDK\n * does not truncate string properties, and Nova already whitelists\n * `$llm_message` server-side.\n *\n * Previous versions split long content into `c0`..`c7` chunks. That format\n * is still readable via {@link getTextFromLlmMessage} for backward\n * compatibility, but is no longer produced.\n */\nexport function chunkContent(text: string): Record<string, unknown> {\n return { text };\n}\n\nexport function getTextFromLlmMessage(\n llmMessage: Record<string, unknown>,\n): string {\n if ('text' in llmMessage) return String(llmMessage.text);\n const n = llmMessage.n;\n if (typeof n === 'number' && n > 0) {\n const parts: string[] = [];\n for (let i = 0; i < n; i++) {\n parts.push(String(llmMessage[`c${i}`] ?? ''));\n }\n return parts.join('');\n }\n return '';\n}\n\nexport function sanitizeAnyContent(\n content: unknown,\n privacyMode = false,\n redactPii = true,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n if (content == null) return result;\n\n let textContent: string;\n if (typeof content === 'string') {\n textContent = content;\n } else if (typeof content === 'object') {\n textContent = extractTextFromStructuredContent(content);\n } else {\n textContent = String(content);\n }\n\n // Tool-call-only LLM responses have content=null which the provider\n // coerces to ''. Emitting $llm_message with an empty string causes\n // the response to appear as \"missing text\" in the thread view.\n if (textContent.length === 0) return result;\n\n if (redactPii) {\n textContent = redactPiiPatterns(textContent);\n const redacted = redactBase64Content(textContent);\n if (typeof redacted === 'string') textContent = redacted;\n }\n\n if (privacyMode) {\n result.content_hash = createContentHash(textContent);\n } else {\n result.$llm_message = chunkContent(textContent);\n }\n\n return result;\n}\n\nexport function sanitizeStructuredContent(\n content: unknown,\n redactPii: boolean,\n): unknown {\n if (typeof content === 'string') {\n let text = content;\n if (redactPii) text = redactPiiPatterns(text);\n return redactBase64Content(text);\n }\n\n if (\n content != null &&\n typeof content === 'object' &&\n !Array.isArray(content)\n ) {\n const dict = content as Record<string, unknown>;\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(dict)) {\n sanitized[key] = sanitizeStructuredContent(value, redactPii);\n }\n return sanitized;\n }\n\n if (Array.isArray(content)) {\n return content.map((item) => sanitizeStructuredContent(item, redactPii));\n }\n\n return content;\n}\n\n/**\n * Normalize tool definitions from various provider formats into a canonical shape:\n * `[{ name, description, parameters }]`.\n */\nexport function normalizeToolDefinitions(\n toolDefinitions: Array<Record<string, unknown>>,\n): Array<Record<string, unknown>> {\n const normalized: Array<Record<string, unknown>> = [];\n for (const tool of toolDefinitions) {\n if (tool == null || typeof tool !== 'object') continue;\n\n // OpenAI Chat format: { type: \"function\", function: { name, description, parameters } }\n const fn = tool.function;\n if (fn != null && typeof fn === 'object') {\n const f = fn as Record<string, unknown>;\n normalized.push({\n name: f.name ?? '',\n description: f.description ?? '',\n parameters: f.parameters ?? null,\n });\n continue;\n }\n\n // Anthropic format: { name, description, input_schema }\n if ('input_schema' in tool) {\n normalized.push({\n name: tool.name ?? '',\n description: tool.description ?? '',\n parameters: tool.input_schema ?? null,\n });\n continue;\n }\n\n // Bedrock format: { toolSpec: { name, description, inputSchema } }\n const toolSpec = tool.toolSpec;\n if (toolSpec != null && typeof toolSpec === 'object') {\n const ts = toolSpec as Record<string, unknown>;\n normalized.push({\n name: ts.name ?? '',\n description: ts.description ?? '',\n parameters: ts.inputSchema ?? null,\n });\n continue;\n }\n\n // Gemini format: { function_declarations: [{ name, description, parameters }] }\n const fnDecls = tool.function_declarations;\n if (Array.isArray(fnDecls)) {\n for (const decl of fnDecls) {\n if (decl != null && typeof decl === 'object') {\n const d = decl as Record<string, unknown>;\n normalized.push({\n name: d.name ?? '',\n description: d.description ?? '',\n parameters: d.parameters ?? null,\n });\n }\n }\n continue;\n }\n\n // Generic / OpenAI Responses format: { name, description, parameters }\n if ('name' in tool) {\n normalized.push({\n name: tool.name ?? '',\n description: tool.description ?? '',\n parameters: tool.parameters ?? null,\n });\n }\n }\n return normalized;\n}\n\nexport interface PrivacyConfigOptions {\n privacyMode?: boolean;\n redactPii?: boolean;\n customRedactionPatterns?: string[];\n contentMode?: string | null;\n validate?: boolean;\n debug?: boolean;\n}\n\nexport class PrivacyConfig {\n readonly privacyMode: boolean;\n readonly redactPii: boolean;\n readonly validate: boolean;\n readonly debug: boolean;\n readonly customPatterns: string[];\n private readonly _compiledCustomPatterns: RegExp[];\n private readonly _contentMode: string | null;\n\n constructor(options: PrivacyConfigOptions = {}) {\n this.privacyMode = options.privacyMode ?? false;\n this.redactPii = options.redactPii ?? false;\n this.validate = options.validate ?? false;\n this.debug = options.debug ?? false;\n this.customPatterns = options.customRedactionPatterns ?? [];\n this._compiledCustomPatterns = [];\n\n for (const pattern of this.customPatterns) {\n try {\n this._compiledCustomPatterns.push(new RegExp(pattern, 'g'));\n } catch (e) {\n getLogger().warn(\n `Invalid custom redaction regex \"${pattern}\": ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n }\n\n let modeStr: string | null = null;\n if (options.contentMode != null) {\n modeStr = String(options.contentMode);\n if (!VALID_CONTENT_MODES.has(modeStr)) {\n throw new Error(\n `Invalid content_mode \"${options.contentMode}\". ` +\n `Must be one of: ${[...VALID_CONTENT_MODES].sort().join(', ')}`,\n );\n }\n }\n this._contentMode = modeStr;\n }\n\n get contentMode(): string | null {\n return this._contentMode;\n }\n\n private _applyCustomPatterns(text: string): string {\n if (!this._compiledCustomPatterns.length || typeof text !== 'string') {\n return text;\n }\n let result = text;\n for (const pattern of this._compiledCustomPatterns) {\n try {\n result = result.replace(pattern, '[REDACTED]');\n } catch (e) {\n getLogger().warn(\n `Invalid custom redaction regex \"${pattern.source}\": ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n }\n return result;\n }\n\n private _applyCustomPatternsToLlmMessage(\n llmMessage: Record<string, unknown>,\n ): void {\n if ('text' in llmMessage) {\n llmMessage.text = this._applyCustomPatterns(String(llmMessage.text));\n return;\n }\n\n const n = llmMessage.n;\n if (typeof n === 'number' && n > 0) {\n for (let i = 0; i < n; i++) {\n const key = `c${i}`;\n if (key in llmMessage) {\n llmMessage[key] = this._applyCustomPatterns(\n String(llmMessage[key] ?? ''),\n );\n }\n }\n }\n }\n\n sanitizeContent(content: unknown): Record<string, unknown> {\n if (this._contentMode == null) {\n if (this.privacyMode) return {};\n const result = sanitizeAnyContent(content, false, this.redactPii);\n if (this.customPatterns.length && '$llm_message' in result) {\n const msg = result.$llm_message as Record<string, unknown>;\n this._applyCustomPatternsToLlmMessage(msg);\n }\n return result;\n }\n\n if (this._contentMode === 'full') {\n const result = sanitizeAnyContent(content, false, this.redactPii);\n if (this.customPatterns.length && '$llm_message' in result) {\n const msg = result.$llm_message as Record<string, unknown>;\n this._applyCustomPatternsToLlmMessage(msg);\n }\n return result;\n }\n\n // metadata_only, customer_enriched → no content\n return {};\n }\n\n sanitizeSystemPrompt(systemPrompt: string | null): Record<string, unknown> {\n if (!systemPrompt) return {};\n\n const result: Record<string, unknown> = {\n [PROP_SYSTEM_PROMPT_LENGTH]: systemPrompt.length,\n };\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let sanitized = systemPrompt;\n if (this.redactPii) sanitized = redactPiiPatterns(sanitized);\n sanitized = this._applyCustomPatterns(sanitized);\n result[PROP_SYSTEM_PROMPT] =\n sanitized.length > 10000 ? sanitized.slice(0, 10000) : sanitized;\n }\n\n return result;\n }\n\n sanitizeReasoningContent(\n reasoningContent: string | null,\n reasoningTokens?: number | null,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n const hasReasoning =\n Boolean(reasoningContent) ||\n (reasoningTokens != null && reasoningTokens > 0);\n if (!hasReasoning && reasoningTokens == null) return result;\n\n if (hasReasoning) result[PROP_HAS_REASONING] = true;\n if (reasoningTokens != null)\n result[PROP_REASONING_TOKENS] = reasoningTokens;\n if (!hasReasoning || reasoningContent == null) return result;\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let sanitized = reasoningContent;\n if (this.redactPii) sanitized = redactPiiPatterns(sanitized);\n sanitized = this._applyCustomPatterns(sanitized);\n result[PROP_REASONING_CONTENT] =\n sanitized.length > 10000 ? sanitized.slice(0, 10000) : sanitized;\n }\n\n return result;\n }\n\n sanitizeToolDefinitions(\n toolDefinitions: Array<Record<string, unknown>> | null | undefined,\n ): Record<string, unknown> {\n if (!toolDefinitions?.length) return {};\n\n const normalized = normalizeToolDefinitions(toolDefinitions);\n const result: Record<string, unknown> = {\n [PROP_TOOL_DEFINITIONS_COUNT]: normalized.length,\n };\n\n const canonicalSorted = JSON.stringify(\n normalized.map((t) => {\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(t).sort()) sorted[key] = t[key];\n return sorted;\n }),\n );\n result[PROP_TOOL_DEFINITIONS_HASH] = crypto\n .createHash('sha256')\n .update(canonicalSorted)\n .digest('hex')\n .slice(0, 16);\n\n let mode = this._contentMode;\n if (mode == null) mode = this.privacyMode ? 'metadata_only' : 'full';\n\n if (mode === 'full') {\n let serialized = JSON.stringify(normalized);\n if (this.redactPii) serialized = redactPiiPatterns(serialized);\n serialized = this._applyCustomPatterns(serialized);\n result[PROP_TOOL_DEFINITIONS] =\n serialized.length > 10000 ? serialized.slice(0, 10000) : serialized;\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","names":[],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":[],"mappings":";;;;;;AAyBM,cADO,mBACW,EAAM,OAAA;AAI9B,cAJM,gBAI2B,EAJT,MAKX,CAAA,MAAA,EAAA,OAEK,CAAA,GAAA,IAAA;AAOA,UAVD,gBAAA,CAUC;EAA0B,SAAA,EAT/B,aAS+B;EAGvB,MAAA,CAAA,EAAA,MAAA;EAGE,aAAA,CAAA,EAbL,aAaK,GAAA,IAAA;EAmCP,gBAAA,CAAA,EAAA,OAAA;EAxCN;EAAc,eAAA,CAAA,EAAA,OAAA;AA6CxB;AACa,cAhDA,SAgDA,CAAA,gBA/CK,MA+CL,CAAA,MAAA,EAAA,OAAA,CAAA,GA/C+B,MA+C/B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,SA9CH,cAAA,CA8CG;EAQA,QAAA,OAAA;EACE,SAAA,QAAA,EArDM,eAqDN;EACI,QAAA,iBAAA;EAeP,WAAA,CAAA,OAAA,EAlEW,gBAkEX;EACa,IAAA,MAAA,CAAA,CAAA,EAhCT,OAgCS;;AACQ,cA5BpB,eAAA,CA4BoB;EAA5B,SAAA,EA3BQ,MA2BR,CAAA,MAAA,EAAA,OAAA,CAAA;EAAO,QAAA,QAAA;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","names":[],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":[],"mappings":";;;;;;AAyBM,cADO,mBACW,EAAM,OAAA;AAI9B,cAJM,gBAI2B,EAJT,MAKX,CAAA,MAAA,EAAA,OAEK,CAAA,GAAA,IAAA;AAOA,UAVD,gBAAA,CAUC;EAA0B,SAAA,EAT/B,aAS+B;EAGvB,MAAA,CAAA,EAAA,MAAA;EAGE,aAAA,CAAA,EAbL,aAaK,GAAA,IAAA;EAmCP,gBAAA,CAAA,EAAA,OAAA;EAxCN;EAAc,eAAA,CAAA,EAAA,OAAA;AA6CxB;AACa,cAhDA,SAgDA,CAAA,gBA/CK,MA+CL,CAAA,MAAA,EAAA,OAAA,CAAA,GA/C+B,MA+C/B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,SA9CH,cAAA,CA8CG;EAQA,QAAA,OAAA;EACE,SAAA,QAAA,EArDM,eAqDN;EACI,QAAA,iBAAA;EAeP,WAAA,CAAA,OAAA,EAlEW,gBAkEX;EACa,IAAA,MAAA,CAAA,CAAA,EAhCT,OAgCS;;AACQ,cA5BpB,eAAA,CA4BoB;EAA5B,SAAA,EA3BQ,MA2BR,CAAA,MAAA,EAAA,OAAA,CAAA;EAAO,QAAA,QAAA;EAkTI,QAAA,UAAA;EAmBA,QAAA,cAAA;EACC,QAAA,iBAAA;EAAN,WAAA,CAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAzVE,OAyVF,EAAA,SAAA,EAxVI,aAwVJ,EAAA,aAAA,EAvVQ,aAuVR,GAAA,IAAA,EAAA,gBAAA,EAAA,OAAA;EAIQ,MAAA,CAAA,MAAA,EA5UP,MA4UO,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,kBAAA,CAAA,EA3UM,oBA2UN,CAAA,EA1Ud,OA0Uc,CA1UN,iBA0UM,GA1Uc,aA0Ud,CAAA,OAAA,CAAA,CAAA;EAAN,QAAA,WAAA;EAAK,QAAA,mBAAA;;;iBAxBF,4BAAA;iBAmBA,uBAAA,UACL,MAAM;;;aAIJ,MAAM"}
|
|
@@ -209,7 +209,9 @@ var WrappedMessages = class {
|
|
|
209
209
|
if (!shouldTrackInputMessages) return;
|
|
210
210
|
if (ctx.userId == null || ctx.sessionId == null) return;
|
|
211
211
|
if (!Array.isArray(messages)) return;
|
|
212
|
-
|
|
212
|
+
const lastReplyIdx = messages.findLastIndex((m) => m?.role === "assistant");
|
|
213
|
+
const newMessages = messages.slice(lastReplyIdx + 1);
|
|
214
|
+
for (const msg of newMessages) {
|
|
213
215
|
if (msg?.role !== "user") continue;
|
|
214
216
|
const rawContent = msg?.content;
|
|
215
217
|
const content = Array.isArray(rawContent) ? rawContent.map((part) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","names":["_AnthropicModule: Record<string, unknown> | null","clientOpts: Record<string, unknown>","costUsd: number | null","reasoning: string | undefined","toolCalls: Array<Record<string, unknown>>"],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":["/**\n * Anthropic provider wrapper with automatic tracking.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { trackUserMessage } from '../core/tracking.js';\nimport { getDefaultPropagateContext, injectContext } from '../propagation.js';\nimport type {\n AmplitudeLike,\n AmplitudeOrAI,\n AnthropicResponse,\n TrackFn,\n} from '../types.js';\nimport { calculateCost } from '../utils/costs.js';\nimport { tryRequire } from '../utils/resolve-module.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\nimport {\n applySessionContext,\n BaseAIProvider,\n contextFields,\n type ProviderTrackOptions,\n} from './base.js';\n\nconst _resolved = tryRequire('@anthropic-ai/sdk');\nexport const ANTHROPIC_AVAILABLE = _resolved != null;\nconst _AnthropicModule: Record<string, unknown> | null = _resolved;\n\nexport { _AnthropicModule };\n\nexport interface AnthropicOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n privacyConfig?: PrivacyConfig | null;\n propagateContext?: boolean;\n /** Pass the `@anthropic-ai/sdk` module directly to bypass `tryRequire` (required in bundler environments). */\n anthropicModule?: unknown;\n}\n\nexport class Anthropic<\n TClient extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseAIProvider {\n private _client: TClient;\n readonly messages: WrappedMessages;\n private _propagateContext: boolean;\n\n constructor(options: AnthropicOptions) {\n super({\n amplitude: options.amplitude,\n privacyConfig: options.privacyConfig,\n providerName: 'anthropic',\n });\n\n const mod =\n (options.anthropicModule as Record<string, unknown> | null) ??\n _AnthropicModule;\n if (mod == null) {\n throw new Error(\n '@anthropic-ai/sdk package is required. Install it with: npm install @anthropic-ai/sdk — or pass the module directly via the anthropicModule option.',\n );\n }\n\n const AnthropicSDK = mod.Anthropic as new (\n opts: Record<string, unknown>,\n ) => unknown;\n\n const clientOpts: Record<string, unknown> = {};\n if (options.apiKey) clientOpts.apiKey = options.apiKey;\n\n this._client = new AnthropicSDK(clientOpts) as TClient;\n this._propagateContext =\n options.propagateContext ?? getDefaultPropagateContext();\n this.messages = new WrappedMessages(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n }\n\n get client(): TClient {\n return this._client;\n }\n}\n\nexport class WrappedMessages {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n ) {\n const clientObj = client as Record<string, unknown>;\n this._original = clientObj.messages as Record<string, unknown>;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<AnthropicResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.messages as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n\n const resp = response as AnthropicResponse;\n const usage = resp.usage;\n const extracted = extractAnthropicContent(\n resp.content as unknown as Array<Record<string, unknown>> | undefined,\n );\n const firstTextBlock = resp.content?.find((b) => b.type === 'text');\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n\n const cacheRead = usage?.cache_read_input_tokens ?? 0;\n const cacheCreation = usage?.cache_creation_input_tokens ?? 0;\n const rawInput = usage?.input_tokens ?? 0;\n const normalizedInput =\n cacheRead || cacheCreation\n ? rawInput + cacheRead + cacheCreation\n : rawInput;\n\n let costUsd: number | null = null;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: normalizedInput,\n outputTokens: usage.output_tokens,\n cacheReadInputTokens: cacheRead,\n cacheCreationInputTokens: cacheCreation,\n defaultProvider: 'anthropic',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: 'anthropic',\n responseContent: String(firstTextBlock?.text ?? ''),\n reasoningContent: extracted.reasoning,\n latencyMs,\n inputTokens: normalizedInput || undefined,\n outputTokens: usage?.output_tokens,\n cacheReadInputTokens: cacheRead || undefined,\n cacheCreationInputTokens: cacheCreation || undefined,\n totalCostUsd: costUsd,\n finishReason: resp.stop_reason,\n toolCalls:\n extracted.toolCalls.length > 0 ? extracted.toolCalls : undefined,\n isStreaming: false,\n toolDefinitions: extractAnthropicToolDefinitions(requestParams),\n systemPrompt: extractAnthropicSystemPrompt(requestParams.system),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as AnthropicResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: 'anthropic',\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n let reasoningContent = '';\n\n try {\n for await (const event of stream) {\n const evt = event as Record<string, unknown>;\n const type = evt.type as string | undefined;\n\n if (type === 'content_block_delta') {\n const delta = evt.delta as Record<string, unknown> | undefined;\n if (delta?.type === 'text_delta' && delta.text != null) {\n accumulator.addContent(String(delta.text));\n } else if (\n delta?.type === 'thinking_delta' &&\n delta.thinking != null\n ) {\n reasoningContent += String(delta.thinking);\n }\n } else if (type === 'content_block_start') {\n const block = evt.content_block as\n | Record<string, unknown>\n | undefined;\n if (block?.type === 'tool_use') {\n accumulator.addToolCall({\n type: 'function',\n id: block.id,\n function: {\n name: String(block.name ?? ''),\n arguments:\n typeof block.input === 'string'\n ? block.input\n : JSON.stringify(block.input ?? {}),\n },\n });\n }\n } else if (type === 'message_delta') {\n const delta = evt.delta as Record<string, unknown> | undefined;\n if (delta?.stop_reason != null) {\n accumulator.finishReason = String(delta.stop_reason);\n }\n const usage = evt.usage as Record<string, number> | undefined;\n if (usage != null) {\n accumulator.setUsage({\n outputTokens: usage.output_tokens,\n });\n }\n } else if (type === 'message_start') {\n const message = evt.message as Record<string, unknown> | undefined;\n if (message?.model != null) {\n accumulator.model = String(message.model);\n }\n const usage = message?.usage as Record<string, number> | undefined;\n if (usage != null) {\n accumulator.setUsage({\n inputTokens: usage.input_tokens,\n cacheReadTokens: usage.cache_read_input_tokens,\n cacheCreationTokens: usage.cache_creation_input_tokens,\n });\n }\n }\n\n yield event;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n const modelName = String(accumulator.model ?? params.model ?? 'unknown');\n\n const streamCacheRead = state.cacheReadTokens ?? 0;\n const streamCacheCreation = state.cacheCreationTokens ?? 0;\n const streamRawInput = state.inputTokens ?? 0;\n const streamNormalizedInput =\n streamCacheRead || streamCacheCreation\n ? streamRawInput + streamCacheRead + streamCacheCreation\n : streamRawInput;\n\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: streamNormalizedInput,\n outputTokens: state.outputTokens,\n cacheReadInputTokens: streamCacheRead,\n cacheCreationInputTokens: streamCacheCreation,\n defaultProvider: 'anthropic',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName,\n provider: 'anthropic',\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: streamNormalizedInput || undefined,\n outputTokens: state.outputTokens,\n cacheReadInputTokens: streamCacheRead || undefined,\n cacheCreationInputTokens: streamCacheCreation || undefined,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : undefined,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n reasoningContent: reasoningContent || undefined,\n toolDefinitions: extractAnthropicToolDefinitions(params),\n systemPrompt: extractAnthropicSystemPrompt(params.system),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n messages: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n if (!Array.isArray(messages)) return;\n for (const msg of messages) {\n const role = (msg as Record<string, unknown>)?.role;\n if (role !== 'user') continue;\n const rawContent = (msg as Record<string, unknown>)?.content;\n const content = Array.isArray(rawContent)\n ? rawContent\n .map((part) => {\n if (typeof part === 'string') return part;\n const text = (part as Record<string, unknown>)?.text;\n return typeof text === 'string' ? text : '';\n })\n .join('')\n : typeof rawContent === 'string'\n ? rawContent\n : '';\n if (!content) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: content,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nfunction _isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n value != null &&\n typeof (value as Record<symbol, unknown>)[Symbol.asyncIterator] ===\n 'function'\n );\n}\n\nexport function extractAnthropicSystemPrompt(\n system: unknown,\n): string | undefined {\n if (typeof system === 'string') return system;\n if (Array.isArray(system)) {\n return system\n .map((block) => {\n if (typeof block === 'string') return block;\n if (typeof block === 'object' && block != null) {\n return String((block as Record<string, unknown>).text ?? '');\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n }\n return undefined;\n}\n\nexport function extractAnthropicContent(\n content: Array<Record<string, unknown>> | undefined,\n): {\n text: string;\n reasoning: string | undefined;\n toolCalls: Array<Record<string, unknown>>;\n} {\n let text = '';\n let reasoning: string | undefined;\n const toolCalls: Array<Record<string, unknown>> = [];\n\n if (!content) return { text, reasoning, toolCalls };\n\n for (const block of content) {\n if (block.type === 'text') {\n text += String(block.text ?? '');\n } else if (block.type === 'thinking') {\n reasoning = String(block.thinking ?? '');\n } else if (block.type === 'tool_use') {\n toolCalls.push({\n type: 'function',\n id: block.id,\n function: {\n name: String(block.name ?? ''),\n arguments:\n typeof block.input === 'string'\n ? block.input\n : JSON.stringify(block.input ?? {}),\n },\n });\n }\n }\n\n return { text, reasoning, toolCalls };\n}\n\nfunction extractAnthropicToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"anthropic.js","names":["_AnthropicModule: Record<string, unknown> | null","clientOpts: Record<string, unknown>","costUsd: number | null","reasoning: string | undefined","toolCalls: Array<Record<string, unknown>>"],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":["/**\n * Anthropic provider wrapper with automatic tracking.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { trackUserMessage } from '../core/tracking.js';\nimport { getDefaultPropagateContext, injectContext } from '../propagation.js';\nimport type {\n AmplitudeLike,\n AmplitudeOrAI,\n AnthropicResponse,\n TrackFn,\n} from '../types.js';\nimport { calculateCost } from '../utils/costs.js';\nimport { tryRequire } from '../utils/resolve-module.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\nimport {\n applySessionContext,\n BaseAIProvider,\n contextFields,\n type ProviderTrackOptions,\n} from './base.js';\n\nconst _resolved = tryRequire('@anthropic-ai/sdk');\nexport const ANTHROPIC_AVAILABLE = _resolved != null;\nconst _AnthropicModule: Record<string, unknown> | null = _resolved;\n\nexport { _AnthropicModule };\n\nexport interface AnthropicOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n privacyConfig?: PrivacyConfig | null;\n propagateContext?: boolean;\n /** Pass the `@anthropic-ai/sdk` module directly to bypass `tryRequire` (required in bundler environments). */\n anthropicModule?: unknown;\n}\n\nexport class Anthropic<\n TClient extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseAIProvider {\n private _client: TClient;\n readonly messages: WrappedMessages;\n private _propagateContext: boolean;\n\n constructor(options: AnthropicOptions) {\n super({\n amplitude: options.amplitude,\n privacyConfig: options.privacyConfig,\n providerName: 'anthropic',\n });\n\n const mod =\n (options.anthropicModule as Record<string, unknown> | null) ??\n _AnthropicModule;\n if (mod == null) {\n throw new Error(\n '@anthropic-ai/sdk package is required. Install it with: npm install @anthropic-ai/sdk — or pass the module directly via the anthropicModule option.',\n );\n }\n\n const AnthropicSDK = mod.Anthropic as new (\n opts: Record<string, unknown>,\n ) => unknown;\n\n const clientOpts: Record<string, unknown> = {};\n if (options.apiKey) clientOpts.apiKey = options.apiKey;\n\n this._client = new AnthropicSDK(clientOpts) as TClient;\n this._propagateContext =\n options.propagateContext ?? getDefaultPropagateContext();\n this.messages = new WrappedMessages(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n }\n\n get client(): TClient {\n return this._client;\n }\n}\n\nexport class WrappedMessages {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n ) {\n const clientObj = client as Record<string, unknown>;\n this._original = clientObj.messages as Record<string, unknown>;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<AnthropicResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.messages as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n\n const resp = response as AnthropicResponse;\n const usage = resp.usage;\n const extracted = extractAnthropicContent(\n resp.content as unknown as Array<Record<string, unknown>> | undefined,\n );\n const firstTextBlock = resp.content?.find((b) => b.type === 'text');\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n\n const cacheRead = usage?.cache_read_input_tokens ?? 0;\n const cacheCreation = usage?.cache_creation_input_tokens ?? 0;\n const rawInput = usage?.input_tokens ?? 0;\n const normalizedInput =\n cacheRead || cacheCreation\n ? rawInput + cacheRead + cacheCreation\n : rawInput;\n\n let costUsd: number | null = null;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: normalizedInput,\n outputTokens: usage.output_tokens,\n cacheReadInputTokens: cacheRead,\n cacheCreationInputTokens: cacheCreation,\n defaultProvider: 'anthropic',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: 'anthropic',\n responseContent: String(firstTextBlock?.text ?? ''),\n reasoningContent: extracted.reasoning,\n latencyMs,\n inputTokens: normalizedInput || undefined,\n outputTokens: usage?.output_tokens,\n cacheReadInputTokens: cacheRead || undefined,\n cacheCreationInputTokens: cacheCreation || undefined,\n totalCostUsd: costUsd,\n finishReason: resp.stop_reason,\n toolCalls:\n extracted.toolCalls.length > 0 ? extracted.toolCalls : undefined,\n isStreaming: false,\n toolDefinitions: extractAnthropicToolDefinitions(requestParams),\n systemPrompt: extractAnthropicSystemPrompt(requestParams.system),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as AnthropicResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: 'anthropic',\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n let reasoningContent = '';\n\n try {\n for await (const event of stream) {\n const evt = event as Record<string, unknown>;\n const type = evt.type as string | undefined;\n\n if (type === 'content_block_delta') {\n const delta = evt.delta as Record<string, unknown> | undefined;\n if (delta?.type === 'text_delta' && delta.text != null) {\n accumulator.addContent(String(delta.text));\n } else if (\n delta?.type === 'thinking_delta' &&\n delta.thinking != null\n ) {\n reasoningContent += String(delta.thinking);\n }\n } else if (type === 'content_block_start') {\n const block = evt.content_block as\n | Record<string, unknown>\n | undefined;\n if (block?.type === 'tool_use') {\n accumulator.addToolCall({\n type: 'function',\n id: block.id,\n function: {\n name: String(block.name ?? ''),\n arguments:\n typeof block.input === 'string'\n ? block.input\n : JSON.stringify(block.input ?? {}),\n },\n });\n }\n } else if (type === 'message_delta') {\n const delta = evt.delta as Record<string, unknown> | undefined;\n if (delta?.stop_reason != null) {\n accumulator.finishReason = String(delta.stop_reason);\n }\n const usage = evt.usage as Record<string, number> | undefined;\n if (usage != null) {\n accumulator.setUsage({\n outputTokens: usage.output_tokens,\n });\n }\n } else if (type === 'message_start') {\n const message = evt.message as Record<string, unknown> | undefined;\n if (message?.model != null) {\n accumulator.model = String(message.model);\n }\n const usage = message?.usage as Record<string, number> | undefined;\n if (usage != null) {\n accumulator.setUsage({\n inputTokens: usage.input_tokens,\n cacheReadTokens: usage.cache_read_input_tokens,\n cacheCreationTokens: usage.cache_creation_input_tokens,\n });\n }\n }\n\n yield event;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n const modelName = String(accumulator.model ?? params.model ?? 'unknown');\n\n const streamCacheRead = state.cacheReadTokens ?? 0;\n const streamCacheCreation = state.cacheCreationTokens ?? 0;\n const streamRawInput = state.inputTokens ?? 0;\n const streamNormalizedInput =\n streamCacheRead || streamCacheCreation\n ? streamRawInput + streamCacheRead + streamCacheCreation\n : streamRawInput;\n\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: streamNormalizedInput,\n outputTokens: state.outputTokens,\n cacheReadInputTokens: streamCacheRead,\n cacheCreationInputTokens: streamCacheCreation,\n defaultProvider: 'anthropic',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName,\n provider: 'anthropic',\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: streamNormalizedInput || undefined,\n outputTokens: state.outputTokens,\n cacheReadInputTokens: streamCacheRead || undefined,\n cacheCreationInputTokens: streamCacheCreation || undefined,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : undefined,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n reasoningContent: reasoningContent || undefined,\n toolDefinitions: extractAnthropicToolDefinitions(params),\n systemPrompt: extractAnthropicSystemPrompt(params.system),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n messages: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n if (!Array.isArray(messages)) return;\n\n // In agent loops each create() re-sends the full conversation.\n // Only track user messages appended after the last assistant reply\n // so the same message isn't autotracked on every iteration.\n const lastReplyIdx = (messages as Record<string, unknown>[]).findLastIndex(\n (m) => m?.role === 'assistant',\n );\n const newMessages = (messages as Record<string, unknown>[]).slice(lastReplyIdx + 1);\n\n for (const msg of newMessages) {\n const role = (msg as Record<string, unknown>)?.role;\n if (role !== 'user') continue;\n const rawContent = (msg as Record<string, unknown>)?.content;\n const content = Array.isArray(rawContent)\n ? rawContent\n .map((part) => {\n if (typeof part === 'string') return part;\n const text = (part as Record<string, unknown>)?.text;\n return typeof text === 'string' ? text : '';\n })\n .join('')\n : typeof rawContent === 'string'\n ? rawContent\n : '';\n if (!content) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: content,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nfunction _isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n value != null &&\n typeof (value as Record<symbol, unknown>)[Symbol.asyncIterator] ===\n 'function'\n );\n}\n\nexport function extractAnthropicSystemPrompt(\n system: unknown,\n): string | undefined {\n if (typeof system === 'string') return system;\n if (Array.isArray(system)) {\n return system\n .map((block) => {\n if (typeof block === 'string') return block;\n if (typeof block === 'object' && block != null) {\n return String((block as Record<string, unknown>).text ?? '');\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n }\n return undefined;\n}\n\nexport function extractAnthropicContent(\n content: Array<Record<string, unknown>> | undefined,\n): {\n text: string;\n reasoning: string | undefined;\n toolCalls: Array<Record<string, unknown>>;\n} {\n let text = '';\n let reasoning: string | undefined;\n const toolCalls: Array<Record<string, unknown>> = [];\n\n if (!content) return { text, reasoning, toolCalls };\n\n for (const block of content) {\n if (block.type === 'text') {\n text += String(block.text ?? '');\n } else if (block.type === 'thinking') {\n reasoning = String(block.thinking ?? '');\n } else if (block.type === 'tool_use') {\n toolCalls.push({\n type: 'function',\n id: block.id,\n function: {\n name: String(block.name ?? ''),\n arguments:\n typeof block.input === 'string'\n ? block.input\n : JSON.stringify(block.input ?? {}),\n },\n });\n }\n }\n\n return { text, reasoning, toolCalls };\n}\n\nfunction extractAnthropicToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n"],"mappings":";;;;;;;;AAuBA,MAAM,YAAY,WAAW,oBAAoB;AACjD,MAAa,sBAAsB,aAAa;AAChD,MAAMA,mBAAmD;AAazD,IAAa,YAAb,cAEU,eAAe;CACvB,AAAQ;CACR,AAAS;CACT,AAAQ;CAER,YAAY,SAA2B;AACrC,QAAM;GACJ,WAAW,QAAQ;GACnB,eAAe,QAAQ;GACvB,cAAc;GACf,CAAC;EAEF,MAAM,MACH,QAAQ,mBACT;AACF,MAAI,OAAO,KACT,OAAM,IAAI,MACR,sJACD;EAGH,MAAM,eAAe,IAAI;EAIzB,MAAMC,aAAsC,EAAE;AAC9C,MAAI,QAAQ,OAAQ,YAAW,SAAS,QAAQ;AAEhD,OAAK,UAAU,IAAI,aAAa,WAAW;AAC3C,OAAK,oBACH,QAAQ,oBAAoB,4BAA4B;AAC1D,OAAK,WAAW,IAAI,gBAClB,KAAK,SACL,KAAK,SAAS,EACd,KAAK,YACL,KAAK,gBACL,KAAK,kBACN;;CAGH,IAAI,SAAkB;AACpB,SAAO,KAAK;;;AAIhB,IAAa,kBAAb,MAA6B;CAC3B;CACA,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YACE,QACA,SACA,WACA,eACA,kBACA;AAEA,OAAK,YADa,OACS;AAC3B,OAAK,WACH,OAAO,YAAY,aACf,UACC,QAA8C,SAAS;AAC9D,OAAK,aAAa;AAClB,OAAK,iBAAiB;AACtB,OAAK,oBAAoB;;CAG3B,MAAM,OACJ,QACA,oBACqD;EACrD,MAAM,WAAW,KAAK,UAAU;EAGhC,MAAM,YAAY,YAAY,KAAK;EACnC,MAAM,gBAAgB,KAAK,oBAAoB,OAAO;EACtD,MAAM,MAAM,oBAAoB,mBAAmB;AAEnD,MAAI;AACF,QAAK,oBACH,cAAc,UACd,KACA,oBAAoB,sBAAsB,KAC3C;GACD,MAAM,WAAW,MAAM,SAAS,KAAK,KAAK,WAAW,cAAc;AAEnE,OAAI,cAAc,WAAW,QAAQ,iBAAiB,SAAS,CAC7D,QAAO,KAAK,YACV,UACA,eACA,WACA,IACD;GAGH,MAAM,YAAY,YAAY,KAAK,GAAG;GAEtC,MAAM,OAAO;GACb,MAAM,QAAQ,KAAK;GACnB,MAAM,YAAY,wBAChB,KAAK,QACN;GACD,MAAM,iBAAiB,KAAK,SAAS,MAAM,MAAM,EAAE,SAAS,OAAO;GACnE,MAAM,YAAY,OAAO,KAAK,SAAS,cAAc,SAAS,UAAU;GAExE,MAAM,YAAY,OAAO,2BAA2B;GACpD,MAAM,gBAAgB,OAAO,+BAA+B;GAC5D,MAAM,WAAW,OAAO,gBAAgB;GACxC,MAAM,kBACJ,aAAa,gBACT,WAAW,YAAY,gBACvB;GAEN,IAAIC,UAAyB;AAC7B,OAAI,OAAO,gBAAgB,QAAQ,OAAO,iBAAiB,KACzD,KAAI;AACF,cAAU,cAAc;KACtB;KACA,aAAa;KACb,cAAc,MAAM;KACpB,sBAAsB;KACtB,0BAA0B;KAC1B,iBAAiB;KAClB,CAAC;WACI;AAKV,QAAK,SAAS;IACZ,GAAG,cAAc,IAAI;IACrB;IACA,UAAU;IACV,iBAAiB,OAAO,gBAAgB,QAAQ,GAAG;IACnD,kBAAkB,UAAU;IAC5B;IACA,aAAa,mBAAmB;IAChC,cAAc,OAAO;IACrB,sBAAsB,aAAa;IACnC,0BAA0B,iBAAiB;IAC3C,cAAc;IACd,cAAc,KAAK;IACnB,WACE,UAAU,UAAU,SAAS,IAAI,UAAU,YAAY;IACzD,aAAa;IACb,iBAAiB,gCAAgC,cAAc;IAC/D,cAAc,6BAA6B,cAAc,OAAO;IAChE,aAAa,cAAc;IAC3B,iBAAiB,cAAc;IAC/B,MAAM,cAAc;IACrB,CAAC;AAEF,UAAO;WACA,OAAO;GACd,MAAM,YAAY,YAAY,KAAK,GAAG;AACtC,QAAK,SAAS;IACZ,GAAG,cAAc,IAAI;IACrB,WAAW,OAAO,cAAc,SAAS,UAAU;IACnD,UAAU;IACV,iBAAiB;IACjB;IACA,SAAS;IACT,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IACrE,CAAC;AAEF,SAAM;;;CAIV,OAAe,YACb,QACA,QACA,YACA,YACyB;EACzB,MAAM,cAAc,IAAI,sBAAsB;AAC9C,cAAY,QAAQ,OAAO,OAAO,SAAS,UAAU;EACrD,IAAI,mBAAmB;AAEvB,MAAI;AACF,cAAW,MAAM,SAAS,QAAQ;IAChC,MAAM,MAAM;IACZ,MAAM,OAAO,IAAI;AAEjB,QAAI,SAAS,uBAAuB;KAClC,MAAM,QAAQ,IAAI;AAClB,SAAI,OAAO,SAAS,gBAAgB,MAAM,QAAQ,KAChD,aAAY,WAAW,OAAO,MAAM,KAAK,CAAC;cAE1C,OAAO,SAAS,oBAChB,MAAM,YAAY,KAElB,qBAAoB,OAAO,MAAM,SAAS;eAEnC,SAAS,uBAAuB;KACzC,MAAM,QAAQ,IAAI;AAGlB,SAAI,OAAO,SAAS,WAClB,aAAY,YAAY;MACtB,MAAM;MACN,IAAI,MAAM;MACV,UAAU;OACR,MAAM,OAAO,MAAM,QAAQ,GAAG;OAC9B,WACE,OAAO,MAAM,UAAU,WACnB,MAAM,QACN,KAAK,UAAU,MAAM,SAAS,EAAE,CAAC;OACxC;MACF,CAAC;eAEK,SAAS,iBAAiB;KACnC,MAAM,QAAQ,IAAI;AAClB,SAAI,OAAO,eAAe,KACxB,aAAY,eAAe,OAAO,MAAM,YAAY;KAEtD,MAAM,QAAQ,IAAI;AAClB,SAAI,SAAS,KACX,aAAY,SAAS,EACnB,cAAc,MAAM,eACrB,CAAC;eAEK,SAAS,iBAAiB;KACnC,MAAM,UAAU,IAAI;AACpB,SAAI,SAAS,SAAS,KACpB,aAAY,QAAQ,OAAO,QAAQ,MAAM;KAE3C,MAAM,QAAQ,SAAS;AACvB,SAAI,SAAS,KACX,aAAY,SAAS;MACnB,aAAa,MAAM;MACnB,iBAAiB,MAAM;MACvB,qBAAqB,MAAM;MAC5B,CAAC;;AAIN,UAAM;;WAED,OAAO;AACd,eAAY,SACV,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CACvD;AACD,SAAM;YACE;GACR,MAAM,QAAQ,YAAY,UAAU;GACpC,MAAM,YAAY,OAAO,YAAY,SAAS,OAAO,SAAS,UAAU;GAExE,MAAM,kBAAkB,MAAM,mBAAmB;GACjD,MAAM,sBAAsB,MAAM,uBAAuB;GACzD,MAAM,iBAAiB,MAAM,eAAe;GAC5C,MAAM,wBACJ,mBAAmB,sBACf,iBAAiB,kBAAkB,sBACnC;GAEN,IAAIA,UAAyB;AAC7B,OAAI,MAAM,eAAe,QAAQ,MAAM,gBAAgB,KACrD,KAAI;AACF,cAAU,cAAc;KACtB;KACA,aAAa;KACb,cAAc,MAAM;KACpB,sBAAsB;KACtB,0BAA0B;KAC1B,iBAAiB;KAClB,CAAC;WACI;AAKV,QAAK,SAAS;IACZ,GAAG,cAAc,WAAW;IAC5B;IACA,UAAU;IACV,iBAAiB,MAAM;IACvB,WAAW,YAAY;IACvB,aAAa,yBAAyB;IACtC,cAAc,MAAM;IACpB,sBAAsB,mBAAmB;IACzC,0BAA0B,uBAAuB;IACjD,cAAc;IACd,cAAc,MAAM;IACpB,WAAW,MAAM,UAAU,SAAS,IAAI,MAAM,YAAY;IAC1D,gBAAgB,MAAM;IACtB,aAAa;IACb,SAAS,MAAM;IACf,cAAc,MAAM;IACpB,kBAAkB,oBAAoB;IACtC,iBAAiB,gCAAgC,OAAO;IACxD,cAAc,6BAA6B,OAAO,OAAO;IACzD,aAAa,OAAO;IACpB,iBAAiB,OAAO;IACxB,MAAM,OAAO;IACd,CAAC;;;CAIN,AAAQ,oBACN,QACyB;AACzB,MAAI,CAAC,KAAK,kBAAmB,QAAO;EAIpC,MAAM,WAAW,cAHC,OAAO,iBAAiB,OAAO,QAGT;AACxC,SAAO;GACL,GAAG;GACH,eAAe;GAChB;;CAGH,AAAQ,oBACN,UACA,KACA,0BACM;AACN,MAAI,CAAC,yBAA0B;AAC/B,MAAI,IAAI,UAAU,QAAQ,IAAI,aAAa,KAAM;AACjD,MAAI,CAAC,MAAM,QAAQ,SAAS,CAAE;EAK9B,MAAM,eAAgB,SAAuC,eAC1D,MAAM,GAAG,SAAS,YACpB;EACD,MAAM,cAAe,SAAuC,MAAM,eAAe,EAAE;AAEnF,OAAK,MAAM,OAAO,aAAa;AAE7B,OADc,KAAiC,SAClC,OAAQ;GACrB,MAAM,aAAc,KAAiC;GACrD,MAAM,UAAU,MAAM,QAAQ,WAAW,GACrC,WACG,KAAK,SAAS;AACb,QAAI,OAAO,SAAS,SAAU,QAAO;IACrC,MAAM,OAAQ,MAAkC;AAChD,WAAO,OAAO,SAAS,WAAW,OAAO;KACzC,CACD,KAAK,GAAG,GACX,OAAO,eAAe,WACpB,aACA;AACN,OAAI,CAAC,QAAS;AACd,oBAAiB;IACf,WAAW,KAAK;IAChB,QAAQ,IAAI;IACZ,gBAAgB;IAChB,WAAW,IAAI;IACf,SAAS,IAAI;IACb,QAAQ,IAAI,UAAU;IACtB,eAAe,IAAI,gBAAgB,UAAU;IAC7C,SAAS,IAAI;IACb,eAAe,IAAI;IACnB,eAAe,IAAI;IACnB,cAAc,IAAI;IAClB,SAAS,IAAI;IACb,KAAK,IAAI;IACT,QAAQ,IAAI;IACZ,iBAAiB,IAAI;IACrB,eAAe,KAAK;IACrB,CAAC;;;;AAKR,SAAS,iBAAiB,OAAiD;AACzE,QACE,SAAS,QACT,OAAQ,MAAkC,OAAO,mBAC/C;;AAIN,SAAgB,6BACd,QACoB;AACpB,KAAI,OAAO,WAAW,SAAU,QAAO;AACvC,KAAI,MAAM,QAAQ,OAAO,CACvB,QAAO,OACJ,KAAK,UAAU;AACd,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,SAAS,KACxC,QAAO,OAAQ,MAAkC,QAAQ,GAAG;AAE9D,SAAO;GACP,CACD,OAAO,QAAQ,CACf,KAAK,KAAK;;AAKjB,SAAgB,wBACd,SAKA;CACA,IAAI,OAAO;CACX,IAAIC;CACJ,MAAMC,YAA4C,EAAE;AAEpD,KAAI,CAAC,QAAS,QAAO;EAAE;EAAM;EAAW;EAAW;AAEnD,MAAK,MAAM,SAAS,QAClB,KAAI,MAAM,SAAS,OACjB,SAAQ,OAAO,MAAM,QAAQ,GAAG;UACvB,MAAM,SAAS,WACxB,aAAY,OAAO,MAAM,YAAY,GAAG;UAC/B,MAAM,SAAS,WACxB,WAAU,KAAK;EACb,MAAM;EACN,IAAI,MAAM;EACV,UAAU;GACR,MAAM,OAAO,MAAM,QAAQ,GAAG;GAC9B,WACE,OAAO,MAAM,UAAU,WACnB,MAAM,QACN,KAAK,UAAU,MAAM,SAAS,EAAE,CAAC;GACxC;EACF,CAAC;AAIN,QAAO;EAAE;EAAM;EAAW;EAAW;;AAGvC,SAAS,gCACP,QAC4C;CAC5C,MAAM,QAAQ,OAAO;AACrB,QAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS,IACzC,QACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mistral.d.ts","names":[],"sources":["../../src/providers/mistral.ts"],"sourcesContent":[],"mappings":";;;;;;AAaM,cADO,iBACS,
|
|
1
|
+
{"version":3,"file":"mistral.d.ts","names":[],"sources":["../../src/providers/mistral.ts"],"sourcesContent":[],"mappings":";;;;;;AAaM,cADO,iBACS,EAAA,OAAM;AAI5B,cAJM,cAIyB,EAJT,MAKT,CAAA,MAAA,EAAA,OAEK,CAAA,GAAA,IAAA;AAOD,UAVA,cAAA,CAUA;EAEM,SAAA,EAXV,aAWU;EAJM,MAAA,CAAA,EAAA,MAAA;EAAc,aAAA,CAAA,EALzB,aAKyB,GAAA,IAAA;EAoC9B;EAI2B,aAAA,CAAA,EAAA,OAAA;;AAQW,cAhDtC,OAAA,SAAgB,cAAA,CAgDsB;EAoF5B,QAAA,OAAA;EAA0B,SAAA,IAAA,EAlIhC,WAkIgC;EAAO,WAAA,CAAA,OAAA,EAhIjC,cAgIiC;;;cAhG3C,WAAA;;;wCAI2B;mBAQf,0BAA0B;iBAoF5B,0BAA0B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.d.ts","names":[],"sources":["../../src/providers/openai.ts"],"sourcesContent":[],"mappings":";;;;;;AAoDiB,cAnBJ,gBAmBI,EAAA,OAAA;cAlBX,aAmBgB,EAnBD,MAmBC,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;AA6CN,UA5DC,aAAA,CA4DD;EAhDN,SAAA,EAXG,aAWH;EAAc,MAAA,CAAA,EAAA,MAAA;EAqDX,OAAA,CAAA,EAAA,MAAW;EACA,aAAA,CAAA,EA9DN,aA8DM,GAAA,IAAA;EAIX,gBAAA,CAAA,EAAA,OAAA;EACE;EACI,YAAA,CAAA,EAAA,OAAA;;AAeN,cA7EA,MA6EkB,CAAA,gBA5Eb,MA4Ea,CAAA,MAAA,EAAA,OAAA,CAAA,GA5Ea,MA4Eb,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,SA3ErB,cAAA,CA2EqB;EAClB,QAAA,OAAA;EAQI,SAAA,IAAA,EAlFA,WAkFA;EACJ,SAAA,SAAA,EAlFS,gBAkFT;EACE,QAAA,iBAAA;EACI,WAAA,CAAA,OAAA,EAjFI,aAiFJ;EAgBP,IAAA,MAAA,CAAA,CAAA,EAvDI,OAuDJ;;AAEC,cApDA,WAAA,CAoDA;EAAyB,SAAA,WAAA,EAnDd,kBAmDc;EAAjC,WAAA,CAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EA/CQ,OA+CR,EAAA,SAAA,EA9CU,aA8CV,EAAA,aAAA,EA7Cc,aA6Cd,GAAA,IAAA,EAAA,gBAAA,EAAA,OAAA;;AA2GoB,cAzIZ,kBAAA,CAyIY;EACZ,SAAA,EAzIA,MAyIA,CAAA,MAAA,EAAA,OAAA,CAAA;EAAyB,QAAA,QAAA;EAAjC,QAAA,UAAA;EAAO,QAAA,cAAA;
|
|
1
|
+
{"version":3,"file":"openai.d.ts","names":[],"sources":["../../src/providers/openai.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/providers/openai.js
CHANGED
|
@@ -237,7 +237,10 @@ var WrappedCompletions = class {
|
|
|
237
237
|
if (!shouldTrackInputMessages) return;
|
|
238
238
|
if (ctx.userId == null || ctx.sessionId == null) return;
|
|
239
239
|
if (!Array.isArray(messages)) return;
|
|
240
|
-
|
|
240
|
+
const msgs = messages;
|
|
241
|
+
const lastReplyIdx = msgs.findLastIndex((m) => m?.role === "assistant" || m?.role === "tool");
|
|
242
|
+
const newMessages = msgs.slice(lastReplyIdx + 1);
|
|
243
|
+
for (const msg of newMessages) {
|
|
241
244
|
if (msg?.role !== "user") continue;
|
|
242
245
|
const content = msg.content;
|
|
243
246
|
if (typeof content !== "string" || content.length === 0) continue;
|
|
@@ -515,8 +518,14 @@ function extractResponsesToolDefinitions(params) {
|
|
|
515
518
|
function extractResponsesUserInputs(input) {
|
|
516
519
|
if (typeof input === "string") return [input];
|
|
517
520
|
if (!Array.isArray(input)) return [];
|
|
521
|
+
const entries = input;
|
|
522
|
+
const lastReplyIdx = entries.findLastIndex((e) => {
|
|
523
|
+
if (typeof e === "string") return false;
|
|
524
|
+
return e.role === "assistant" || e.type === "function_call" || e.type === "function_call_output";
|
|
525
|
+
});
|
|
526
|
+
const newEntries = entries.slice(lastReplyIdx + 1);
|
|
518
527
|
const result = [];
|
|
519
|
-
for (const entry of
|
|
528
|
+
for (const entry of newEntries) {
|
|
520
529
|
if (typeof entry === "string") {
|
|
521
530
|
result.push(entry);
|
|
522
531
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","names":["_OpenAIModule: Record<string, unknown> | null","clientOpts: Record<string, unknown>","costUsd: number | null","toolCalls: Array<Record<string, unknown>>","result: string[]"],"sources":["../../src/providers/openai.ts"],"sourcesContent":["/**\n * OpenAI provider wrapper with automatic tracking.\n *\n * Wraps the OpenAI client and instruments:\n * - chat.completions.create()\n * - responses.create()\n * to track AI response events via Amplitude.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { trackUserMessage } from '../core/tracking.js';\nimport { getDefaultPropagateContext, injectContext } from '../propagation.js';\nimport type {\n AmplitudeLike,\n AmplitudeOrAI,\n ChatCompletionResponse,\n ChatMessage,\n OpenAIResponse,\n OpenAIResponseInput,\n OpenAIResponseOutputItem,\n TrackFn,\n} from '../types.js';\nimport { calculateCost } from '../utils/costs.js';\nimport { tryRequire } from '../utils/resolve-module.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\nimport {\n applySessionContext,\n BaseAIProvider,\n contextFields,\n type ProviderTrackOptions,\n} from './base.js';\n\nconst _resolved = tryRequire('openai');\nexport const OPENAI_AVAILABLE = _resolved != null;\nconst _OpenAIModule: Record<string, unknown> | null = _resolved;\n\nexport { _OpenAIModule };\n\nexport interface OpenAIOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n baseUrl?: string;\n privacyConfig?: PrivacyConfig | null;\n propagateContext?: boolean;\n /** Pass the `openai` module directly to bypass `tryRequire` (required in bundler environments). */\n openaiModule?: unknown;\n}\n\nexport class OpenAI<\n TClient extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseAIProvider {\n private _client: TClient;\n readonly chat: WrappedChat;\n readonly responses: WrappedResponses;\n private _propagateContext: boolean;\n\n constructor(options: OpenAIOptions) {\n super({\n amplitude: options.amplitude,\n privacyConfig: options.privacyConfig,\n providerName: 'openai',\n });\n\n const mod =\n (options.openaiModule as Record<string, unknown> | null) ?? _OpenAIModule;\n if (mod == null) {\n throw new Error(\n 'openai package is required. Install it with: npm install openai — or pass the module directly via the openaiModule option.',\n );\n }\n\n const OpenAISDK = mod.OpenAI as new (\n opts: Record<string, unknown>,\n ) => unknown;\n\n const clientOpts: Record<string, unknown> = {};\n if (options.apiKey) clientOpts.apiKey = options.apiKey;\n if (options.baseUrl) clientOpts.baseURL = options.baseUrl;\n\n this._client = new OpenAISDK(clientOpts) as TClient;\n this._propagateContext =\n options.propagateContext ?? getDefaultPropagateContext();\n this.chat = new WrappedChat(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n this.responses = new WrappedResponses(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n }\n\n get client(): TClient {\n return this._client;\n }\n}\n\nexport class WrappedChat {\n readonly completions: WrappedCompletions;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n ) {\n const clientObj = client as Record<string, unknown>;\n const chat = clientObj.chat as Record<string, unknown>;\n this.completions = new WrappedCompletions(\n chat.completions as Record<string, unknown>,\n trackFn,\n amplitude,\n privacyConfig,\n propagateContext,\n );\n }\n}\n\nexport class WrappedCompletions {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n private _providerName: string;\n\n constructor(\n completions: Record<string, unknown>,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n providerName = 'openai',\n ) {\n this._original = completions;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n this._providerName = providerName;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<ChatCompletionResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n let requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n if (requestParams.stream === true && requestParams.stream_options == null) {\n requestParams = {\n ...requestParams,\n stream_options: { include_usage: true },\n };\n }\n\n try {\n this._trackInputMessages(\n requestParams.messages as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n\n const resp = response as ChatCompletionResponse;\n const usage = resp.usage;\n const choice = resp.choices?.[0];\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n const toolCalls = choice?.message?.tool_calls;\n\n const usageExt = usage as Record<string, unknown> | undefined;\n const promptDetails = usageExt?.prompt_tokens_details as\n | Record<string, number>\n | undefined;\n const completionDetails = usageExt?.completion_tokens_details as\n | Record<string, number>\n | undefined;\n const reasoningTokens = completionDetails?.reasoning_tokens;\n const cachedTokens = promptDetails?.cached_tokens;\n\n let costUsd: number | null = null;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: usage.prompt_tokens,\n outputTokens: usage.completion_tokens,\n reasoningTokens: reasoningTokens ?? 0,\n cacheReadInputTokens: cachedTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: this._providerName,\n responseContent: String(choice?.message?.content ?? ''),\n latencyMs,\n inputTokens: usage?.prompt_tokens,\n outputTokens: usage?.completion_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens,\n cacheReadInputTokens: cachedTokens,\n totalCostUsd: costUsd,\n finishReason: choice?.finish_reason,\n toolCalls: toolCalls ?? undefined,\n isStreaming: false,\n toolDefinitions: extractToolDefinitions(requestParams),\n systemPrompt: extractSystemPrompt(requestParams),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as ChatCompletionResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n }\n }\n\n async parse(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<ChatCompletionResponse | AsyncIterable<unknown>> {\n const parseFn = this._original.parse as\n | ((...args: unknown[]) => Promise<unknown>)\n | undefined;\n if (typeof parseFn !== 'function') {\n throw new Error('OpenAI SDK does not expose chat.completions.parse');\n }\n const originalCreate = this._original.create;\n this._original.create = parseFn;\n try {\n return await this.create(params, amplitudeOverrides);\n } finally {\n this._original.create = originalCreate;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n let reasoningContent = '';\n\n try {\n for await (const chunk of stream) {\n const c = chunk as Record<string, unknown>;\n const choices = c.choices as Array<Record<string, unknown>> | undefined;\n const delta = choices?.[0]?.delta as\n | Record<string, unknown>\n | undefined;\n\n if (delta?.content != null) {\n accumulator.addContent(String(delta.content));\n }\n\n const deltaToolCalls = delta?.tool_calls as\n | Array<Record<string, unknown>>\n | undefined;\n if (Array.isArray(deltaToolCalls)) {\n for (const call of deltaToolCalls) {\n const idx = call.index as number | undefined;\n const id = call.id as string | undefined;\n const fn = call.function as Record<string, unknown> | undefined;\n if (idx != null && id && fn?.name != null) {\n accumulator.setToolCallAt(idx, {\n type: 'function',\n id,\n function: {\n name: fn.name,\n arguments: ((fn.arguments as string) ?? ''),\n },\n });\n } else if (idx != null && fn?.arguments) {\n accumulator.appendToolCallArgs(idx, fn.arguments as string);\n } else {\n accumulator.addToolCall(call);\n }\n }\n }\n\n if (delta?.reasoning_content != null) {\n reasoningContent += String(delta.reasoning_content);\n }\n\n const finishReason = choices?.[0]?.finish_reason;\n if (finishReason != null) {\n accumulator.finishReason = String(finishReason);\n }\n\n const usage = c.usage as Record<string, unknown> | undefined;\n if (usage != null) {\n const promptDetails = usage.prompt_tokens_details as\n | Record<string, number>\n | undefined;\n const completionDetails = usage.completion_tokens_details as\n | Record<string, number>\n | undefined;\n\n accumulator.setUsage({\n inputTokens: usage.prompt_tokens as number | undefined,\n outputTokens: usage.completion_tokens as number | undefined,\n totalTokens: usage.total_tokens as number | undefined,\n reasoningTokens: completionDetails?.reasoning_tokens,\n cacheReadTokens: promptDetails?.cached_tokens,\n });\n }\n\n yield chunk;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n const modelName = String(accumulator.model ?? params.model ?? 'unknown');\n\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n reasoningTokens: state.reasoningTokens ?? 0,\n cacheReadInputTokens: state.cacheReadTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName,\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n cacheReadInputTokens: state.cacheReadTokens,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : undefined,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n reasoningContent: reasoningContent || undefined,\n toolDefinitions: extractToolDefinitions(params),\n systemPrompt: extractSystemPrompt(params),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n messages: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n if (!Array.isArray(messages)) return;\n for (const msg of messages as ChatMessage[]) {\n if (msg?.role !== 'user') continue;\n const content = msg.content;\n if (typeof content !== 'string' || content.length === 0) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: content,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nexport class WrappedResponses {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n private _providerName: string;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n providerName = 'openai',\n ) {\n const clientObj = client as Record<string, unknown>;\n const responses = (clientObj.responses ?? {}) as Record<string, unknown>;\n this._original = responses;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n this._providerName = providerName;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<OpenAIResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.input as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n const resp = response as OpenAIResponse;\n const usage = resp.usage;\n const responseText = extractResponsesText(resp);\n const responseToolCalls = extractResponsesToolCalls(resp);\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n\n let costUsd: number | null = null;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: usage.input_tokens,\n outputTokens: usage.output_tokens,\n reasoningTokens: usage.output_tokens_details?.reasoning_tokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: this._providerName,\n responseContent: responseText,\n latencyMs,\n inputTokens: usage?.input_tokens,\n outputTokens: usage?.output_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens: usage?.output_tokens_details?.reasoning_tokens,\n totalCostUsd: costUsd,\n finishReason: extractResponsesFinishReason(resp),\n toolCalls: responseToolCalls.length > 0 ? responseToolCalls : undefined,\n isStreaming: false,\n toolDefinitions: extractResponsesToolDefinitions(requestParams),\n systemPrompt: extractResponsesSystemPrompt(requestParams),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_output_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as OpenAIResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async stream(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<AsyncIterable<unknown>> {\n const streamFn = this._original.stream as\n | ((...args: unknown[]) => Promise<unknown>)\n | undefined;\n if (typeof streamFn !== 'function') {\n throw new Error('OpenAI SDK does not expose responses.stream');\n }\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.input as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await streamFn.call(this._original, requestParams);\n if (!_isAsyncIterable(response)) {\n throw new Error('OpenAI responses.stream did not return AsyncIterable');\n }\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n } catch (error) {\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs: performance.now() - startTime,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n isStreaming: true,\n });\n throw error;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n\n try {\n for await (const event of stream) {\n const e = event as Record<string, unknown>;\n const type = e.type as string | undefined;\n if (type === 'response.output_text.delta') {\n const delta = e.delta;\n if (typeof delta === 'string') accumulator.addContent(delta);\n } else if (type === 'response.completed') {\n const response = e.response as OpenAIResponse | undefined;\n if (response != null) {\n const outputText = extractResponsesText(response);\n if (outputText.length > 0) {\n accumulator.content = outputText;\n }\n const usage = response.usage;\n accumulator.setUsage({\n inputTokens: usage?.input_tokens,\n outputTokens: usage?.output_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens: usage?.output_tokens_details?.reasoning_tokens,\n });\n const finishReason = extractResponsesFinishReason(response);\n if (finishReason != null) accumulator.finishReason = finishReason;\n }\n }\n yield event;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName: String(accumulator.model ?? params.model ?? 'unknown'),\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n reasoningTokens: state.reasoningTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName: String(accumulator.model ?? params.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n toolDefinitions: extractResponsesToolDefinitions(params),\n systemPrompt: extractResponsesSystemPrompt(params),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_output_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n input: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n for (const text of extractResponsesUserInputs(input)) {\n if (!text) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: text,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nfunction _isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n value != null &&\n typeof (value as Record<symbol, unknown>)[Symbol.asyncIterator] ===\n 'function'\n );\n}\n\nexport function extractSystemPrompt(\n params: Record<string, unknown>,\n): string | undefined {\n const messages = params.messages as\n | Array<Record<string, unknown>>\n | undefined;\n if (!messages?.length) return undefined;\n const systemMsg = messages.find(\n (m) => m.role === 'system' || m.role === 'developer',\n );\n return systemMsg ? String(systemMsg.content ?? '') : undefined;\n}\n\nfunction extractResponsesSystemPrompt(\n params: Record<string, unknown>,\n): string | undefined {\n const instructions = params.instructions;\n return typeof instructions === 'string' ? instructions : undefined;\n}\n\nfunction extractResponsesFinishReason(\n resp: OpenAIResponse,\n): string | undefined {\n const status = resp.status;\n if (typeof status === 'string' && status.length > 0) return status;\n const out = resp.output?.[0];\n if (out != null && typeof out.status === 'string') return out.status;\n return undefined;\n}\n\nfunction extractResponsesText(resp: OpenAIResponse): string {\n if (typeof resp.output_text === 'string') return resp.output_text;\n const outputs = resp.output ?? [];\n let text = '';\n for (const item of outputs) {\n text += extractOutputItemText(item);\n }\n return text;\n}\n\nfunction extractResponsesToolCalls(\n resp: OpenAIResponse,\n): Array<Record<string, unknown>> {\n const toolCalls: Array<Record<string, unknown>> = [];\n const outputs = resp.output ?? [];\n for (const item of outputs) {\n if (!Array.isArray(item.content)) continue;\n for (const contentItem of item.content) {\n if (\n contentItem?.type === 'tool_call' ||\n contentItem?.type === 'function_call'\n ) {\n toolCalls.push(contentItem as Record<string, unknown>);\n }\n }\n }\n return toolCalls;\n}\n\nfunction extractOutputItemText(item: OpenAIResponseOutputItem): string {\n if (!Array.isArray(item.content)) return '';\n let text = '';\n for (const c of item.content) {\n if (typeof c?.text === 'string') text += c.text;\n }\n return text;\n}\n\nexport function extractToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n\nfunction extractResponsesToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n\nfunction extractResponsesUserInputs(input: unknown): string[] {\n if (typeof input === 'string') return [input];\n if (!Array.isArray(input)) return [];\n\n const result: string[] = [];\n for (const entry of input as OpenAIResponseInput[]) {\n if (typeof entry === 'string') {\n result.push(entry);\n continue;\n }\n const role = entry.role;\n if (role !== 'user') continue;\n const content = entry.content;\n if (typeof content === 'string') {\n result.push(content);\n } else if (Array.isArray(content)) {\n for (const part of content) {\n if (typeof part?.text === 'string') result.push(part.text);\n }\n }\n }\n return result;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"openai.js","names":["_OpenAIModule: Record<string, unknown> | null","clientOpts: Record<string, unknown>","costUsd: number | null","toolCalls: Array<Record<string, unknown>>","result: string[]"],"sources":["../../src/providers/openai.ts"],"sourcesContent":["/**\n * OpenAI provider wrapper with automatic tracking.\n *\n * Wraps the OpenAI client and instruments:\n * - chat.completions.create()\n * - responses.create()\n * to track AI response events via Amplitude.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { trackUserMessage } from '../core/tracking.js';\nimport { getDefaultPropagateContext, injectContext } from '../propagation.js';\nimport type {\n AmplitudeLike,\n AmplitudeOrAI,\n ChatCompletionResponse,\n ChatMessage,\n OpenAIResponse,\n OpenAIResponseInput,\n OpenAIResponseOutputItem,\n TrackFn,\n} from '../types.js';\nimport { calculateCost } from '../utils/costs.js';\nimport { tryRequire } from '../utils/resolve-module.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\nimport {\n applySessionContext,\n BaseAIProvider,\n contextFields,\n type ProviderTrackOptions,\n} from './base.js';\n\nconst _resolved = tryRequire('openai');\nexport const OPENAI_AVAILABLE = _resolved != null;\nconst _OpenAIModule: Record<string, unknown> | null = _resolved;\n\nexport { _OpenAIModule };\n\nexport interface OpenAIOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n baseUrl?: string;\n privacyConfig?: PrivacyConfig | null;\n propagateContext?: boolean;\n /** Pass the `openai` module directly to bypass `tryRequire` (required in bundler environments). */\n openaiModule?: unknown;\n}\n\nexport class OpenAI<\n TClient extends Record<string, unknown> = Record<string, unknown>,\n> extends BaseAIProvider {\n private _client: TClient;\n readonly chat: WrappedChat;\n readonly responses: WrappedResponses;\n private _propagateContext: boolean;\n\n constructor(options: OpenAIOptions) {\n super({\n amplitude: options.amplitude,\n privacyConfig: options.privacyConfig,\n providerName: 'openai',\n });\n\n const mod =\n (options.openaiModule as Record<string, unknown> | null) ?? _OpenAIModule;\n if (mod == null) {\n throw new Error(\n 'openai package is required. Install it with: npm install openai — or pass the module directly via the openaiModule option.',\n );\n }\n\n const OpenAISDK = mod.OpenAI as new (\n opts: Record<string, unknown>,\n ) => unknown;\n\n const clientOpts: Record<string, unknown> = {};\n if (options.apiKey) clientOpts.apiKey = options.apiKey;\n if (options.baseUrl) clientOpts.baseURL = options.baseUrl;\n\n this._client = new OpenAISDK(clientOpts) as TClient;\n this._propagateContext =\n options.propagateContext ?? getDefaultPropagateContext();\n this.chat = new WrappedChat(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n this.responses = new WrappedResponses(\n this._client,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n );\n }\n\n get client(): TClient {\n return this._client;\n }\n}\n\nexport class WrappedChat {\n readonly completions: WrappedCompletions;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n ) {\n const clientObj = client as Record<string, unknown>;\n const chat = clientObj.chat as Record<string, unknown>;\n this.completions = new WrappedCompletions(\n chat.completions as Record<string, unknown>,\n trackFn,\n amplitude,\n privacyConfig,\n propagateContext,\n );\n }\n}\n\nexport class WrappedCompletions {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n private _providerName: string;\n\n constructor(\n completions: Record<string, unknown>,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n providerName = 'openai',\n ) {\n this._original = completions;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n this._providerName = providerName;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<ChatCompletionResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n let requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n if (requestParams.stream === true && requestParams.stream_options == null) {\n requestParams = {\n ...requestParams,\n stream_options: { include_usage: true },\n };\n }\n\n try {\n this._trackInputMessages(\n requestParams.messages as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n\n const resp = response as ChatCompletionResponse;\n const usage = resp.usage;\n const choice = resp.choices?.[0];\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n const toolCalls = choice?.message?.tool_calls;\n\n const usageExt = usage as Record<string, unknown> | undefined;\n const promptDetails = usageExt?.prompt_tokens_details as\n | Record<string, number>\n | undefined;\n const completionDetails = usageExt?.completion_tokens_details as\n | Record<string, number>\n | undefined;\n const reasoningTokens = completionDetails?.reasoning_tokens;\n const cachedTokens = promptDetails?.cached_tokens;\n\n let costUsd: number | null = null;\n if (usage?.prompt_tokens != null && usage?.completion_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: usage.prompt_tokens,\n outputTokens: usage.completion_tokens,\n reasoningTokens: reasoningTokens ?? 0,\n cacheReadInputTokens: cachedTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: this._providerName,\n responseContent: String(choice?.message?.content ?? ''),\n latencyMs,\n inputTokens: usage?.prompt_tokens,\n outputTokens: usage?.completion_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens,\n cacheReadInputTokens: cachedTokens,\n totalCostUsd: costUsd,\n finishReason: choice?.finish_reason,\n toolCalls: toolCalls ?? undefined,\n isStreaming: false,\n toolDefinitions: extractToolDefinitions(requestParams),\n systemPrompt: extractSystemPrompt(requestParams),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as ChatCompletionResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n }\n }\n\n async parse(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<ChatCompletionResponse | AsyncIterable<unknown>> {\n const parseFn = this._original.parse as\n | ((...args: unknown[]) => Promise<unknown>)\n | undefined;\n if (typeof parseFn !== 'function') {\n throw new Error('OpenAI SDK does not expose chat.completions.parse');\n }\n const originalCreate = this._original.create;\n this._original.create = parseFn;\n try {\n return await this.create(params, amplitudeOverrides);\n } finally {\n this._original.create = originalCreate;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n let reasoningContent = '';\n\n try {\n for await (const chunk of stream) {\n const c = chunk as Record<string, unknown>;\n const choices = c.choices as Array<Record<string, unknown>> | undefined;\n const delta = choices?.[0]?.delta as\n | Record<string, unknown>\n | undefined;\n\n if (delta?.content != null) {\n accumulator.addContent(String(delta.content));\n }\n\n const deltaToolCalls = delta?.tool_calls as\n | Array<Record<string, unknown>>\n | undefined;\n if (Array.isArray(deltaToolCalls)) {\n for (const call of deltaToolCalls) {\n const idx = call.index as number | undefined;\n const id = call.id as string | undefined;\n const fn = call.function as Record<string, unknown> | undefined;\n if (idx != null && id && fn?.name != null) {\n accumulator.setToolCallAt(idx, {\n type: 'function',\n id,\n function: {\n name: fn.name,\n arguments: ((fn.arguments as string) ?? ''),\n },\n });\n } else if (idx != null && fn?.arguments) {\n accumulator.appendToolCallArgs(idx, fn.arguments as string);\n } else {\n accumulator.addToolCall(call);\n }\n }\n }\n\n if (delta?.reasoning_content != null) {\n reasoningContent += String(delta.reasoning_content);\n }\n\n const finishReason = choices?.[0]?.finish_reason;\n if (finishReason != null) {\n accumulator.finishReason = String(finishReason);\n }\n\n const usage = c.usage as Record<string, unknown> | undefined;\n if (usage != null) {\n const promptDetails = usage.prompt_tokens_details as\n | Record<string, number>\n | undefined;\n const completionDetails = usage.completion_tokens_details as\n | Record<string, number>\n | undefined;\n\n accumulator.setUsage({\n inputTokens: usage.prompt_tokens as number | undefined,\n outputTokens: usage.completion_tokens as number | undefined,\n totalTokens: usage.total_tokens as number | undefined,\n reasoningTokens: completionDetails?.reasoning_tokens,\n cacheReadTokens: promptDetails?.cached_tokens,\n });\n }\n\n yield chunk;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n const modelName = String(accumulator.model ?? params.model ?? 'unknown');\n\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n reasoningTokens: state.reasoningTokens ?? 0,\n cacheReadInputTokens: state.cacheReadTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName,\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n cacheReadInputTokens: state.cacheReadTokens,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : undefined,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n reasoningContent: reasoningContent || undefined,\n toolDefinitions: extractToolDefinitions(params),\n systemPrompt: extractSystemPrompt(params),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n messages: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n if (!Array.isArray(messages)) return;\n\n const msgs = messages as ChatMessage[];\n\n // In agent loops each create() re-sends the full conversation history.\n // Only track user messages appended *after* the last assistant/tool\n // reply so the same message isn't autotracked on every iteration.\n const lastReplyIdx = msgs.findLastIndex(\n (m) => m?.role === 'assistant' || m?.role === 'tool',\n );\n const newMessages = msgs.slice(lastReplyIdx + 1);\n\n for (const msg of newMessages) {\n if (msg?.role !== 'user') continue;\n const content = msg.content;\n if (typeof content !== 'string' || content.length === 0) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: content,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nexport class WrappedResponses {\n _original: Record<string, unknown>;\n private _trackFn: TrackFn;\n private _amplitude: AmplitudeLike;\n private _privacyConfig: PrivacyConfig | null;\n private _propagateContext: boolean;\n private _providerName: string;\n\n constructor(\n client: unknown,\n trackFn: TrackFn,\n amplitude: AmplitudeLike,\n privacyConfig: PrivacyConfig | null,\n propagateContext: boolean,\n providerName = 'openai',\n ) {\n const clientObj = client as Record<string, unknown>;\n const responses = (clientObj.responses ?? {}) as Record<string, unknown>;\n this._original = responses;\n this._trackFn =\n typeof trackFn === 'function'\n ? trackFn\n : (trackFn as unknown as { trackFn(): TrackFn }).trackFn();\n this._amplitude = amplitude;\n this._privacyConfig = privacyConfig;\n this._propagateContext = propagateContext;\n this._providerName = providerName;\n }\n\n async create(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<OpenAIResponse | AsyncIterable<unknown>> {\n const createFn = this._original.create as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.input as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await createFn.call(this._original, requestParams);\n if (requestParams.stream === true && _isAsyncIterable(response)) {\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n }\n\n const latencyMs = performance.now() - startTime;\n const resp = response as OpenAIResponse;\n const usage = resp.usage;\n const responseText = extractResponsesText(resp);\n const responseToolCalls = extractResponsesToolCalls(resp);\n const modelName = String(resp.model ?? requestParams.model ?? 'unknown');\n\n let costUsd: number | null = null;\n if (usage?.input_tokens != null && usage?.output_tokens != null) {\n try {\n costUsd = calculateCost({\n modelName,\n inputTokens: usage.input_tokens,\n outputTokens: usage.output_tokens,\n reasoningTokens: usage.output_tokens_details?.reasoning_tokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n ...contextFields(ctx),\n modelName,\n provider: this._providerName,\n responseContent: responseText,\n latencyMs,\n inputTokens: usage?.input_tokens,\n outputTokens: usage?.output_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens: usage?.output_tokens_details?.reasoning_tokens,\n totalCostUsd: costUsd,\n finishReason: extractResponsesFinishReason(resp),\n toolCalls: responseToolCalls.length > 0 ? responseToolCalls : undefined,\n isStreaming: false,\n toolDefinitions: extractResponsesToolDefinitions(requestParams),\n systemPrompt: extractResponsesSystemPrompt(requestParams),\n temperature: requestParams.temperature as number | undefined,\n maxOutputTokens: requestParams.max_output_tokens as number | undefined,\n topP: requestParams.top_p as number | undefined,\n });\n\n return response as OpenAIResponse;\n } catch (error) {\n const latencyMs = performance.now() - startTime;\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async stream(\n params: Record<string, unknown>,\n amplitudeOverrides?: ProviderTrackOptions,\n ): Promise<AsyncIterable<unknown>> {\n const streamFn = this._original.stream as\n | ((...args: unknown[]) => Promise<unknown>)\n | undefined;\n if (typeof streamFn !== 'function') {\n throw new Error('OpenAI SDK does not expose responses.stream');\n }\n const startTime = performance.now();\n const requestParams = this._withContextHeaders(params);\n const ctx = applySessionContext(amplitudeOverrides);\n\n try {\n this._trackInputMessages(\n requestParams.input as unknown,\n ctx,\n amplitudeOverrides?.trackInputMessages ?? true,\n );\n const response = await streamFn.call(this._original, requestParams);\n if (!_isAsyncIterable(response)) {\n throw new Error('OpenAI responses.stream did not return AsyncIterable');\n }\n return this._wrapStream(\n response as AsyncIterable<unknown>,\n requestParams,\n startTime,\n ctx,\n );\n } catch (error) {\n this._trackFn({\n ...contextFields(ctx),\n modelName: String(requestParams.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: '',\n latencyMs: performance.now() - startTime,\n isError: true,\n errorMessage: error instanceof Error ? error.message : String(error),\n isStreaming: true,\n });\n throw error;\n }\n }\n\n private async *_wrapStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n _startTime: number,\n sessionCtx: ProviderTrackOptions,\n ): AsyncGenerator<unknown> {\n const accumulator = new StreamingAccumulator();\n accumulator.model = String(params.model ?? 'unknown');\n\n try {\n for await (const event of stream) {\n const e = event as Record<string, unknown>;\n const type = e.type as string | undefined;\n if (type === 'response.output_text.delta') {\n const delta = e.delta;\n if (typeof delta === 'string') accumulator.addContent(delta);\n } else if (type === 'response.completed') {\n const response = e.response as OpenAIResponse | undefined;\n if (response != null) {\n const outputText = extractResponsesText(response);\n if (outputText.length > 0) {\n accumulator.content = outputText;\n }\n const usage = response.usage;\n accumulator.setUsage({\n inputTokens: usage?.input_tokens,\n outputTokens: usage?.output_tokens,\n totalTokens: usage?.total_tokens,\n reasoningTokens: usage?.output_tokens_details?.reasoning_tokens,\n });\n const finishReason = extractResponsesFinishReason(response);\n if (finishReason != null) accumulator.finishReason = finishReason;\n }\n }\n yield event;\n }\n } catch (error) {\n accumulator.setError(\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n } finally {\n const state = accumulator.getState();\n let costUsd: number | null = null;\n if (state.inputTokens != null && state.outputTokens != null) {\n try {\n costUsd = calculateCost({\n modelName: String(accumulator.model ?? params.model ?? 'unknown'),\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n reasoningTokens: state.reasoningTokens ?? 0,\n defaultProvider: 'openai',\n });\n } catch {\n // cost calculation is best-effort\n }\n }\n this._trackFn({\n ...contextFields(sessionCtx),\n modelName: String(accumulator.model ?? params.model ?? 'unknown'),\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n totalCostUsd: costUsd,\n finishReason: state.finishReason,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n isError: state.isError,\n errorMessage: state.errorMessage,\n toolDefinitions: extractResponsesToolDefinitions(params),\n systemPrompt: extractResponsesSystemPrompt(params),\n temperature: params.temperature as number | undefined,\n maxOutputTokens: params.max_output_tokens as number | undefined,\n topP: params.top_p as number | undefined,\n });\n }\n }\n\n private _withContextHeaders(\n params: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!this._propagateContext) return params;\n const existing = (params.extra_headers ?? params.headers) as\n | Record<string, string>\n | undefined;\n const injected = injectContext(existing);\n return {\n ...params,\n extra_headers: injected,\n };\n }\n\n private _trackInputMessages(\n input: unknown,\n ctx: ProviderTrackOptions,\n shouldTrackInputMessages: boolean,\n ): void {\n if (!shouldTrackInputMessages) return;\n if (ctx.userId == null || ctx.sessionId == null) return;\n for (const text of extractResponsesUserInputs(input)) {\n if (!text) continue;\n trackUserMessage({\n amplitude: this._amplitude,\n userId: ctx.userId,\n messageContent: text,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n messageSource: ctx.parentAgentId ? 'agent' : 'user',\n agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n agentVersion: ctx.agentVersion,\n context: ctx.context,\n env: ctx.env,\n groups: ctx.groups,\n eventProperties: ctx.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n }\n}\n\nfunction _isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n value != null &&\n typeof (value as Record<symbol, unknown>)[Symbol.asyncIterator] ===\n 'function'\n );\n}\n\nexport function extractSystemPrompt(\n params: Record<string, unknown>,\n): string | undefined {\n const messages = params.messages as\n | Array<Record<string, unknown>>\n | undefined;\n if (!messages?.length) return undefined;\n const systemMsg = messages.find(\n (m) => m.role === 'system' || m.role === 'developer',\n );\n return systemMsg ? String(systemMsg.content ?? '') : undefined;\n}\n\nfunction extractResponsesSystemPrompt(\n params: Record<string, unknown>,\n): string | undefined {\n const instructions = params.instructions;\n return typeof instructions === 'string' ? instructions : undefined;\n}\n\nfunction extractResponsesFinishReason(\n resp: OpenAIResponse,\n): string | undefined {\n const status = resp.status;\n if (typeof status === 'string' && status.length > 0) return status;\n const out = resp.output?.[0];\n if (out != null && typeof out.status === 'string') return out.status;\n return undefined;\n}\n\nfunction extractResponsesText(resp: OpenAIResponse): string {\n if (typeof resp.output_text === 'string') return resp.output_text;\n const outputs = resp.output ?? [];\n let text = '';\n for (const item of outputs) {\n text += extractOutputItemText(item);\n }\n return text;\n}\n\nfunction extractResponsesToolCalls(\n resp: OpenAIResponse,\n): Array<Record<string, unknown>> {\n const toolCalls: Array<Record<string, unknown>> = [];\n const outputs = resp.output ?? [];\n for (const item of outputs) {\n if (!Array.isArray(item.content)) continue;\n for (const contentItem of item.content) {\n if (\n contentItem?.type === 'tool_call' ||\n contentItem?.type === 'function_call'\n ) {\n toolCalls.push(contentItem as Record<string, unknown>);\n }\n }\n }\n return toolCalls;\n}\n\nfunction extractOutputItemText(item: OpenAIResponseOutputItem): string {\n if (!Array.isArray(item.content)) return '';\n let text = '';\n for (const c of item.content) {\n if (typeof c?.text === 'string') text += c.text;\n }\n return text;\n}\n\nexport function extractToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n\nfunction extractResponsesToolDefinitions(\n params: Record<string, unknown>,\n): Array<Record<string, unknown>> | undefined {\n const tools = params.tools;\n return Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : undefined;\n}\n\nfunction extractResponsesUserInputs(input: unknown): string[] {\n if (typeof input === 'string') return [input];\n if (!Array.isArray(input)) return [];\n\n const entries = input as OpenAIResponseInput[];\n\n // In agent loops the full input array is re-sent each iteration.\n // Only extract user inputs after the last assistant/function reply\n // so the same message isn't autotracked on every create() call.\n const lastReplyIdx = entries.findLastIndex((e) => {\n if (typeof e === 'string') return false;\n return e.role === 'assistant' || e.type === 'function_call' || e.type === 'function_call_output';\n });\n const newEntries = entries.slice(lastReplyIdx + 1);\n\n const result: string[] = [];\n for (const entry of newEntries) {\n if (typeof entry === 'string') {\n result.push(entry);\n continue;\n }\n const role = entry.role;\n if (role !== 'user') continue;\n const content = entry.content;\n if (typeof content === 'string') {\n result.push(content);\n } else if (Array.isArray(content)) {\n for (const part of content) {\n if (typeof part?.text === 'string') result.push(part.text);\n }\n }\n }\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":[],"mappings":";UAAiB,MAAA;EAAA,KAAA,CAAA,OAAM,EAAA,MAAA,CAAA,EAAA,IAAA;EAcP,KAAA,CAAA,OAAS,EAAA,MAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":[],"mappings":";UAAiB,MAAA;EAAA,KAAA,CAAA,OAAM,EAAA,MAAA,CAAA,EAAA,IAAA;EAcP,KAAA,CAAA,OAAS,EAAA,MAAA,CAAA,EAAA,IAAuB;;;;iBAAhC,SAAA,uBAAgC"}
|
package/llms-full.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# llms-full.txt
|
|
2
|
-
# @amplitude/ai 0.3.
|
|
2
|
+
# @amplitude/ai 0.3.7 — Complete API Reference for AI Coding Agents
|
|
3
3
|
#
|
|
4
4
|
# This file is the definitive guide for any coding agent instrumenting
|
|
5
5
|
# a JavaScript/TypeScript AI application with @amplitude/ai.
|
|
@@ -67,6 +67,7 @@ const ai = new AmplitudeAI({
|
|
|
67
67
|
|
|
68
68
|
### patch(options) / unpatch()
|
|
69
69
|
Zero-code instrumentation. Monkey-patches all detected provider SDKs.
|
|
70
|
+
Captures aggregate `[Agent] AI Response` events only — no user identity, no funnels. Use as a quick verification or for legacy codebases where you cannot modify call sites.
|
|
70
71
|
```
|
|
71
72
|
import { patch, unpatch } from '@amplitude/ai';
|
|
72
73
|
patch({ amplitudeAI: ai });
|
|
@@ -395,6 +396,8 @@ with code examples for every step. Read this for guided instrumentation.
|
|
|
395
396
|
|
|
396
397
|
## CLI
|
|
397
398
|
|
|
399
|
+
- `amplitude-ai` — Print instrumentation prompt for AI coding agents
|
|
400
|
+
- `amplitude-ai --print-guide` — Print the full amplitude-ai.md guide to stdout
|
|
398
401
|
- `amplitude-ai mcp` — Start the MCP server for AI coding agents
|
|
399
402
|
- `amplitude-ai doctor [--json] [--no-mock-check]` — Validate environment and event pipeline
|
|
400
403
|
- `amplitude-ai status [--json]` — Show SDK version, installed providers, and env config
|
package/llms.txt
CHANGED
package/mcp.schema.json
CHANGED