@amplitude/ai 0.2.0 → 0.3.0
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/.claude/commands/instrument-with-amplitude-ai.md +12 -0
- package/.cursor/skills/instrument-with-amplitude-ai/SKILL.md +4 -42
- package/AGENTS.md +86 -28
- package/README.md +190 -111
- package/amplitude-ai.md +463 -0
- package/bin/amplitude-ai-doctor.mjs +0 -0
- package/bin/amplitude-ai-instrument.mjs +0 -0
- package/bin/amplitude-ai-mcp.mjs +0 -0
- package/bin/amplitude-ai-register-catalog.mjs +0 -0
- package/bin/amplitude-ai-status.mjs +0 -0
- package/bin/amplitude-ai.mjs +14 -5
- package/data/agent_event_catalog.json +52 -2
- package/dist/bound-agent.d.ts +18 -14
- package/dist/bound-agent.d.ts.map +1 -1
- package/dist/bound-agent.js +4 -1
- package/dist/bound-agent.js.map +1 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +31 -19
- package/dist/cli/status.js.map +1 -1
- package/dist/client.d.ts +14 -14
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +38 -0
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +5 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +4 -0
- package/dist/context.js.map +1 -1
- package/dist/core/constants.d.ts +3 -1
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +3 -1
- package/dist/core/constants.js.map +1 -1
- package/dist/core/tracking.d.ts +12 -2
- package/dist/core/tracking.d.ts.map +1 -1
- package/dist/core/tracking.js +13 -2
- package/dist/core/tracking.js.map +1 -1
- package/dist/decorators.d.ts +1 -1
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +4 -3
- package/dist/decorators.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -2
- package/dist/mcp/contract.d.ts +4 -0
- package/dist/mcp/contract.d.ts.map +1 -1
- package/dist/mcp/contract.js +6 -2
- package/dist/mcp/contract.js.map +1 -1
- package/dist/mcp/generate-verify-test.d.ts +7 -0
- package/dist/mcp/generate-verify-test.d.ts.map +1 -0
- package/dist/mcp/generate-verify-test.js +25 -0
- package/dist/mcp/generate-verify-test.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -1
- package/dist/mcp/index.js +2 -1
- package/dist/mcp/instrument-file.d.ts +14 -0
- package/dist/mcp/instrument-file.d.ts.map +1 -0
- package/dist/mcp/instrument-file.js +139 -0
- package/dist/mcp/instrument-file.js.map +1 -0
- package/dist/mcp/scan-project.d.ts +52 -0
- package/dist/mcp/scan-project.d.ts.map +1 -0
- package/dist/mcp/scan-project.js +309 -0
- package/dist/mcp/scan-project.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +79 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/validate-file.d.ts +4 -0
- package/dist/mcp/validate-file.d.ts.map +1 -1
- package/dist/mcp/validate-file.js +559 -11
- package/dist/mcp/validate-file.js.map +1 -1
- package/dist/middleware.js +2 -1
- package/dist/middleware.js.map +1 -1
- package/dist/node_modules/.pnpm/acorn-typescript@1.4.13_acorn@8.16.0/node_modules/acorn-typescript/lib/index.js +2389 -0
- package/dist/node_modules/.pnpm/acorn-typescript@1.4.13_acorn@8.16.0/node_modules/acorn-typescript/lib/index.js.map +1 -0
- package/dist/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/dist/acorn.js +5128 -0
- package/dist/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/dist/acorn.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +1 -0
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/base.d.ts +2 -1
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/base.js +4 -0
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +2 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/serverless.d.ts +19 -0
- package/dist/serverless.d.ts.map +1 -0
- package/dist/serverless.js +35 -0
- package/dist/serverless.js.map +1 -0
- package/dist/session.d.ts +24 -8
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +20 -1
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/costs.d.ts.map +1 -1
- package/dist/utils/costs.js +5 -1
- package/dist/utils/costs.js.map +1 -1
- package/llms-full.txt +353 -69
- package/llms.txt +6 -2
- package/mcp.schema.json +7 -3
- package/package.json +10 -5
- package/bin/amplitude-ai-init.mjs +0 -27
- package/dist/cli/init.d.ts +0 -14
- package/dist/cli/init.d.ts.map +0 -1
- package/dist/cli/init.js +0 -40
- package/dist/cli/init.js.map +0 -1
package/dist/session.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getLogger } from "./utils/logger.js";
|
|
2
2
|
import { PROP_SESSION_REPLAY_ID } from "./core/constants.js";
|
|
3
3
|
import { SessionContext, _sessionStorage, getActiveContext } from "./context.js";
|
|
4
|
+
import { isServerless } from "./serverless.js";
|
|
4
5
|
import { randomUUID } from "node:crypto";
|
|
5
6
|
|
|
6
7
|
//#region src/session.ts
|
|
@@ -26,6 +27,7 @@ var Session = class Session {
|
|
|
26
27
|
userId;
|
|
27
28
|
deviceId;
|
|
28
29
|
browserSessionId;
|
|
30
|
+
autoFlush;
|
|
29
31
|
_agent;
|
|
30
32
|
_enrichments = null;
|
|
31
33
|
_sessionReplayId;
|
|
@@ -35,6 +37,7 @@ var Session = class Session {
|
|
|
35
37
|
this.userId = opts.userId ?? null;
|
|
36
38
|
this.deviceId = opts.deviceId ?? agent._defaults.deviceId;
|
|
37
39
|
this.browserSessionId = opts.browserSessionId ?? agent._defaults.browserSessionId;
|
|
40
|
+
this.autoFlush = opts.autoFlush ?? isServerless();
|
|
38
41
|
this._agent = agent;
|
|
39
42
|
this._sessionReplayId = this.deviceId && this.browserSessionId ? `${this.deviceId}/${this.browserSessionId}` : null;
|
|
40
43
|
}
|
|
@@ -51,12 +54,14 @@ var Session = class Session {
|
|
|
51
54
|
env: defaults.env,
|
|
52
55
|
customerOrgId: defaults.customerOrgId,
|
|
53
56
|
agentVersion: defaults.agentVersion,
|
|
57
|
+
description: defaults.description,
|
|
54
58
|
context: defaults.context,
|
|
55
59
|
groups: defaults.groups,
|
|
56
60
|
idleTimeoutMinutes: this.idleTimeoutMinutes,
|
|
57
61
|
deviceId: this.deviceId ?? defaults.deviceId,
|
|
58
62
|
browserSessionId: this.browserSessionId ?? defaults.browserSessionId,
|
|
59
|
-
nextTurnIdFn: () => ai._nextTurnId(sid)
|
|
63
|
+
nextTurnIdFn: () => ai._nextTurnId(sid),
|
|
64
|
+
amplitude: ai.amplitude
|
|
60
65
|
});
|
|
61
66
|
}
|
|
62
67
|
newTrace() {
|
|
@@ -71,6 +76,11 @@ var Session = class Session {
|
|
|
71
76
|
/**
|
|
72
77
|
* Run a callback within this session context.
|
|
73
78
|
* This is the Node.js equivalent of Python's `with session as s:` block.
|
|
79
|
+
*
|
|
80
|
+
* When {@link autoFlush} is `true` (default in serverless environments),
|
|
81
|
+
* all pending events are flushed before the promise resolves. This
|
|
82
|
+
* prevents event loss when the serverless runtime freezes or terminates
|
|
83
|
+
* after the handler returns.
|
|
74
84
|
*/
|
|
75
85
|
async run(fn) {
|
|
76
86
|
const ctx = this._buildSessionContext();
|
|
@@ -78,6 +88,7 @@ var Session = class Session {
|
|
|
78
88
|
return await _sessionStorage.run(ctx, () => fn(this));
|
|
79
89
|
} finally {
|
|
80
90
|
this._autoEnd();
|
|
91
|
+
if (this.autoFlush) await this._flush();
|
|
81
92
|
}
|
|
82
93
|
}
|
|
83
94
|
/**
|
|
@@ -147,6 +158,14 @@ var Session = class Session {
|
|
|
147
158
|
getLogger().debug(`Failed to auto-end session ${this.sessionId}: ${e}`);
|
|
148
159
|
}
|
|
149
160
|
}
|
|
161
|
+
async _flush() {
|
|
162
|
+
try {
|
|
163
|
+
const result = this._agent.flush();
|
|
164
|
+
if (result != null && typeof result.then === "function") await result;
|
|
165
|
+
} catch (e) {
|
|
166
|
+
getLogger().debug(`Failed to flush after session ${this.sessionId}: ${e}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
150
169
|
_inject(kwargs) {
|
|
151
170
|
const merged = { ...kwargs };
|
|
152
171
|
if (merged.sessionId == null) merged.sessionId = this.sessionId;
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","names":["endOpts: SessionEndOpts"],"sources":["../src/session.ts"],"sourcesContent":["/**\n * Session context manager using Node.js AsyncLocalStorage.\n *\n * Use `.run()` to execute code within session context. The session\n * auto-ends when the callback completes, emitting `[Agent] Session End`.\n *\n * @example\n * ```typescript\n * const session = agent.session();\n * await session.run(async (s) => {\n * s.trackUserMessage('What is retention?');\n * s.trackAiMessage('Retention is...', 'gpt-4', 'openai', 200);\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n AiMessageOpts,\n BoundAgent,\n EmbeddingOpts,\n ScoreOpts,\n SessionEndOpts,\n SpanOpts,\n ToolCallOpts,\n UserMessageOpts,\n} from './bound-agent.js';\nimport {\n _sessionStorage,\n getActiveContext,\n SessionContext,\n} from './context.js';\nimport type { SessionEnrichments } from './core/enrichments.js';\nimport { PROP_SESSION_REPLAY_ID } from './core/tracking.js';\nimport { getLogger } from './utils/logger.js';\n\nexport class Session {\n readonly sessionId: string;\n traceId: string | null = null;\n readonly idleTimeoutMinutes: number | null;\n readonly userId: string | null;\n readonly deviceId: string | null;\n readonly browserSessionId: string | null;\n private _agent: BoundAgent;\n private _enrichments: SessionEnrichments | null = null;\n private _sessionReplayId: string | null;\n\n constructor(\n agent: BoundAgent,\n opts: {\n sessionId?: string | null;\n idleTimeoutMinutes?: number | null;\n userId?: string | null;\n deviceId?: string | null;\n browserSessionId?: string | null;\n } = {},\n ) {\n this.sessionId = opts.sessionId ?? randomUUID();\n this.idleTimeoutMinutes = opts.idleTimeoutMinutes ?? null;\n this.userId = opts.userId ?? null;\n this.deviceId =\n opts.deviceId ?? (agent._defaults.deviceId as string | null);\n this.browserSessionId =\n opts.browserSessionId ??\n (agent._defaults.browserSessionId as string | null);\n this._agent = agent;\n this._sessionReplayId =\n this.deviceId && this.browserSessionId\n ? `${this.deviceId}/${this.browserSessionId}`\n : null;\n }\n\n private _buildSessionContext(): SessionContext {\n const defaults = this._agent._defaults;\n const ai = this._agent._ai;\n const sid = this.sessionId;\n\n return new SessionContext({\n sessionId: sid,\n traceId: this.traceId,\n userId: (this.userId ?? defaults.userId) as string | null,\n agentId: defaults.agentId as string | null,\n parentAgentId: defaults.parentAgentId as string | null,\n env: defaults.env as string | null,\n customerOrgId: defaults.customerOrgId as string | null,\n agentVersion: defaults.agentVersion as string | null,\n context: defaults.context as Record<string, unknown> | null,\n groups: defaults.groups as Record<string, unknown> | null,\n idleTimeoutMinutes: this.idleTimeoutMinutes,\n deviceId: this.deviceId ?? (defaults.deviceId as string | null),\n browserSessionId:\n this.browserSessionId ?? (defaults.browserSessionId as string | null),\n nextTurnIdFn: () => ai._nextTurnId(sid),\n });\n }\n\n newTrace(): string {\n this.traceId = randomUUID();\n const ctx = getActiveContext();\n if (ctx != null) {\n ctx.traceId = this.traceId;\n }\n return this.traceId;\n }\n\n setEnrichments(enrichments: SessionEnrichments): void {\n this._enrichments = enrichments;\n }\n\n /**\n * Run a callback within this session context.\n * This is the Node.js equivalent of Python's `with session as s:` block.\n */\n async run<T>(fn: (session: Session) => T | Promise<T>): Promise<T> {\n const ctx = this._buildSessionContext();\n try {\n const result = await _sessionStorage.run(ctx, () => fn(this));\n return result;\n } finally {\n this._autoEnd();\n }\n }\n\n /**\n * Synchronous version of run() for non-async code.\n */\n runSync<T>(fn: (session: Session) => T): T {\n const ctx = this._buildSessionContext();\n try {\n return _sessionStorage.run(ctx, () => fn(this));\n } finally {\n this._autoEnd();\n }\n }\n\n /**\n * Run a callback as a child agent within this session.\n *\n * Provider wrappers automatically pick up the child agent's identity\n * (`agentId`, `parentAgentId`) while sharing this session's `sessionId`,\n * `traceId`, and turn counter. No `[Agent] Session End` is emitted.\n *\n * @example\n * ```typescript\n * const child = parentAgent.child('researcher');\n * await session.run(async (s) => {\n * const result = await s.runAs(child, async (cs) => {\n * // provider wrappers see agentId='researcher'\n * return openai.chat.completions.create({ ... });\n * });\n * });\n * ```\n */\n async runAs<T>(\n childAgent: BoundAgent,\n fn: (session: Session) => T | Promise<T>,\n ): Promise<T> {\n const childSession = new Session(childAgent, {\n sessionId: this.sessionId,\n userId: this.userId,\n deviceId: this.deviceId,\n browserSessionId: this.browserSessionId,\n });\n childSession.traceId = this.traceId;\n const ctx = childSession._buildSessionContext();\n return await _sessionStorage.run(ctx, () => fn(childSession));\n }\n\n /**\n * Synchronous version of {@link runAs}.\n */\n runAsSync<T>(\n childAgent: BoundAgent,\n fn: (session: Session) => T,\n ): T {\n const childSession = new Session(childAgent, {\n sessionId: this.sessionId,\n userId: this.userId,\n deviceId: this.deviceId,\n browserSessionId: this.browserSessionId,\n });\n childSession.traceId = this.traceId;\n const ctx = childSession._buildSessionContext();\n return _sessionStorage.run(ctx, () => fn(childSession));\n }\n\n private _autoEnd(): void {\n try {\n const endOpts: SessionEndOpts = {\n sessionId: this.sessionId,\n enrichments: this._enrichments,\n idleTimeoutMinutes: this.idleTimeoutMinutes,\n };\n if (this.userId != null) endOpts.userId = this.userId;\n this._agent.trackSessionEnd(this._inject(endOpts));\n } catch (e) {\n getLogger().debug(`Failed to auto-end session ${this.sessionId}: ${e}`);\n }\n }\n\n private _inject<T extends Record<string, unknown>>(kwargs: T): T {\n const merged = { ...kwargs } as Record<string, unknown>;\n if (merged.sessionId == null) merged.sessionId = this.sessionId;\n if (this.traceId != null && merged.traceId == null)\n merged.traceId = this.traceId;\n if (this.userId != null && merged.userId == null)\n merged.userId = this.userId;\n if (this._sessionReplayId != null) {\n const existingEp = merged.eventProperties as\n | Record<string, unknown>\n | undefined;\n const ep = existingEp != null ? { ...existingEp } : {};\n if (!(PROP_SESSION_REPLAY_ID in ep)) {\n ep[PROP_SESSION_REPLAY_ID] = this._sessionReplayId;\n merged.eventProperties = ep;\n }\n }\n return merged as T;\n }\n\n trackUserMessage(content: string, opts: UserMessageOpts = {}): string {\n return this._agent.trackUserMessage(content, this._inject(opts));\n }\n\n trackAiMessage(\n content: string,\n model: string,\n provider: string,\n latencyMs: number,\n opts: AiMessageOpts = {},\n ): string {\n return this._agent.trackAiMessage(\n content,\n model,\n provider,\n latencyMs,\n this._inject(opts),\n );\n }\n\n trackToolCall(\n toolName: string,\n latencyMs: number,\n success: boolean,\n opts: ToolCallOpts = {},\n ): string {\n return this._agent.trackToolCall(\n toolName,\n latencyMs,\n success,\n this._inject(opts),\n );\n }\n\n trackEmbedding(\n model: string,\n provider: string,\n latencyMs: number,\n opts: EmbeddingOpts = {},\n ): string {\n return this._agent.trackEmbedding(\n model,\n provider,\n latencyMs,\n this._inject(opts),\n );\n }\n\n trackSpan(spanName: string, latencyMs: number, opts: SpanOpts = {}): string {\n return this._agent.trackSpan(spanName, latencyMs, this._inject(opts));\n }\n\n score(\n name: string,\n value: number,\n targetId: string,\n opts: ScoreOpts = {},\n ): void {\n this._agent.score(name, value, targetId, this._inject(opts));\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.js","names":["endOpts: SessionEndOpts"],"sources":["../src/session.ts"],"sourcesContent":["/**\n * Session context manager using Node.js AsyncLocalStorage.\n *\n * Use `.run()` to execute code within session context. The session\n * auto-ends when the callback completes, emitting `[Agent] Session End`.\n *\n * @example\n * ```typescript\n * const session = agent.session();\n * await session.run(async (s) => {\n * s.trackUserMessage('What is retention?');\n * s.trackAiMessage('Retention is...', 'gpt-4', 'openai', 200);\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n AiMessageOpts,\n BoundAgent,\n EmbeddingOpts,\n ScoreOpts,\n SessionEndOpts,\n SpanOpts,\n ToolCallOpts,\n UserMessageOpts,\n} from './bound-agent.js';\nimport {\n _sessionStorage,\n getActiveContext,\n SessionContext,\n} from './context.js';\nimport type { SessionEnrichments } from './core/enrichments.js';\nimport { PROP_SESSION_REPLAY_ID } from './core/tracking.js';\nimport { isServerless } from './serverless.js';\nimport { getLogger } from './utils/logger.js';\n\nexport interface SessionOptions {\n sessionId?: string | null;\n idleTimeoutMinutes?: number | null;\n userId?: string | null;\n deviceId?: string | null;\n browserSessionId?: string | null;\n /**\n * Automatically flush pending events when `run()` completes.\n *\n * - `true` — always flush (recommended for serverless)\n * - `false` — never flush (for long-running servers where the periodic timer handles it)\n * - `undefined` (default) — auto-detect: flush if a serverless environment is detected\n */\n autoFlush?: boolean;\n}\n\nexport class Session {\n readonly sessionId: string;\n traceId: string | null = null;\n readonly idleTimeoutMinutes: number | null;\n readonly userId: string | null;\n readonly deviceId: string | null;\n readonly browserSessionId: string | null;\n readonly autoFlush: boolean;\n private _agent: BoundAgent;\n private _enrichments: SessionEnrichments | null = null;\n private _sessionReplayId: string | null;\n\n constructor(agent: BoundAgent, opts: SessionOptions = {}) {\n this.sessionId = opts.sessionId ?? randomUUID();\n this.idleTimeoutMinutes = opts.idleTimeoutMinutes ?? null;\n this.userId = opts.userId ?? null;\n this.deviceId =\n opts.deviceId ?? (agent._defaults.deviceId as string | null);\n this.browserSessionId =\n opts.browserSessionId ??\n (agent._defaults.browserSessionId as string | null);\n this.autoFlush = opts.autoFlush ?? isServerless();\n this._agent = agent;\n this._sessionReplayId =\n this.deviceId && this.browserSessionId\n ? `${this.deviceId}/${this.browserSessionId}`\n : null;\n }\n\n private _buildSessionContext(): SessionContext {\n const defaults = this._agent._defaults;\n const ai = this._agent._ai;\n const sid = this.sessionId;\n\n return new SessionContext({\n sessionId: sid,\n traceId: this.traceId,\n userId: (this.userId ?? defaults.userId) as string | null,\n agentId: defaults.agentId as string | null,\n parentAgentId: defaults.parentAgentId as string | null,\n env: defaults.env as string | null,\n customerOrgId: defaults.customerOrgId as string | null,\n agentVersion: defaults.agentVersion as string | null,\n description: defaults.description as string | null,\n context: defaults.context as Record<string, unknown> | null,\n groups: defaults.groups as Record<string, unknown> | null,\n idleTimeoutMinutes: this.idleTimeoutMinutes,\n deviceId: this.deviceId ?? (defaults.deviceId as string | null),\n browserSessionId:\n this.browserSessionId ?? (defaults.browserSessionId as string | null),\n nextTurnIdFn: () => ai._nextTurnId(sid),\n amplitude: ai.amplitude,\n });\n }\n\n newTrace(): string {\n this.traceId = randomUUID();\n const ctx = getActiveContext();\n if (ctx != null) {\n ctx.traceId = this.traceId;\n }\n return this.traceId;\n }\n\n setEnrichments(enrichments: SessionEnrichments): void {\n this._enrichments = enrichments;\n }\n\n /**\n * Run a callback within this session context.\n * This is the Node.js equivalent of Python's `with session as s:` block.\n *\n * When {@link autoFlush} is `true` (default in serverless environments),\n * all pending events are flushed before the promise resolves. This\n * prevents event loss when the serverless runtime freezes or terminates\n * after the handler returns.\n */\n async run<T>(fn: (session: Session) => T | Promise<T>): Promise<T> {\n const ctx = this._buildSessionContext();\n try {\n const result = await _sessionStorage.run(ctx, () => fn(this));\n return result;\n } finally {\n this._autoEnd();\n if (this.autoFlush) {\n await this._flush();\n }\n }\n }\n\n /**\n * Synchronous version of run() for non-async code.\n */\n runSync<T>(fn: (session: Session) => T): T {\n const ctx = this._buildSessionContext();\n try {\n return _sessionStorage.run(ctx, () => fn(this));\n } finally {\n this._autoEnd();\n }\n }\n\n /**\n * Run a callback as a child agent within this session.\n *\n * Provider wrappers automatically pick up the child agent's identity\n * (`agentId`, `parentAgentId`) while sharing this session's `sessionId`,\n * `traceId`, and turn counter. No `[Agent] Session End` is emitted.\n *\n * @example\n * ```typescript\n * const child = parentAgent.child('researcher');\n * await session.run(async (s) => {\n * const result = await s.runAs(child, async (cs) => {\n * // provider wrappers see agentId='researcher'\n * return openai.chat.completions.create({ ... });\n * });\n * });\n * ```\n */\n async runAs<T>(\n childAgent: BoundAgent,\n fn: (session: Session) => T | Promise<T>,\n ): Promise<T> {\n const childSession = new Session(childAgent, {\n sessionId: this.sessionId,\n userId: this.userId,\n deviceId: this.deviceId,\n browserSessionId: this.browserSessionId,\n });\n childSession.traceId = this.traceId;\n const ctx = childSession._buildSessionContext();\n return await _sessionStorage.run(ctx, () => fn(childSession));\n }\n\n /**\n * Synchronous version of {@link runAs}.\n */\n runAsSync<T>(\n childAgent: BoundAgent,\n fn: (session: Session) => T,\n ): T {\n const childSession = new Session(childAgent, {\n sessionId: this.sessionId,\n userId: this.userId,\n deviceId: this.deviceId,\n browserSessionId: this.browserSessionId,\n });\n childSession.traceId = this.traceId;\n const ctx = childSession._buildSessionContext();\n return _sessionStorage.run(ctx, () => fn(childSession));\n }\n\n private _autoEnd(): void {\n try {\n const endOpts: SessionEndOpts = {\n sessionId: this.sessionId,\n enrichments: this._enrichments,\n idleTimeoutMinutes: this.idleTimeoutMinutes,\n };\n if (this.userId != null) endOpts.userId = this.userId;\n this._agent.trackSessionEnd(this._inject(endOpts));\n } catch (e) {\n getLogger().debug(`Failed to auto-end session ${this.sessionId}: ${e}`);\n }\n }\n\n private async _flush(): Promise<void> {\n try {\n const result = this._agent.flush();\n if (result != null && typeof (result as Promise<unknown>).then === 'function') {\n await result;\n }\n } catch (e) {\n getLogger().debug(`Failed to flush after session ${this.sessionId}: ${e}`);\n }\n }\n\n private _inject<T extends Record<string, unknown>>(kwargs: T): T {\n const merged = { ...kwargs } as Record<string, unknown>;\n if (merged.sessionId == null) merged.sessionId = this.sessionId;\n if (this.traceId != null && merged.traceId == null)\n merged.traceId = this.traceId;\n if (this.userId != null && merged.userId == null)\n merged.userId = this.userId;\n if (this._sessionReplayId != null) {\n const existingEp = merged.eventProperties as\n | Record<string, unknown>\n | undefined;\n const ep = existingEp != null ? { ...existingEp } : {};\n if (!(PROP_SESSION_REPLAY_ID in ep)) {\n ep[PROP_SESSION_REPLAY_ID] = this._sessionReplayId;\n merged.eventProperties = ep;\n }\n }\n return merged as T;\n }\n\n trackUserMessage(content: string, opts: UserMessageOpts = {}): string {\n return this._agent.trackUserMessage(content, this._inject(opts));\n }\n\n trackAiMessage(\n content: string,\n model: string,\n provider: string,\n latencyMs: number,\n opts: AiMessageOpts = {},\n ): string {\n return this._agent.trackAiMessage(\n content,\n model,\n provider,\n latencyMs,\n this._inject(opts),\n );\n }\n\n trackToolCall(\n toolName: string,\n latencyMs: number,\n success: boolean,\n opts: ToolCallOpts = {},\n ): string {\n return this._agent.trackToolCall(\n toolName,\n latencyMs,\n success,\n this._inject(opts),\n );\n }\n\n trackEmbedding(\n model: string,\n provider: string,\n latencyMs: number,\n opts: EmbeddingOpts = {},\n ): string {\n return this._agent.trackEmbedding(\n model,\n provider,\n latencyMs,\n this._inject(opts),\n );\n }\n\n trackSpan(spanName: string, latencyMs: number, opts: SpanOpts = {}): string {\n return this._agent.trackSpan(spanName, latencyMs, this._inject(opts));\n }\n\n score(\n name: string,\n value: number,\n targetId: string,\n opts: ScoreOpts = {},\n ): void {\n this._agent.score(name, value, targetId, this._inject(opts));\n }\n}\n"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -359,6 +359,7 @@ interface TrackCallOptions {
|
|
|
359
359
|
parentAgentId?: string | null;
|
|
360
360
|
customerOrgId?: string | null;
|
|
361
361
|
agentVersion?: string | null;
|
|
362
|
+
description?: string | null;
|
|
362
363
|
context?: Record<string, unknown> | null;
|
|
363
364
|
env?: string | null;
|
|
364
365
|
groups?: Record<string, unknown> | null;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AAkBA;;;;;AAeA;AAQA;AAeA;AAQA;AAKA;AA0BA;AAWA;AAciB,UAtGA,cAAA,CAsGsB;EAStB,UAAA,EAAA,MAAU;EAQV,OAAA,CAAA,EAAA,MAAA;EASA,SAAA,CAAA,EAAA,MAAA;EASA,UAAA,CAAA,EAAA,MAAA;EASA,gBAAA,CAAA,EA7II,MA6IJ,CAAA,MAAwB,EAAA,OAG7B,CAAA;EAOK,eAAA,CAAA,EAtJG,MAsJgB,CAAA,MAAA,EAAA,OAAA,CAAA;EAcnB,MAAA,CAAA,EAnKN,MAmKM,CAAA,MAAc,EAAA,OAIpB,CAAA;EAYM,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAe;AAahC;AAUA;AAYA;AAeA;;AAGkB,UAhOD,aAAA,CAgOC;EACH,KAAA,EAAA,CAAA,KAAA,EAhOE,cAgOF,EAAA,GAAA,IAAA;;AAMf;AASA;AASA;AAQA;AAYiB,UArQA,mBAAA,SAA4B,aAqQP,CAAA;EASrB,KAAA,EAAA,GAAA,GAAA,OAAA;EAqBA,QAAA,CAAA,EAAA,GAAA,GAAA,IAAiB;EAYjB,IAAA,CAAA,EAAA,CAAA,MAAA,EAAA,MAAmB,EAAA,GAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AAkBA;;;;;AAeA;AAQA;AAeA;AAQA;AAKA;AA0BA;AAWA;AAciB,UAtGA,cAAA,CAsGsB;EAStB,UAAA,EAAA,MAAU;EAQV,OAAA,CAAA,EAAA,MAAA;EASA,SAAA,CAAA,EAAA,MAAA;EASA,UAAA,CAAA,EAAA,MAAA;EASA,gBAAA,CAAA,EA7II,MA6IJ,CAAA,MAAwB,EAAA,OAG7B,CAAA;EAOK,eAAA,CAAA,EAtJG,MAsJgB,CAAA,MAAA,EAAA,OAAA,CAAA;EAcnB,MAAA,CAAA,EAnKN,MAmKM,CAAA,MAAc,EAAA,OAIpB,CAAA;EAYM,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAe;AAahC;AAUA;AAYA;AAeA;;AAGkB,UAhOD,aAAA,CAgOC;EACH,KAAA,EAAA,CAAA,KAAA,EAhOE,cAgOF,EAAA,GAAA,IAAA;;AAMf;AASA;AASA;AAQA;AAYiB,UArQA,mBAAA,SAA4B,aAqQP,CAAA;EASrB,KAAA,EAAA,GAAA,GAAA,OAAA;EAqBA,QAAA,CAAA,EAAA,GAAA,GAAA,IAAiB;EAYjB,IAAA,CAAA,EAAA,CAAA,MAAA,EAAA,MAAmB,EAAA,GAAA,OAAA;EASnB,aAAA,CAAA,EApTC,MAoTY,CAAA,MAAA,EAAA,OAAA,CAAA;AAQ9B;AAaA;AASA;AAkBA;AAUA;;;;;AA6BoC,UAhYnB,eAAA,CAgYmB;EAAtB,SAAA,SAAA,EA/XQ,mBA+XR;;;;;;KAxXF,aAAA,GAAgB,gBAAgB;;;;iBAK5B,gBAAA,QAAwB,gBAAgB;;;;;UA0BvC,WAAA;;;;eAIF;;;;;;UAOE,oBAAA;;YAEL;;;;;;;;;;;UAYK,sBAAA;;WAEN;UACD;;;;;UAMO,UAAA;;;iBACkC;;;;;;;UAOlC,gBAAA;;;;;;;;UASA,mBAAA;;qBAEI;;;;;;;;;UAOJ,+BAAA;;;;;;;;UASA,wBAAA;;;YAGL;;;;;;UAOK,mBAAA;;;;;;;;;;;;;UAcA,cAAA;;;;WAIN;UACD;;;;;;UAWO,eAAA;;;;;;;;;;;;UAaA,iBAAA;;WAEN;SACF;;;;;;UAOQ,YAAA;;;;;;;;;;;UAYA,mBAAA;;;;;;;;;;UAeA,cAAA;aACJ;;kBAEK;eACH;;;;;UAME,oBAAA;;kBAEC;eACH;;;;;UAME,mBAAA;;;;;;;;UASA,eAAA;;;YAEK;;;;;;UAML,UAAA;;;;UAEsB;;;;;;UAUtB,qBAAA;;;;;;;;UASA,uBAAA;;;gBAGD;;;;;;;;;;;;;;;UAkBC,iBAAA;;;;;;;;;;;UAYA,mBAAA;;YAEL;UACF;;;;;UAMO,aAAA;;;;;;;;;UAQA,iBAAA;;;;;;;;UAaA,aAAA;;;;;;;;UASA,UAAA;;;;;;;;;;;;;;;;;KAkBL,OAAA,UAAiB;;;;;;;;;UAUZ,gBAAA;;;;;;;;;;;;;;YAcL;;WAED;oBACS;;;;;;;;;;;;cAYN,MAAM,gBAAgB"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["/**\n * Shared type definitions for the Amplitude AI SDK.\n *\n * Structural interfaces for provider request/response shapes,\n * events, and the core AmplitudeLike contract. These are\n * \"duck-typed\" interfaces — they describe the subset of each\n * provider SDK's shape that we actually use, without importing\n * the real SDK types.\n */\n\n// ---------------------------------------------------------------------------\n// Amplitude client contract\n// ---------------------------------------------------------------------------\n\n/**\n * Event payload shape for Amplitude tracking.\n * Used when passing events to `AmplitudeLike.track()`.\n */\nexport interface AmplitudeEvent {\n event_type: string;\n user_id?: string;\n device_id?: string;\n session_id?: number;\n event_properties?: Record<string, unknown>;\n user_properties?: Record<string, unknown>;\n groups?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Contract for Amplitude analytics clients.\n * Any object with a `track(event)` method satisfies this interface.\n */\nexport interface AmplitudeLike {\n track: (event: AmplitudeEvent) => void;\n}\n\n/**\n * Extended Amplitude client with flush, shutdown, and optional init.\n * Used by the SDK when it owns or receives an Amplitude instance.\n */\nexport interface AmplitudeClientLike extends AmplitudeLike {\n flush: () => unknown;\n shutdown?: () => void;\n init?: (apiKey: string) => unknown;\n configuration?: Record<string, unknown>;\n}\n\n/**\n * Structural type matching AmplitudeAI instances.\n * Allows providers to accept either an AmplitudeLike (raw analytics client)\n * or an AmplitudeAI instance (which exposes `.amplitude` getter).\n * This avoids circular imports while enabling the convenience pattern:\n * new OpenAI({ amplitude: ai }) // AmplitudeAI\n * new OpenAI({ amplitude: amp }) // raw Amplitude client\n */\nexport interface AmplitudeAILike {\n readonly amplitude: AmplitudeClientLike;\n}\n\n/**\n * Union type accepted by provider constructors.\n * Providers call `resolveAmplitude()` to normalize to `AmplitudeLike`.\n */\nexport type AmplitudeOrAI = AmplitudeLike | AmplitudeAILike;\n\n/**\n * Resolve an `AmplitudeOrAI` value to a plain `AmplitudeLike`.\n */\nexport function resolveAmplitude(input: AmplitudeOrAI): AmplitudeLike {\n if (\n 'amplitude' in input &&\n typeof input.amplitude === 'object' &&\n input.amplitude !== null &&\n 'track' in input.amplitude\n ) {\n return input.amplitude;\n }\n if ('track' in input && typeof input.track === 'function') {\n return input as AmplitudeLike;\n }\n throw new Error(\n 'Expected an AmplitudeLike (with .track()) or AmplitudeAI (with .amplitude) instance. ' +\n 'Pass either your AmplitudeAI instance or ai.amplitude.',\n );\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI-compatible shapes (also used by Azure OpenAI)\n// ---------------------------------------------------------------------------\n\n/**\n * Single message in a chat completion request.\n * Supports role, content, optional name, and tool calls.\n */\nexport interface ChatMessage {\n role: string;\n content?: string | null;\n name?: string;\n tool_calls?: ToolCallShape[];\n}\n\n/**\n * Structural interface for OpenAI-compatible chat completion parameters.\n * Used by the OpenAI and Azure OpenAI provider wrappers.\n */\nexport interface ChatCompletionParams {\n model: string;\n messages: ChatMessage[];\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n stream?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI-compatible chat completion responses.\n * Describes the subset of the OpenAI SDK's response shape that the SDK tracks.\n */\nexport interface ChatCompletionResponse {\n model: string;\n choices: ChatChoice[];\n usage?: OpenAITokenUsage;\n}\n\n/**\n * Single choice in a chat completion response.\n */\nexport interface ChatChoice {\n message: { content?: string | null; tool_calls?: ToolCallShape[] };\n finish_reason?: string;\n}\n\n/**\n * Token usage metadata for OpenAI/Azure OpenAI responses.\n */\nexport interface OpenAITokenUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\n/**\n * Structural interface for OpenAI Responses API request input items.\n */\nexport interface OpenAIResponseInput {\n role?: string;\n content?: string | Array<{ text?: string; [key: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API output content blocks.\n */\nexport interface OpenAIResponseOutputContentItem {\n type?: string;\n text?: string;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API output items.\n */\nexport interface OpenAIResponseOutputItem {\n type?: string;\n status?: string;\n content?: OpenAIResponseOutputContentItem[];\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API usage metadata.\n */\nexport interface OpenAIResponseUsage {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n output_tokens_details?: {\n reasoning_tokens?: number;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API responses.\n */\nexport interface OpenAIResponse {\n model?: string;\n status?: string;\n output_text?: string;\n output?: OpenAIResponseOutputItem[];\n usage?: OpenAIResponseUsage;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Anthropic chat completion request parameters.\n */\nexport interface AnthropicParams {\n model: string;\n system?: string;\n messages: unknown[];\n max_tokens?: number;\n temperature?: number;\n top_p?: number;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for Anthropic chat completion responses.\n */\nexport interface AnthropicResponse {\n model: string;\n content: ContentBlock[];\n usage: AnthropicTokenUsage;\n stop_reason?: string;\n}\n\n/**\n * Content block in an Anthropic response (text, thinking, or tool_use).\n */\nexport interface ContentBlock {\n type: 'text' | 'thinking' | 'tool_use';\n text?: string;\n thinking?: string;\n name?: string;\n input?: unknown;\n id?: string;\n}\n\n/**\n * Token usage metadata for Anthropic responses.\n */\nexport interface AnthropicTokenUsage {\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Gemini shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Google Gemini API responses.\n * Supports both response object and legacy text/usageMetadata shape.\n */\nexport interface GeminiResponse {\n response?: GeminiResponseObject;\n text?: (() => string) | string;\n usageMetadata?: GeminiUsageMetadata;\n candidates?: GeminiCandidate[];\n}\n\n/**\n * Wrapper object for Gemini response (response.text, usageMetadata, candidates).\n */\nexport interface GeminiResponseObject {\n text?: () => string;\n usageMetadata?: GeminiUsageMetadata;\n candidates?: GeminiCandidate[];\n}\n\n/**\n * Token usage metadata for Gemini responses.\n */\nexport interface GeminiUsageMetadata {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n}\n\n/**\n * Single candidate in a Gemini response.\n */\nexport interface GeminiCandidate {\n finishReason?: string;\n content?: { parts?: GeminiPart[] };\n}\n\n/**\n * Part of a Gemini candidate (text or functionCall).\n */\nexport interface GeminiPart {\n text?: string;\n functionCall?: { name: string; args: Record<string, unknown> };\n}\n\n// ---------------------------------------------------------------------------\n// Bedrock shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for AWS Bedrock Converse API request parameters.\n */\nexport interface BedrockConverseParams {\n modelId: string;\n messages?: unknown[];\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for AWS Bedrock Converse API responses.\n */\nexport interface BedrockConverseResponse {\n output?: {\n message?: {\n content?: Array<{ text?: string }>;\n };\n };\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n stopReason?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Mistral shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Mistral chat completion request parameters.\n */\nexport interface MistralChatParams {\n model: string;\n messages: unknown[];\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for Mistral chat completion responses.\n */\nexport interface MistralChatResponse {\n model?: string;\n choices?: MistralChoice[];\n usage?: MistralTokenUsage;\n}\n\n/**\n * Single choice in a Mistral chat response.\n */\nexport interface MistralChoice {\n message?: { content?: string | unknown[] | null };\n finish_reason?: string;\n}\n\n/**\n * Token usage metadata for Mistral responses.\n */\nexport interface MistralTokenUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Shape of a tool/function call across provider SDKs.\n */\nexport interface ToolCallShape {\n name: string;\n arguments?: unknown;\n id?: string;\n}\n\n/**\n * File or URL attachment for messages (e.g., image, document).\n */\nexport interface Attachment {\n type: string;\n name?: string;\n content?: string;\n url?: string;\n size_bytes?: number;\n}\n\n/**\n * Callback used by provider wrappers to emit an AI response tracking event.\n *\n * Provider wrappers (OpenAI, Anthropic, etc.) receive a `TrackFn` via\n * `BaseAIProvider.trackFn()` and call it after each completion or stream\n * finishes. The function serializes the options into an Amplitude event\n * and sends it via the underlying Amplitude client.\n *\n * @returns The generated message ID for the tracked event.\n */\nexport type TrackFn = (opts: TrackCallOptions) => string;\n\n/**\n * Options passed to the internal track function for LLM completion events.\n *\n * This is the unified shape used by all provider wrappers to report a\n * single AI completion (streaming or non-streaming). Fields like\n * `reasoningTokens`, `cacheReadInputTokens`, and `totalCostUsd` are\n * optional and populated when the provider returns that data.\n */\nexport interface TrackCallOptions {\n userId: string;\n modelName: string;\n provider: string;\n responseContent: string;\n latencyMs: number;\n sessionId?: string | null;\n traceId?: string | null;\n turnId?: number;\n agentId?: string | null;\n parentAgentId?: string | null;\n customerOrgId?: string | null;\n agentVersion?: string | null;\n context?: Record<string, unknown> | null;\n env?: string | null;\n groups?: Record<string, unknown> | null;\n eventProperties?: Record<string, unknown> | null;\n inputTokens?: number | null;\n outputTokens?: number | null;\n totalTokens?: number | null;\n reasoningTokens?: number | null;\n cacheReadInputTokens?: number | null;\n cacheCreationInputTokens?: number | null;\n totalCostUsd?: number | null;\n providerTtfbMs?: number | null;\n isError?: boolean;\n errorMessage?: string | null;\n finishReason?: string | null;\n toolCalls?: Array<ToolCallShape | Record<string, unknown>> | null;\n reasoningContent?: string | null;\n systemPrompt?: string | null;\n temperature?: number | null;\n maxOutputTokens?: number | null;\n topP?: number | null;\n isStreaming?: boolean;\n}\n"],"mappings":";;;;AAqEA,SAAgB,iBAAiB,OAAqC;AACpE,KACE,eAAe,SACf,OAAO,MAAM,cAAc,YAC3B,MAAM,cAAc,QACpB,WAAW,MAAM,UAEjB,QAAO,MAAM;AAEf,KAAI,WAAW,SAAS,OAAO,MAAM,UAAU,WAC7C,QAAO;AAET,OAAM,IAAI,MACR,8IAED"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["/**\n * Shared type definitions for the Amplitude AI SDK.\n *\n * Structural interfaces for provider request/response shapes,\n * events, and the core AmplitudeLike contract. These are\n * \"duck-typed\" interfaces — they describe the subset of each\n * provider SDK's shape that we actually use, without importing\n * the real SDK types.\n */\n\n// ---------------------------------------------------------------------------\n// Amplitude client contract\n// ---------------------------------------------------------------------------\n\n/**\n * Event payload shape for Amplitude tracking.\n * Used when passing events to `AmplitudeLike.track()`.\n */\nexport interface AmplitudeEvent {\n event_type: string;\n user_id?: string;\n device_id?: string;\n session_id?: number;\n event_properties?: Record<string, unknown>;\n user_properties?: Record<string, unknown>;\n groups?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Contract for Amplitude analytics clients.\n * Any object with a `track(event)` method satisfies this interface.\n */\nexport interface AmplitudeLike {\n track: (event: AmplitudeEvent) => void;\n}\n\n/**\n * Extended Amplitude client with flush, shutdown, and optional init.\n * Used by the SDK when it owns or receives an Amplitude instance.\n */\nexport interface AmplitudeClientLike extends AmplitudeLike {\n flush: () => unknown;\n shutdown?: () => void;\n init?: (apiKey: string) => unknown;\n configuration?: Record<string, unknown>;\n}\n\n/**\n * Structural type matching AmplitudeAI instances.\n * Allows providers to accept either an AmplitudeLike (raw analytics client)\n * or an AmplitudeAI instance (which exposes `.amplitude` getter).\n * This avoids circular imports while enabling the convenience pattern:\n * new OpenAI({ amplitude: ai }) // AmplitudeAI\n * new OpenAI({ amplitude: amp }) // raw Amplitude client\n */\nexport interface AmplitudeAILike {\n readonly amplitude: AmplitudeClientLike;\n}\n\n/**\n * Union type accepted by provider constructors.\n * Providers call `resolveAmplitude()` to normalize to `AmplitudeLike`.\n */\nexport type AmplitudeOrAI = AmplitudeLike | AmplitudeAILike;\n\n/**\n * Resolve an `AmplitudeOrAI` value to a plain `AmplitudeLike`.\n */\nexport function resolveAmplitude(input: AmplitudeOrAI): AmplitudeLike {\n if (\n 'amplitude' in input &&\n typeof input.amplitude === 'object' &&\n input.amplitude !== null &&\n 'track' in input.amplitude\n ) {\n return input.amplitude;\n }\n if ('track' in input && typeof input.track === 'function') {\n return input as AmplitudeLike;\n }\n throw new Error(\n 'Expected an AmplitudeLike (with .track()) or AmplitudeAI (with .amplitude) instance. ' +\n 'Pass either your AmplitudeAI instance or ai.amplitude.',\n );\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI-compatible shapes (also used by Azure OpenAI)\n// ---------------------------------------------------------------------------\n\n/**\n * Single message in a chat completion request.\n * Supports role, content, optional name, and tool calls.\n */\nexport interface ChatMessage {\n role: string;\n content?: string | null;\n name?: string;\n tool_calls?: ToolCallShape[];\n}\n\n/**\n * Structural interface for OpenAI-compatible chat completion parameters.\n * Used by the OpenAI and Azure OpenAI provider wrappers.\n */\nexport interface ChatCompletionParams {\n model: string;\n messages: ChatMessage[];\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n stream?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI-compatible chat completion responses.\n * Describes the subset of the OpenAI SDK's response shape that the SDK tracks.\n */\nexport interface ChatCompletionResponse {\n model: string;\n choices: ChatChoice[];\n usage?: OpenAITokenUsage;\n}\n\n/**\n * Single choice in a chat completion response.\n */\nexport interface ChatChoice {\n message: { content?: string | null; tool_calls?: ToolCallShape[] };\n finish_reason?: string;\n}\n\n/**\n * Token usage metadata for OpenAI/Azure OpenAI responses.\n */\nexport interface OpenAITokenUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\n/**\n * Structural interface for OpenAI Responses API request input items.\n */\nexport interface OpenAIResponseInput {\n role?: string;\n content?: string | Array<{ text?: string; [key: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API output content blocks.\n */\nexport interface OpenAIResponseOutputContentItem {\n type?: string;\n text?: string;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API output items.\n */\nexport interface OpenAIResponseOutputItem {\n type?: string;\n status?: string;\n content?: OpenAIResponseOutputContentItem[];\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API usage metadata.\n */\nexport interface OpenAIResponseUsage {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n output_tokens_details?: {\n reasoning_tokens?: number;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for OpenAI Responses API responses.\n */\nexport interface OpenAIResponse {\n model?: string;\n status?: string;\n output_text?: string;\n output?: OpenAIResponseOutputItem[];\n usage?: OpenAIResponseUsage;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Anthropic chat completion request parameters.\n */\nexport interface AnthropicParams {\n model: string;\n system?: string;\n messages: unknown[];\n max_tokens?: number;\n temperature?: number;\n top_p?: number;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for Anthropic chat completion responses.\n */\nexport interface AnthropicResponse {\n model: string;\n content: ContentBlock[];\n usage: AnthropicTokenUsage;\n stop_reason?: string;\n}\n\n/**\n * Content block in an Anthropic response (text, thinking, or tool_use).\n */\nexport interface ContentBlock {\n type: 'text' | 'thinking' | 'tool_use';\n text?: string;\n thinking?: string;\n name?: string;\n input?: unknown;\n id?: string;\n}\n\n/**\n * Token usage metadata for Anthropic responses.\n */\nexport interface AnthropicTokenUsage {\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Gemini shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Google Gemini API responses.\n * Supports both response object and legacy text/usageMetadata shape.\n */\nexport interface GeminiResponse {\n response?: GeminiResponseObject;\n text?: (() => string) | string;\n usageMetadata?: GeminiUsageMetadata;\n candidates?: GeminiCandidate[];\n}\n\n/**\n * Wrapper object for Gemini response (response.text, usageMetadata, candidates).\n */\nexport interface GeminiResponseObject {\n text?: () => string;\n usageMetadata?: GeminiUsageMetadata;\n candidates?: GeminiCandidate[];\n}\n\n/**\n * Token usage metadata for Gemini responses.\n */\nexport interface GeminiUsageMetadata {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n}\n\n/**\n * Single candidate in a Gemini response.\n */\nexport interface GeminiCandidate {\n finishReason?: string;\n content?: { parts?: GeminiPart[] };\n}\n\n/**\n * Part of a Gemini candidate (text or functionCall).\n */\nexport interface GeminiPart {\n text?: string;\n functionCall?: { name: string; args: Record<string, unknown> };\n}\n\n// ---------------------------------------------------------------------------\n// Bedrock shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for AWS Bedrock Converse API request parameters.\n */\nexport interface BedrockConverseParams {\n modelId: string;\n messages?: unknown[];\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for AWS Bedrock Converse API responses.\n */\nexport interface BedrockConverseResponse {\n output?: {\n message?: {\n content?: Array<{ text?: string }>;\n };\n };\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n stopReason?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Mistral shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Structural interface for Mistral chat completion request parameters.\n */\nexport interface MistralChatParams {\n model: string;\n messages: unknown[];\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n [key: string]: unknown;\n}\n\n/**\n * Structural interface for Mistral chat completion responses.\n */\nexport interface MistralChatResponse {\n model?: string;\n choices?: MistralChoice[];\n usage?: MistralTokenUsage;\n}\n\n/**\n * Single choice in a Mistral chat response.\n */\nexport interface MistralChoice {\n message?: { content?: string | unknown[] | null };\n finish_reason?: string;\n}\n\n/**\n * Token usage metadata for Mistral responses.\n */\nexport interface MistralTokenUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common shapes\n// ---------------------------------------------------------------------------\n\n/**\n * Shape of a tool/function call across provider SDKs.\n */\nexport interface ToolCallShape {\n name: string;\n arguments?: unknown;\n id?: string;\n}\n\n/**\n * File or URL attachment for messages (e.g., image, document).\n */\nexport interface Attachment {\n type: string;\n name?: string;\n content?: string;\n url?: string;\n size_bytes?: number;\n}\n\n/**\n * Callback used by provider wrappers to emit an AI response tracking event.\n *\n * Provider wrappers (OpenAI, Anthropic, etc.) receive a `TrackFn` via\n * `BaseAIProvider.trackFn()` and call it after each completion or stream\n * finishes. The function serializes the options into an Amplitude event\n * and sends it via the underlying Amplitude client.\n *\n * @returns The generated message ID for the tracked event.\n */\nexport type TrackFn = (opts: TrackCallOptions) => string;\n\n/**\n * Options passed to the internal track function for LLM completion events.\n *\n * This is the unified shape used by all provider wrappers to report a\n * single AI completion (streaming or non-streaming). Fields like\n * `reasoningTokens`, `cacheReadInputTokens`, and `totalCostUsd` are\n * optional and populated when the provider returns that data.\n */\nexport interface TrackCallOptions {\n userId: string;\n modelName: string;\n provider: string;\n responseContent: string;\n latencyMs: number;\n sessionId?: string | null;\n traceId?: string | null;\n turnId?: number;\n agentId?: string | null;\n parentAgentId?: string | null;\n customerOrgId?: string | null;\n agentVersion?: string | null;\n description?: string | null;\n context?: Record<string, unknown> | null;\n env?: string | null;\n groups?: Record<string, unknown> | null;\n eventProperties?: Record<string, unknown> | null;\n inputTokens?: number | null;\n outputTokens?: number | null;\n totalTokens?: number | null;\n reasoningTokens?: number | null;\n cacheReadInputTokens?: number | null;\n cacheCreationInputTokens?: number | null;\n totalCostUsd?: number | null;\n providerTtfbMs?: number | null;\n isError?: boolean;\n errorMessage?: string | null;\n finishReason?: string | null;\n toolCalls?: Array<ToolCallShape | Record<string, unknown>> | null;\n reasoningContent?: string | null;\n systemPrompt?: string | null;\n temperature?: number | null;\n maxOutputTokens?: number | null;\n topP?: number | null;\n isStreaming?: boolean;\n}\n"],"mappings":";;;;AAqEA,SAAgB,iBAAiB,OAAqC;AACpE,KACE,eAAe,SACf,OAAO,MAAM,cAAc,YAC3B,MAAM,cAAc,QACpB,WAAW,MAAM,UAEjB,QAAO,MAAM;AAEf,KAAI,WAAW,SAAS,OAAO,MAAM,UAAU,WAC7C,QAAO;AAET,OAAM,IAAI,MACR,8IAED"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"costs.d.ts","names":[],"sources":["../../src/utils/costs.ts"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"costs.d.ts","names":[],"sources":["../../src/utils/costs.ts"],"sourcesContent":[],"mappings":";;;;AAmLA;;;;;;;;;;;;;iBArJgB,sBAAA;iBAiCA,mBAAA;;;;;cASH,sBAAa;;;;;;;;;;;;;iBAqBV,6BAAA,+CAGb;;;;;;;;;;;;;;;;;;;iBAmFa,aAAA"}
|
package/dist/utils/costs.js
CHANGED
|
@@ -50,6 +50,10 @@ function stripProviderPrefix(modelName) {
|
|
|
50
50
|
* Delegates to the canonical implementation in utils/providers.ts.
|
|
51
51
|
*/
|
|
52
52
|
const inferProvider = inferProviderFromModel;
|
|
53
|
+
function normalizeProviderForGenaiPrices(provider) {
|
|
54
|
+
if (provider === "gemini") return "google";
|
|
55
|
+
return provider;
|
|
56
|
+
}
|
|
53
57
|
/**
|
|
54
58
|
* Generate candidate (modelRef, providerId) pairs for price lookup.
|
|
55
59
|
*
|
|
@@ -66,7 +70,7 @@ function getGenaiPriceLookupCandidates(modelName, defaultProvider) {
|
|
|
66
70
|
const stripped = stripProviderPrefix(modelName);
|
|
67
71
|
const inferred = defaultProvider ?? tryInferProviderFromModel(stripped);
|
|
68
72
|
const isBedrock = inferred === "bedrock" || defaultProvider === "bedrock" || modelName.startsWith("bedrock:");
|
|
69
|
-
const providerId = isBedrock ? "aws" : inferred;
|
|
73
|
+
const providerId = isBedrock ? "aws" : normalizeProviderForGenaiPrices(inferred);
|
|
70
74
|
const candidates = [{
|
|
71
75
|
model: stripped,
|
|
72
76
|
providerId
|
package/dist/utils/costs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"costs.js","names":["candidates: Array<{ model: string; providerId?: string }>","opts: Record<string, unknown>"],"sources":["../../src/utils/costs.ts"],"sourcesContent":["/**\n * Cost calculation utilities.\n *\n * Uses the genai-prices package when available (npm: @pydantic/genai-prices).\n * Falls back to returning 0 when not installed.\n */\n\nimport {\n inferProviderFromModel,\n tryInferProviderFromModel,\n} from './providers.js';\nimport { tryRequire } from './resolve-module.js';\n\nconst genaiPrices = tryRequire('@pydantic/genai-prices');\n\nlet _livePricesEnabled = false;\n\n/**\n * Opt in to background price updates from the genai-prices GitHub repo.\n *\n * Call once at application startup (e.g. after `AmplitudeAI` init) to fetch\n * the latest pricing data periodically. This ensures new model pricing is\n * available within days of being added to the genai-prices repository,\n * instead of waiting for an npm package release.\n *\n * This makes outbound HTTPS requests to raw.githubusercontent.com.\n * Only enable in environments where outbound network access is permitted.\n *\n * @param intervalMs - refresh interval in milliseconds (default: 1 hour)\n */\nexport function enableLivePriceUpdates(intervalMs = 3_600_000): void {\n if (_livePricesEnabled || genaiPrices == null) return;\n _livePricesEnabled = true;\n\n const prices = genaiPrices as Record<string, unknown>;\n if (typeof prices.updatePrices !== 'function') return;\n\n const doUpdate = () => {\n try {\n (prices.updatePrices as (cb: (ctx: {\n remoteDataUrl: string;\n setProviderData: (data: unknown) => void;\n }) => void) => void)(\n async ({ remoteDataUrl, setProviderData }) => {\n try {\n const resp = await fetch(remoteDataUrl);\n if (resp.ok) {\n setProviderData(await resp.json());\n }\n } catch {\n // Network errors are non-fatal — bundled data still works\n }\n },\n );\n } catch {\n // Best-effort\n }\n };\n\n doUpdate();\n setInterval(doUpdate, intervalMs).unref?.();\n}\n\nexport function stripProviderPrefix(modelName: string): string {\n const colonIdx = modelName.indexOf(':');\n return colonIdx >= 0 ? modelName.slice(colonIdx + 1) : modelName;\n}\n\n/**\n * Infer the provider name from a model name.\n * Delegates to the canonical implementation in utils/providers.ts.\n */\nexport const inferProvider = inferProviderFromModel;\n\n/**\n * Generate candidate (modelRef, providerId) pairs for price lookup.\n *\n * For Bedrock/AWS models, uses a **generalized** dot-prefix stripping strategy\n * instead of enumerating known regions or vendors. Bedrock model IDs follow\n * `[region.][vendor.]model-name[-version]` — we progressively strip\n * dot-separated prefixes and try each variant with and without provider,\n * plus `regional.` / `global.` prefixes that genai-prices uses.\n *\n * This approach is forward-compatible: new AWS regions and Bedrock vendors\n * work automatically without code changes.\n */\nexport function getGenaiPriceLookupCandidates(\n modelName: string,\n defaultProvider?: string,\n): Array<{ model: string; providerId?: string }> {\n const stripped = stripProviderPrefix(modelName);\n const inferred = defaultProvider ?? tryInferProviderFromModel(stripped);\n\n const isBedrock =\n inferred === 'bedrock' ||\n defaultProvider === 'bedrock' ||\n modelName.startsWith('bedrock:');\n const providerId = isBedrock ? 'aws' : inferred;\n\n const candidates: Array<{ model: string; providerId?: string }> = [\n { model: stripped, providerId },\n ];\n // For Bedrock, also try without provider for globally-matched models (e.g. Claude)\n if (isBedrock) {\n candidates.push({ model: stripped, providerId: undefined });\n }\n\n // For any model with dot-separated segments (e.g. vendor.model, region.vendor.model),\n // progressively strip prefixes. This is safe: iteration stops at the first price hit.\n // For Bedrock models specifically, also try regional./global. prefixes.\n if (stripped.includes('.')) {\n const parts = stripped.split('.');\n for (let i = 1; i < parts.length; i++) {\n const sub = parts.slice(i).join('.');\n candidates.push({ model: sub, providerId });\n candidates.push({ model: sub });\n }\n\n if (isBedrock) {\n // genai-prices often indexes Bedrock models under regional.X / global.X\n let vendorModel = stripped;\n const firstSeg = parts[0];\n if (\n firstSeg !== 'regional' &&\n firstSeg !== 'global' &&\n parts.length > 2\n ) {\n vendorModel = parts.slice(1).join('.');\n }\n if (\n !vendorModel.startsWith('regional.') &&\n !vendorModel.startsWith('global.')\n ) {\n candidates.push({ model: `regional.${vendorModel}` });\n candidates.push({ model: `global.${vendorModel}` });\n }\n }\n }\n\n // Deduplicate\n const seen = new Set<string>();\n return candidates.filter((c) => {\n const key = `${c.model}::${c.providerId ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nfunction safeInt(value: unknown): number {\n if (typeof value === 'number' && !Number.isNaN(value))\n return Math.round(value);\n return 0;\n}\n\n/**\n * Calculate cost for an LLM call using genai-prices.\n *\n * IMPORTANT CONTRACT:\n * - `inputTokens` MUST be the TOTAL input token count (including cached tokens).\n * For Anthropic: raw input_tokens + cache_read + cache_creation.\n * For OpenAI: prompt_tokens already includes cached_tokens.\n * - `outputTokens` MUST be the TOTAL output token count (including reasoning tokens).\n * For OpenAI: completion_tokens already includes reasoning_tokens.\n * Do NOT pass reasoning tokens separately and then add them here.\n * - `cacheReadInputTokens` and `cacheCreationInputTokens` are SUBSETS of inputTokens,\n * used only for differential pricing (cached tokens are cheaper).\n * - `reasoningTokens` is IGNORED for cost calculation — it exists only for backward\n * compatibility. Reasoning tokens are already included in outputTokens.\n */\nexport function calculateCost(options: {\n modelName: string;\n inputTokens: number;\n outputTokens: number;\n /** @deprecated Ignored — reasoning tokens are already included in outputTokens. */\n reasoningTokens?: number;\n cacheReadInputTokens?: number;\n cacheCreationInputTokens?: number;\n defaultProvider?: string;\n}): number {\n const {\n modelName,\n inputTokens,\n outputTokens,\n cacheReadInputTokens = 0,\n cacheCreationInputTokens = 0,\n defaultProvider,\n } = options;\n\n if (genaiPrices != null) {\n try {\n const prices = genaiPrices as Record<string, unknown>;\n if (typeof prices.calcPrice === 'function') {\n const calcPriceFn = prices.calcPrice as (\n usage: Record<string, number>,\n modelId: string,\n options?: Record<string, unknown>,\n ) => { total_price?: number } | null;\n\n const usage = {\n input_tokens: safeInt(inputTokens),\n output_tokens: safeInt(outputTokens),\n cache_read_tokens: safeInt(cacheReadInputTokens),\n cache_write_tokens: safeInt(cacheCreationInputTokens),\n };\n\n const candidates = getGenaiPriceLookupCandidates(\n modelName,\n defaultProvider,\n );\n for (const { model, providerId } of candidates) {\n const opts: Record<string, unknown> = {};\n if (providerId) opts.providerId = providerId;\n const result = calcPriceFn(\n usage,\n model,\n Object.keys(opts).length > 0 ? opts : undefined,\n );\n if (result?.total_price != null && result.total_price > 0) {\n return result.total_price;\n }\n }\n return 0;\n }\n } catch {\n // Fall through to 0\n }\n }\n\n return 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"costs.js","names":["candidates: Array<{ model: string; providerId?: string }>","opts: Record<string, unknown>"],"sources":["../../src/utils/costs.ts"],"sourcesContent":["/**\n * Cost calculation utilities.\n *\n * Uses the genai-prices package when available (npm: @pydantic/genai-prices).\n * Falls back to returning 0 when not installed.\n */\n\nimport {\n inferProviderFromModel,\n tryInferProviderFromModel,\n} from './providers.js';\nimport { tryRequire } from './resolve-module.js';\n\nconst genaiPrices = tryRequire('@pydantic/genai-prices');\n\nlet _livePricesEnabled = false;\n\n/**\n * Opt in to background price updates from the genai-prices GitHub repo.\n *\n * Call once at application startup (e.g. after `AmplitudeAI` init) to fetch\n * the latest pricing data periodically. This ensures new model pricing is\n * available within days of being added to the genai-prices repository,\n * instead of waiting for an npm package release.\n *\n * This makes outbound HTTPS requests to raw.githubusercontent.com.\n * Only enable in environments where outbound network access is permitted.\n *\n * @param intervalMs - refresh interval in milliseconds (default: 1 hour)\n */\nexport function enableLivePriceUpdates(intervalMs = 3_600_000): void {\n if (_livePricesEnabled || genaiPrices == null) return;\n _livePricesEnabled = true;\n\n const prices = genaiPrices as Record<string, unknown>;\n if (typeof prices.updatePrices !== 'function') return;\n\n const doUpdate = () => {\n try {\n (prices.updatePrices as (cb: (ctx: {\n remoteDataUrl: string;\n setProviderData: (data: unknown) => void;\n }) => void) => void)(\n async ({ remoteDataUrl, setProviderData }) => {\n try {\n const resp = await fetch(remoteDataUrl);\n if (resp.ok) {\n setProviderData(await resp.json());\n }\n } catch {\n // Network errors are non-fatal — bundled data still works\n }\n },\n );\n } catch {\n // Best-effort\n }\n };\n\n doUpdate();\n setInterval(doUpdate, intervalMs).unref?.();\n}\n\nexport function stripProviderPrefix(modelName: string): string {\n const colonIdx = modelName.indexOf(':');\n return colonIdx >= 0 ? modelName.slice(colonIdx + 1) : modelName;\n}\n\n/**\n * Infer the provider name from a model name.\n * Delegates to the canonical implementation in utils/providers.ts.\n */\nexport const inferProvider = inferProviderFromModel;\n\nfunction normalizeProviderForGenaiPrices(\n provider: string | undefined,\n): string | undefined {\n if (provider === 'gemini') return 'google';\n return provider;\n}\n\n/**\n * Generate candidate (modelRef, providerId) pairs for price lookup.\n *\n * For Bedrock/AWS models, uses a **generalized** dot-prefix stripping strategy\n * instead of enumerating known regions or vendors. Bedrock model IDs follow\n * `[region.][vendor.]model-name[-version]` — we progressively strip\n * dot-separated prefixes and try each variant with and without provider,\n * plus `regional.` / `global.` prefixes that genai-prices uses.\n *\n * This approach is forward-compatible: new AWS regions and Bedrock vendors\n * work automatically without code changes.\n */\nexport function getGenaiPriceLookupCandidates(\n modelName: string,\n defaultProvider?: string,\n): Array<{ model: string; providerId?: string }> {\n const stripped = stripProviderPrefix(modelName);\n const inferred = defaultProvider ?? tryInferProviderFromModel(stripped);\n\n const isBedrock =\n inferred === 'bedrock' ||\n defaultProvider === 'bedrock' ||\n modelName.startsWith('bedrock:');\n const providerId = isBedrock\n ? 'aws'\n : normalizeProviderForGenaiPrices(inferred);\n\n const candidates: Array<{ model: string; providerId?: string }> = [\n { model: stripped, providerId },\n ];\n // For Bedrock, also try without provider for globally-matched models (e.g. Claude)\n if (isBedrock) {\n candidates.push({ model: stripped, providerId: undefined });\n }\n\n // For any model with dot-separated segments (e.g. vendor.model, region.vendor.model),\n // progressively strip prefixes. This is safe: iteration stops at the first price hit.\n // For Bedrock models specifically, also try regional./global. prefixes.\n if (stripped.includes('.')) {\n const parts = stripped.split('.');\n for (let i = 1; i < parts.length; i++) {\n const sub = parts.slice(i).join('.');\n candidates.push({ model: sub, providerId });\n candidates.push({ model: sub });\n }\n\n if (isBedrock) {\n // genai-prices often indexes Bedrock models under regional.X / global.X\n let vendorModel = stripped;\n const firstSeg = parts[0];\n if (\n firstSeg !== 'regional' &&\n firstSeg !== 'global' &&\n parts.length > 2\n ) {\n vendorModel = parts.slice(1).join('.');\n }\n if (\n !vendorModel.startsWith('regional.') &&\n !vendorModel.startsWith('global.')\n ) {\n candidates.push({ model: `regional.${vendorModel}` });\n candidates.push({ model: `global.${vendorModel}` });\n }\n }\n }\n\n // Deduplicate\n const seen = new Set<string>();\n return candidates.filter((c) => {\n const key = `${c.model}::${c.providerId ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nfunction safeInt(value: unknown): number {\n if (typeof value === 'number' && !Number.isNaN(value))\n return Math.round(value);\n return 0;\n}\n\n/**\n * Calculate cost for an LLM call using genai-prices.\n *\n * IMPORTANT CONTRACT:\n * - `inputTokens` MUST be the TOTAL input token count (including cached tokens).\n * For Anthropic: raw input_tokens + cache_read + cache_creation.\n * For OpenAI: prompt_tokens already includes cached_tokens.\n * - `outputTokens` MUST be the TOTAL output token count (including reasoning tokens).\n * For OpenAI: completion_tokens already includes reasoning_tokens.\n * Do NOT pass reasoning tokens separately and then add them here.\n * - `cacheReadInputTokens` and `cacheCreationInputTokens` are SUBSETS of inputTokens,\n * used only for differential pricing (cached tokens are cheaper).\n * - `reasoningTokens` is IGNORED for cost calculation — it exists only for backward\n * compatibility. Reasoning tokens are already included in outputTokens.\n */\nexport function calculateCost(options: {\n modelName: string;\n inputTokens: number;\n outputTokens: number;\n /** @deprecated Ignored — reasoning tokens are already included in outputTokens. */\n reasoningTokens?: number;\n cacheReadInputTokens?: number;\n cacheCreationInputTokens?: number;\n defaultProvider?: string;\n}): number {\n const {\n modelName,\n inputTokens,\n outputTokens,\n cacheReadInputTokens = 0,\n cacheCreationInputTokens = 0,\n defaultProvider,\n } = options;\n\n if (genaiPrices != null) {\n try {\n const prices = genaiPrices as Record<string, unknown>;\n if (typeof prices.calcPrice === 'function') {\n const calcPriceFn = prices.calcPrice as (\n usage: Record<string, number>,\n modelId: string,\n options?: Record<string, unknown>,\n ) => { total_price?: number } | null;\n\n const usage = {\n input_tokens: safeInt(inputTokens),\n output_tokens: safeInt(outputTokens),\n cache_read_tokens: safeInt(cacheReadInputTokens),\n cache_write_tokens: safeInt(cacheCreationInputTokens),\n };\n\n const candidates = getGenaiPriceLookupCandidates(\n modelName,\n defaultProvider,\n );\n for (const { model, providerId } of candidates) {\n const opts: Record<string, unknown> = {};\n if (providerId) opts.providerId = providerId;\n const result = calcPriceFn(\n usage,\n model,\n Object.keys(opts).length > 0 ? opts : undefined,\n );\n if (result?.total_price != null && result.total_price > 0) {\n return result.total_price;\n }\n }\n return 0;\n }\n } catch {\n // Fall through to 0\n }\n }\n\n return 0;\n}\n"],"mappings":"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"}
|