@amplitude/ai 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # AGENTS.md
4
4
 
5
- Package: `@amplitude/ai` v0.2.0
5
+ Package: `@amplitude/ai` v0.2.1
6
6
 
7
7
  ## Install
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/server.ts"],"sourcesContent":[],"mappings":";;;KAqCK,WAAA;cAaC,iFAGS;AAlDqD,cA2H9D,YAzFU,EAAA,GAAA,GAyFS,SAzFT;AAAA,cAqaV,YAxZA,EAAA,GAAA,GAwZyB,OAhW9B,CAAA,IAAA,CArDc"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/server.ts"],"sourcesContent":[],"mappings":";;;KAqCK,WAAA;cAaC,iFAGS;AAlDqD,cA2H9D,YAzFU,EAAA,GAAA,GAyFS,SAzFT;AAAA,cAqaV,YAxZA,EAAA,GAAA,GAwZyB,OAhW9B,CAAA,IAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"patching.d.ts","names":[],"sources":["../src/patching.ts"],"sourcesContent":[],"mappings":";;;;AAoLgB,iBAjJA,gBAAA,CAAA,CAkJU,EAAA,MAAA,EAAA;AAuHV,iBApNA,WAAA,CAqND,OAAW,EAAA;EA6CV,WAAA,EAjQD,WAiQa;EAgGZ,gBAAK,CAAA,EAAA,OACN;EAiEC,MAAA,CAAA,EAAA,OAAO;AAUvB,CAAA,CAAA,EAAgB,IAAA;AAIA,iBA7ZA,cAAA,CA6ZgB,OAAA,EAAA;EAIhB,WAAA,EAhaD,WAgac;EAIb,MAAA,CAAA,EAAA,OAAA;AAIhB,CAAA,CAAA,EAAgB,IAAA;AAIA,iBAhYA,gBAAA,CAgYkB,OAAA,EAAA;eA/XnB;;;iBAyBC,WAAA;eACD;;;iBAuHC,YAAA;eACD;;;iBA6CC,YAAA;eACD;;;;;;;;;;;;;;;;;;iBA+FC,KAAA;eACD;YACH;;iBAgEI,OAAA,CAAA;iBAUA,aAAA,CAAA;iBAIA,gBAAA,CAAA;iBAIA,aAAA,CAAA;iBAIA,cAAA,CAAA;iBAIA,cAAA,CAAA;iBAIA,kBAAA,CAAA"}
1
+ {"version":3,"file":"patching.d.ts","names":[],"sources":["../src/patching.ts"],"sourcesContent":[],"mappings":";;;;AAoLgB,iBAjJA,gBAAA,CAAA,CAkJD,EAAW,MAAA,EAAA;AAuHV,iBApNA,WAAA,CAqND,OAAA,EAAW;EA6CV,WAAA,EAjQD,WAiQa;EAgGZ,gBAAK,CAAA,EAAA,OACN;EAiEC,MAAA,CAAA,EAAA,OAAO;AAUvB,CAAA,CAAA,EAAgB,IAAA;AAIA,iBA7ZA,cAAA,CA6ZgB,OAAA,EAAA;EAIhB,WAAA,EAhaD,WAgac;EAIb,MAAA,CAAA,EAAA,OAAA;AAIhB,CAAA,CAAA,EAAgB,IAAA;AAIA,iBAhYA,gBAAA,CAgYkB,OAAA,EAAA;eA/XnB;;;iBAyBC,WAAA;eACD;;;iBAuHC,YAAA;eACD;;;iBA6CC,YAAA;eACD;;;;;;;;;;;;;;;;;;iBA+FC,KAAA;eACD;YACH;;iBAgEI,OAAA,CAAA;iBAUA,aAAA,CAAA;iBAIA,gBAAA,CAAA;iBAIA,aAAA,CAAA;iBAIA,cAAA,CAAA;iBAIA,cAAA,CAAA;iBAIA,kBAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"costs.d.ts","names":[],"sources":["../../src/utils/costs.ts"],"sourcesContent":[],"mappings":";;;;AA0KA;;;;;;;;;;;;;iBA5IgB,sBAAA;iBAiCA,mBAAA;;;;;cASH,sBAAa;;;;;;;;;;;;;iBAcV,6BAAA,+CAGb;;;;;;;;;;;;;;;;;;;iBAiFa,aAAA"}
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"}
@@ -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
@@ -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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"}
package/llms-full.txt CHANGED
@@ -1,5 +1,5 @@
1
1
  # llms-full.txt
2
- # @amplitude/ai 0.2.0 — Detailed API Reference for LLM Agents
2
+ # @amplitude/ai 0.2.1 — Detailed API Reference for LLM Agents
3
3
  # Use this file for instrumentation guidance. See llms.txt for discovery.
4
4
 
5
5
  ## Core API
package/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  <!-- GENERATED FILE: do not edit manually -->
2
2
  # llms.txt
3
3
  package=@amplitude/ai
4
- version=0.2.0
4
+ version=0.2.1
5
5
 
6
6
  [mcp.tools]
7
7
  get_event_schema
package/mcp.schema.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "generated": true,
3
3
  "package": "@amplitude/ai",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "prompt": "instrument_app",
6
6
  "tools": [
7
7
  "get_event_schema",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amplitude/ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "description": "Amplitude AI SDK - LLM usage tracking for Amplitude Analytics",
6
6
  "keywords": [