@amplitude/ai 0.1.0 → 0.1.2
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 +1 -1
- package/README.md +436 -6
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/patching.d.ts.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +4 -18
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/azure-openai.d.ts +3 -3
- package/dist/providers/azure-openai.d.ts.map +1 -1
- package/dist/providers/azure-openai.js +2 -2
- package/dist/providers/azure-openai.js.map +1 -1
- package/dist/providers/base.d.ts +11 -2
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/base.js +32 -14
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +13 -28
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +8 -27
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/mistral.js +20 -24
- package/dist/providers/mistral.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +23 -41
- package/dist/providers/openai.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/streaming.d.ts +2 -0
- package/dist/utils/streaming.d.ts.map +1 -1
- package/dist/utils/streaming.js +10 -0
- package/dist/utils/streaming.js.map +1 -1
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/mcp.schema.json +1 -1
- package/package.json +1 -1
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["_catalogCache: EventCatalog | undefined","z.string","z\n .enum","z\n .number","sources: Array<{ name: string; path: string }>","results: Array<{\n source: string;\n heading: string;\n snippet: string;\n line: number;\n priority: number;\n }>","content: string"],"sources":["../../src/mcp/server.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport {\n MCP_PROMPTS,\n MCP_RESOURCES,\n MCP_SERVER_NAME,\n MCP_TOOLS,\n} from './contract.js';\nimport { getIntegrationPatterns } from './patterns.js';\nimport { analyzeFileInstrumentation } from './validate-file.js';\n\ntype EventSchema = {\n event_type: string;\n description?: string;\n event_properties?: Record<string, unknown>;\n};\n\ntype EventCatalog = {\n events?: EventSchema[];\n};\n\nconst packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');\n\nlet _catalogCache: EventCatalog | undefined;\n\nconst readEventCatalog = (): EventCatalog => {\n if (_catalogCache) return _catalogCache;\n const filePath = join(packageRoot, 'data', 'agent_event_catalog.json');\n const raw = readFileSync(filePath, 'utf8');\n _catalogCache = JSON.parse(raw) as EventCatalog;\n return _catalogCache;\n};\n\ntype ContentTier = 'full' | 'metadata_only' | 'customer_enriched';\n\nconst normalizeContentTier = (value: unknown): ContentTier => {\n if (\n value === 'full' ||\n value === 'metadata_only' ||\n value === 'customer_enriched'\n ) {\n return value;\n }\n return 'full';\n};\n\nconst buildInstrumentationGuidance = (\n framework: string,\n provider: string,\n contentTier: ContentTier,\n): string[] => {\n const providerSetup =\n provider === 'openai' || provider === 'anthropic'\n ? `use ${provider} wrapper/swap integration (for example: \\`new ${provider === 'openai' ? 'OpenAI' : 'Anthropic'}({ amplitude: ai, ... })\\`)`\n : `use the ${provider} provider wrapper class from @amplitude/ai`;\n\n const frameworkStep =\n framework === 'express' || framework === 'koa' || framework === 'fastify'\n ? 'wire `createAmplitudeAIMiddleware()` for per-request identity propagation and run LLM calls inside session context'\n : framework === 'next' || framework === 'nextjs'\n ? 'wrap route handlers in `session.run()` so every LLM call inherits user/session lineage'\n : 'attach `ai.agent(...).session(...)` where request or conversation identity exists';\n\n const tierGuidance =\n contentTier === 'full'\n ? 'Content tier (`full`): maximum insight and automatic server enrichments. Prefer `redactPii: true` (+ optional `customRedactionPatterns`).'\n : contentTier === 'metadata_only'\n ? 'Content tier (`metadata_only`): no content leaves your infrastructure; keep token/cost/latency/session analytics.'\n : 'Content tier (`customer_enriched`): no content leaves infra; send your own labels via `trackSessionEnrichment(...)` for advanced analytics.';\n\n const nextForTier =\n contentTier === 'metadata_only'\n ? 'if you need quality/topic analytics without sending content, move to `customer_enriched` and emit structured enrichments.'\n : contentTier === 'customer_enriched'\n ? 'if policy allows and you want zero eval-code overhead, consider `full` with redaction for automatic server enrichments.'\n : 'if policy prohibits content egress, switch to `metadata_only` or `customer_enriched` without changing session instrumentation.';\n\n return [\n `Framework: ${framework}`,\n `Provider: ${provider}`,\n `Content tier: ${contentTier}`,\n '',\n 'Now:',\n '1) install @amplitude/ai and @amplitude/analytics-node',\n '2) initialize `AmplitudeAI` with API key',\n `3) ${providerSetup}`,\n '4) bind session context with `const session = ai.agent(...).session(...)` and run calls in `session.run(...)`',\n `5) ${frameworkStep}`,\n '',\n 'Next:',\n `- ${nextForTier}`,\n '- treat `patch({ amplitudeAI: ai })` as migration quickstart, not steady-state production.',\n '',\n 'Why:',\n '- session lineage unlocks scoring, enrichments, and reliable product-to-AI funnels.',\n '- wrapper/swap integration preserves fidelity while keeping implementation effort low.',\n `- ${tierGuidance}`,\n '- privacy controls apply before events leave your process.',\n '',\n 'Validate:',\n '- run `amplitude-ai doctor` and verify [Agent] session-scoped events.',\n ];\n};\n\nconst headingPriority = (heading: string): number => {\n const normalized = heading.toLowerCase();\n if (\n normalized.includes('choose your integration tier') ||\n normalized.includes('privacy & content control')\n ) {\n return 3;\n }\n if (\n normalized.includes('boundagent') ||\n normalized.includes('bound agent') ||\n normalized.includes('session')\n ) {\n return 2;\n }\n return 1;\n};\n\nconst createServer = (): McpServer => {\n const server = new McpServer({\n name: MCP_SERVER_NAME,\n version: '0.1.0',\n });\n\n server.registerTool(\n MCP_TOOLS.getEventSchema,\n {\n title: 'Get Event Schema',\n description:\n 'Return Amplitude AI event schema and event-property definitions.',\n inputSchema: {\n event_type: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const eventType =\n typeof args?.event_type === 'string' ? args.event_type : undefined;\n const catalog = readEventCatalog();\n const events = catalog.events ?? [];\n const selected = eventType\n ? events.filter((event) => event.event_type === eventType)\n : events;\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n total: selected.length,\n events: selected,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.getIntegrationPattern,\n {\n title: 'Get Integration Pattern',\n description:\n 'Return canonical instrumentation patterns for @amplitude/ai.',\n inputSchema: {\n id: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const id = typeof args?.id === 'string' ? args.id : undefined;\n const patterns = getIntegrationPatterns();\n const selected = id\n ? patterns.filter((pattern) => pattern.id === id)\n : patterns;\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ patterns: selected }, null, 2),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.validateSetup,\n {\n title: 'Validate Setup',\n description: 'Validate environment variables required for @amplitude/ai.',\n inputSchema: {},\n },\n async () => {\n const required = ['AMPLITUDE_AI_API_KEY'];\n const missing = required.filter((name) => !process.env[name]);\n const status = missing.length === 0 ? 'ok' : 'missing_env';\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n status,\n missing_env: missing,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.suggestInstrumentation,\n {\n title: 'Suggest Instrumentation',\n description:\n 'Suggest practical next instrumentation steps from minimal hints.',\n inputSchema: {\n framework: z.string().optional(),\n provider: z.string().optional(),\n content_tier: z\n .enum(['full', 'metadata_only', 'customer_enriched'])\n .optional()\n .describe('Desired content tier (default: full)'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const framework =\n typeof args?.framework === 'string' ? args.framework : 'node';\n const provider =\n typeof args?.provider === 'string' ? args.provider : 'openai';\n const contentTier = normalizeContentTier(args?.content_tier);\n const guidance = buildInstrumentationGuidance(\n framework,\n provider,\n contentTier,\n );\n\n return {\n content: [\n {\n type: 'text',\n text: guidance.join('\\n'),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.validateFile,\n {\n title: 'Validate File Instrumentation',\n description:\n 'Analyze source code to detect LLM call sites and report which are instrumented vs uninstrumented.',\n inputSchema: {\n source: z.string().describe('Source code content to analyze'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const source = typeof args?.source === 'string' ? args.source : '';\n const result = analyzeFileInstrumentation(source);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.searchDocs,\n {\n title: 'Search Documentation',\n description:\n 'Search the SDK README and API reference for a keyword or phrase. Returns matching sections with surrounding context.',\n inputSchema: {\n query: z.string().describe('Keyword or phrase to search for'),\n max_results: z\n .number()\n .optional()\n .describe('Maximum number of results to return (default: 5)'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const query =\n typeof args?.query === 'string' ? args.query.toLowerCase() : '';\n const maxResults =\n typeof args?.max_results === 'number' ? args.max_results : 5;\n\n if (!query) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ error: 'query is required' }),\n },\n ],\n };\n }\n\n const sources: Array<{ name: string; path: string }> = [\n { name: 'README.md', path: join(packageRoot, 'README.md') },\n { name: 'llms-full.txt', path: join(packageRoot, 'llms-full.txt') },\n ];\n\n const results: Array<{\n source: string;\n heading: string;\n snippet: string;\n line: number;\n priority: number;\n }> = [];\n\n for (const { name, path } of sources) {\n let content: string;\n try {\n content = readFileSync(path, 'utf8');\n } catch {\n continue;\n }\n const lines = content.split('\\n');\n let currentHeading = '(top)';\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n if (line.startsWith('#')) {\n currentHeading = line.replace(/^#+\\s*/, '');\n }\n if (line.toLowerCase().includes(query)) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n results.push({\n source: name,\n heading: currentHeading,\n snippet: lines.slice(start, end).join('\\n'),\n line: i + 1,\n priority: headingPriority(currentHeading),\n });\n }\n }\n }\n\n results.sort((a, b) => b.priority - a.priority || a.line - b.line);\n const selected = results.slice(0, maxResults);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query,\n total: selected.length,\n results: selected.map(({ priority, ...rest }) => rest),\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerResource(\n 'event_schema',\n MCP_RESOURCES.eventSchema,\n {\n title: 'Amplitude AI Event Schema',\n description: 'Current event and property catalog for @amplitude/ai.',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: MCP_RESOURCES.eventSchema,\n mimeType: 'application/json',\n text: JSON.stringify(readEventCatalog(), null, 2),\n },\n ],\n }),\n );\n\n server.registerResource(\n 'integration_patterns',\n MCP_RESOURCES.integrationPatterns,\n {\n title: 'Amplitude AI Integration Patterns',\n description: 'Canonical setup patterns used by docs and agent workflows.',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: MCP_RESOURCES.integrationPatterns,\n mimeType: 'application/json',\n text: JSON.stringify({ patterns: getIntegrationPatterns() }, null, 2),\n },\n ],\n }),\n );\n\n server.registerPrompt(\n MCP_PROMPTS.instrumentApp,\n {\n title: 'Instrument App',\n description:\n 'Guided checklist for instrumenting an app with @amplitude/ai from zero to validated setup.',\n argsSchema: {\n framework: z.string().optional(),\n provider: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const framework =\n typeof args?.framework === 'string' ? args.framework : 'node';\n const provider =\n typeof args?.provider === 'string' ? args.provider : 'openai';\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Instrument this ${framework} app with ${provider} using @amplitude/ai. Start from the production default: wrapper/swap integration plus ai.agent(...).session(...), choose a content tier (full/metadata_only/customer_enriched) with privacy defaults, and treat patch() only as a migration fallback. Then validate setup and annotate any uninstrumented call sites.`,\n },\n },\n ],\n };\n },\n );\n\n return server;\n};\n\nconst runMcpServer = async (): Promise<void> => {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n};\n\nexport { buildInstrumentationGuidance, createServer, runMcpServer };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["_catalogCache: EventCatalog | undefined","z.string","z\n .enum","z\n .number","sources: Array<{ name: string; path: string }>","results: Array<{\n source: string;\n heading: string;\n snippet: string;\n line: number;\n priority: number;\n }>","content: string"],"sources":["../../src/mcp/server.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport {\n MCP_PROMPTS,\n MCP_RESOURCES,\n MCP_SERVER_NAME,\n MCP_TOOLS,\n} from './contract.js';\nimport { getIntegrationPatterns } from './patterns.js';\nimport { analyzeFileInstrumentation } from './validate-file.js';\n\ntype EventSchema = {\n event_type: string;\n description?: string;\n event_properties?: Record<string, unknown>;\n};\n\ntype EventCatalog = {\n events?: EventSchema[];\n};\n\nconst packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');\n\nlet _catalogCache: EventCatalog | undefined;\n\nconst readEventCatalog = (): EventCatalog => {\n if (_catalogCache) return _catalogCache;\n const filePath = join(packageRoot, 'data', 'agent_event_catalog.json');\n const raw = readFileSync(filePath, 'utf8');\n _catalogCache = JSON.parse(raw) as EventCatalog;\n return _catalogCache;\n};\n\ntype ContentTier = 'full' | 'metadata_only' | 'customer_enriched';\n\nconst normalizeContentTier = (value: unknown): ContentTier => {\n if (\n value === 'full' ||\n value === 'metadata_only' ||\n value === 'customer_enriched'\n ) {\n return value;\n }\n return 'full';\n};\n\nconst buildInstrumentationGuidance = (\n framework: string,\n provider: string,\n contentTier: ContentTier,\n): string[] => {\n const providerSetup =\n provider === 'openai' || provider === 'anthropic'\n ? `use ${provider} wrapper/swap integration (for example: \\`new ${provider === 'openai' ? 'OpenAI' : 'Anthropic'}({ amplitude: ai, ... })\\`)`\n : `use the ${provider} provider wrapper class from @amplitude/ai`;\n\n const frameworkStep =\n framework === 'express' || framework === 'koa' || framework === 'fastify'\n ? 'wire `createAmplitudeAIMiddleware()` for per-request identity propagation and run LLM calls inside session context'\n : framework === 'next' || framework === 'nextjs'\n ? 'wrap route handlers in `session.run()` so every LLM call inherits user/session lineage'\n : 'attach `ai.agent(...).session(...)` where request or conversation identity exists';\n\n const tierGuidance =\n contentTier === 'full'\n ? 'Content tier (`full`): maximum insight and automatic server enrichments. Prefer `redactPii: true` (+ optional `customRedactionPatterns`).'\n : contentTier === 'metadata_only'\n ? 'Content tier (`metadata_only`): no content leaves your infrastructure; keep token/cost/latency/session analytics.'\n : 'Content tier (`customer_enriched`): no content leaves infra; send your own labels via `trackSessionEnrichment(...)` for advanced analytics.';\n\n const nextForTier =\n contentTier === 'metadata_only'\n ? 'if you need quality/topic analytics without sending content, move to `customer_enriched` and emit structured enrichments.'\n : contentTier === 'customer_enriched'\n ? 'if policy allows and you want zero eval-code overhead, consider `full` with redaction for automatic server enrichments.'\n : 'if policy prohibits content egress, switch to `metadata_only` or `customer_enriched` without changing session instrumentation.';\n\n return [\n `Framework: ${framework}`,\n `Provider: ${provider}`,\n `Content tier: ${contentTier}`,\n '',\n 'Now:',\n '1) install @amplitude/ai and @amplitude/analytics-node',\n '2) initialize `AmplitudeAI` with API key',\n `3) ${providerSetup}`,\n '4) bind session context with `const session = ai.agent(...).session(...)` and run calls in `session.run(...)`',\n `5) ${frameworkStep}`,\n '',\n 'Next:',\n `- ${nextForTier}`,\n '- treat `patch({ amplitudeAI: ai })` as migration quickstart, not steady-state production.',\n '',\n 'Why:',\n '- session lineage unlocks scoring, enrichments, and reliable product-to-AI funnels.',\n '- wrapper/swap integration preserves fidelity while keeping implementation effort low.',\n `- ${tierGuidance}`,\n '- privacy controls apply before events leave your process.',\n '',\n 'Validate:',\n '- run `amplitude-ai doctor` and verify [Agent] session-scoped events.',\n ];\n};\n\nconst headingPriority = (heading: string): number => {\n const normalized = heading.toLowerCase();\n if (\n normalized.includes('choose your integration tier') ||\n normalized.includes('privacy & content control')\n ) {\n return 3;\n }\n if (\n normalized.includes('boundagent') ||\n normalized.includes('bound agent') ||\n normalized.includes('session')\n ) {\n return 2;\n }\n return 1;\n};\n\nconst createServer = (): McpServer => {\n const server = new McpServer({\n name: MCP_SERVER_NAME,\n version: '0.1.0',\n });\n\n server.registerTool(\n MCP_TOOLS.getEventSchema,\n {\n title: 'Get Event Schema',\n description:\n 'Return Amplitude AI event schema and event-property definitions.',\n inputSchema: {\n event_type: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const eventType =\n typeof args?.event_type === 'string' ? args.event_type : undefined;\n const catalog = readEventCatalog();\n const events = catalog.events ?? [];\n const selected = eventType\n ? events.filter((event) => event.event_type === eventType)\n : events;\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n total: selected.length,\n events: selected,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.getIntegrationPattern,\n {\n title: 'Get Integration Pattern',\n description:\n 'Return canonical instrumentation patterns for @amplitude/ai.',\n inputSchema: {\n id: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const id = typeof args?.id === 'string' ? args.id : undefined;\n const patterns = getIntegrationPatterns();\n const selected = id\n ? patterns.filter((pattern) => pattern.id === id)\n : patterns;\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ patterns: selected }, null, 2),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.validateSetup,\n {\n title: 'Validate Setup',\n description: 'Validate environment variables required for @amplitude/ai.',\n inputSchema: {},\n },\n async () => {\n const required = ['AMPLITUDE_AI_API_KEY'];\n const missing = required.filter((name) => !process.env[name]);\n const status = missing.length === 0 ? 'ok' : 'missing_env';\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n status,\n missing_env: missing,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.suggestInstrumentation,\n {\n title: 'Suggest Instrumentation',\n description:\n 'Suggest practical next instrumentation steps from minimal hints.',\n inputSchema: {\n framework: z.string().optional(),\n provider: z.string().optional(),\n content_tier: z\n .enum(['full', 'metadata_only', 'customer_enriched'])\n .optional()\n .describe('Desired content tier (default: full)'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const framework =\n typeof args?.framework === 'string' ? args.framework : 'node';\n const provider =\n typeof args?.provider === 'string' ? args.provider : 'openai';\n const contentTier = normalizeContentTier(args?.content_tier);\n const guidance = buildInstrumentationGuidance(\n framework,\n provider,\n contentTier,\n );\n\n return {\n content: [\n {\n type: 'text',\n text: guidance.join('\\n'),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.validateFile,\n {\n title: 'Validate File Instrumentation',\n description:\n 'Analyze source code to detect LLM call sites and report which are instrumented vs uninstrumented.',\n inputSchema: {\n source: z.string().describe('Source code content to analyze'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const source = typeof args?.source === 'string' ? args.source : '';\n const result = analyzeFileInstrumentation(source);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n },\n );\n\n server.registerTool(\n MCP_TOOLS.searchDocs,\n {\n title: 'Search Documentation',\n description:\n 'Search the SDK README and API reference for a keyword or phrase. Returns matching sections with surrounding context.',\n inputSchema: {\n query: z.string().describe('Keyword or phrase to search for'),\n max_results: z\n .number()\n .optional()\n .describe('Maximum number of results to return (default: 5)'),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const query =\n typeof args?.query === 'string' ? args.query.toLowerCase() : '';\n const maxResults =\n typeof args?.max_results === 'number' ? args.max_results : 5;\n\n if (!query) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ error: 'query is required' }),\n },\n ],\n };\n }\n\n const sources: Array<{ name: string; path: string }> = [\n { name: 'README.md', path: join(packageRoot, 'README.md') },\n { name: 'llms-full.txt', path: join(packageRoot, 'llms-full.txt') },\n ];\n\n const results: Array<{\n source: string;\n heading: string;\n snippet: string;\n line: number;\n priority: number;\n }> = [];\n\n for (const { name, path } of sources) {\n let content: string;\n try {\n content = readFileSync(path, 'utf8');\n } catch {\n continue;\n }\n const lines = content.split('\\n');\n let currentHeading = '(top)';\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n if (line.startsWith('#')) {\n currentHeading = line.replace(/^#+\\s*/, '');\n }\n if (line.toLowerCase().includes(query)) {\n const start = Math.max(0, i - 2);\n const end = Math.min(lines.length, i + 3);\n results.push({\n source: name,\n heading: currentHeading,\n snippet: lines.slice(start, end).join('\\n'),\n line: i + 1,\n priority: headingPriority(currentHeading),\n });\n }\n }\n }\n\n results.sort((a, b) => b.priority - a.priority || a.line - b.line);\n const selected = results.slice(0, maxResults);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query,\n total: selected.length,\n results: selected.map(({ priority: _priority, ...rest }) => rest),\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n );\n\n server.registerResource(\n 'event_schema',\n MCP_RESOURCES.eventSchema,\n {\n title: 'Amplitude AI Event Schema',\n description: 'Current event and property catalog for @amplitude/ai.',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: MCP_RESOURCES.eventSchema,\n mimeType: 'application/json',\n text: JSON.stringify(readEventCatalog(), null, 2),\n },\n ],\n }),\n );\n\n server.registerResource(\n 'integration_patterns',\n MCP_RESOURCES.integrationPatterns,\n {\n title: 'Amplitude AI Integration Patterns',\n description: 'Canonical setup patterns used by docs and agent workflows.',\n mimeType: 'application/json',\n },\n async () => ({\n contents: [\n {\n uri: MCP_RESOURCES.integrationPatterns,\n mimeType: 'application/json',\n text: JSON.stringify({ patterns: getIntegrationPatterns() }, null, 2),\n },\n ],\n }),\n );\n\n server.registerPrompt(\n MCP_PROMPTS.instrumentApp,\n {\n title: 'Instrument App',\n description:\n 'Guided checklist for instrumenting an app with @amplitude/ai from zero to validated setup.',\n argsSchema: {\n framework: z.string().optional(),\n provider: z.string().optional(),\n },\n },\n // biome-ignore lint/suspicious/noExplicitAny: SDK callback type is intentionally broad.\n async (args: any) => {\n const framework =\n typeof args?.framework === 'string' ? args.framework : 'node';\n const provider =\n typeof args?.provider === 'string' ? args.provider : 'openai';\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Instrument this ${framework} app with ${provider} using @amplitude/ai. Start from the production default: wrapper/swap integration plus ai.agent(...).session(...), choose a content tier (full/metadata_only/customer_enriched) with privacy defaults, and treat patch() only as a migration fallback. Then validate setup and annotate any uninstrumented call sites.`,\n },\n },\n ],\n };\n },\n );\n\n return server;\n};\n\nconst runMcpServer = async (): Promise<void> => {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n};\n\nexport { buildInstrumentationGuidance, createServer, runMcpServer };\n"],"mappings":";;;;;;;;;;;AAyBA,MAAM,cAAc,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EAAE,MAAM,KAAK;AAE7E,IAAIA;AAEJ,MAAM,yBAAuC;AAC3C,KAAI,cAAe,QAAO;CAE1B,MAAM,MAAM,aADK,KAAK,aAAa,QAAQ,2BAA2B,EACnC,OAAO;AAC1C,iBAAgB,KAAK,MAAM,IAAI;AAC/B,QAAO;;AAKT,MAAM,wBAAwB,UAAgC;AAC5D,KACE,UAAU,UACV,UAAU,mBACV,UAAU,oBAEV,QAAO;AAET,QAAO;;AAGT,MAAM,gCACJ,WACA,UACA,gBACa;CACb,MAAM,gBACJ,aAAa,YAAY,aAAa,cAClC,OAAO,SAAS,gDAAgD,aAAa,WAAW,WAAW,YAAY,+BAC/G,WAAW,SAAS;CAE1B,MAAM,gBACJ,cAAc,aAAa,cAAc,SAAS,cAAc,YAC5D,uHACA,cAAc,UAAU,cAAc,WACpC,2FACA;CAER,MAAM,eACJ,gBAAgB,SACZ,8IACA,gBAAgB,kBACd,sHACA;CAER,MAAM,cACJ,gBAAgB,kBACZ,8HACA,gBAAgB,sBACd,4HACA;AAER,QAAO;EACL,cAAc;EACd,aAAa;EACb,iBAAiB;EACjB;EACA;EACA;EACA;EACA,MAAM;EACN;EACA,MAAM;EACN;EACA;EACA,KAAK;EACL;EACA;EACA;EACA;EACA;EACA,KAAK;EACL;EACA;EACA;EACA;EACD;;AAGH,MAAM,mBAAmB,YAA4B;CACnD,MAAM,aAAa,QAAQ,aAAa;AACxC,KACE,WAAW,SAAS,+BAA+B,IACnD,WAAW,SAAS,4BAA4B,CAEhD,QAAO;AAET,KACE,WAAW,SAAS,aAAa,IACjC,WAAW,SAAS,cAAc,IAClC,WAAW,SAAS,UAAU,CAE9B,QAAO;AAET,QAAO;;AAGT,MAAM,qBAAgC;CACpC,MAAM,SAAS,IAAI,UAAU;EAC3B,MAAM;EACN,SAAS;EACV,CAAC;AAEF,QAAO,aACL,UAAU,gBACV;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,YAAYC,YAAU,CAAC,UAAU,EAClC;EACF,EAED,OAAO,SAAc;EACnB,MAAM,YACJ,OAAO,MAAM,eAAe,WAAW,KAAK,aAAa;EAE3D,MAAM,SADU,kBAAkB,CACX,UAAU,EAAE;EACnC,MAAM,WAAW,YACb,OAAO,QAAQ,UAAU,MAAM,eAAe,UAAU,GACxD;AAEJ,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UACT;IACE,OAAO,SAAS;IAChB,QAAQ;IACT,EACD,MACA,EACD;GACF,CACF,EACF;GAEJ;AAED,QAAO,aACL,UAAU,uBACV;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,IAAIA,YAAU,CAAC,UAAU,EAC1B;EACF,EAED,OAAO,SAAc;EACnB,MAAM,KAAK,OAAO,MAAM,OAAO,WAAW,KAAK,KAAK;EACpD,MAAM,WAAW,wBAAwB;EACzC,MAAM,WAAW,KACb,SAAS,QAAQ,YAAY,QAAQ,OAAO,GAAG,GAC/C;AACJ,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UAAU,EAAE,UAAU,UAAU,EAAE,MAAM,EAAE;GACtD,CACF,EACF;GAEJ;AAED,QAAO,aACL,UAAU,eACV;EACE,OAAO;EACP,aAAa;EACb,aAAa,EAAE;EAChB,EACD,YAAY;EAEV,MAAM,UADW,CAAC,uBAAuB,CAChB,QAAQ,SAAS,CAAC,QAAQ,IAAI,MAAM;EAC7D,MAAM,SAAS,QAAQ,WAAW,IAAI,OAAO;AAC7C,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UACT;IACE;IACA,aAAa;IACd,EACD,MACA,EACD;GACF,CACF,EACF;GAEJ;AAED,QAAO,aACL,UAAU,wBACV;EACE,OAAO;EACP,aACE;EACF,aAAa;GACX,WAAWA,YAAU,CAAC,UAAU;GAChC,UAAUA,YAAU,CAAC,UAAU;GAC/B,cAAcC,SACN;IAAC;IAAQ;IAAiB;IAAoB,CAAC,CACpD,UAAU,CACV,SAAS,uCAAuC;GACpD;EACF,EAED,OAAO,SAAc;AAYnB,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAVW,6BAJf,OAAO,MAAM,cAAc,WAAW,KAAK,YAAY,QAEvD,OAAO,MAAM,aAAa,WAAW,KAAK,WAAW,UACnC,qBAAqB,MAAM,aAAa,CAK3D,CAMoB,KAAK,KAAK;GAC1B,CACF,EACF;GAEJ;AAED,QAAO,aACL,UAAU,cACV;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,QAAQD,YAAU,CAAC,SAAS,iCAAiC,EAC9D;EACF,EAED,OAAO,SAAc;EAEnB,MAAM,SAAS,2BADA,OAAO,MAAM,WAAW,WAAW,KAAK,SAAS,GACf;AACjD,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UAAU,QAAQ,MAAM,EAAE;GACtC,CACF,EACF;GAEJ;AAED,QAAO,aACL,UAAU,YACV;EACE,OAAO;EACP,aACE;EACF,aAAa;GACX,OAAOA,YAAU,CAAC,SAAS,kCAAkC;GAC7D,aAAaE,YACF,CACR,UAAU,CACV,SAAS,mDAAmD;GAChE;EACF,EAED,OAAO,SAAc;EACnB,MAAM,QACJ,OAAO,MAAM,UAAU,WAAW,KAAK,MAAM,aAAa,GAAG;EAC/D,MAAM,aACJ,OAAO,MAAM,gBAAgB,WAAW,KAAK,cAAc;AAE7D,MAAI,CAAC,MACH,QAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UAAU,EAAE,OAAO,qBAAqB,CAAC;GACrD,CACF,EACF;EAGH,MAAMC,UAAiD,CACrD;GAAE,MAAM;GAAa,MAAM,KAAK,aAAa,YAAY;GAAE,EAC3D;GAAE,MAAM;GAAiB,MAAM,KAAK,aAAa,gBAAgB;GAAE,CACpE;EAED,MAAMC,UAMD,EAAE;AAEP,OAAK,MAAM,EAAE,MAAM,UAAU,SAAS;GACpC,IAAIC;AACJ,OAAI;AACF,cAAU,aAAa,MAAM,OAAO;WAC9B;AACN;;GAEF,MAAM,QAAQ,QAAQ,MAAM,KAAK;GACjC,IAAI,iBAAiB;AACrB,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM,MAAM;AACzB,QAAI,KAAK,WAAW,IAAI,CACtB,kBAAiB,KAAK,QAAQ,UAAU,GAAG;AAE7C,QAAI,KAAK,aAAa,CAAC,SAAS,MAAM,EAAE;KACtC,MAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,EAAE;KAChC,MAAM,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,EAAE;AACzC,aAAQ,KAAK;MACX,QAAQ;MACR,SAAS;MACT,SAAS,MAAM,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK;MAC3C,MAAM,IAAI;MACV,UAAU,gBAAgB,eAAe;MAC1C,CAAC;;;;AAKR,UAAQ,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK;EAClE,MAAM,WAAW,QAAQ,MAAM,GAAG,WAAW;AAE7C,SAAO,EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM,KAAK,UACT;IACE;IACA,OAAO,SAAS;IAChB,SAAS,SAAS,KAAK,EAAE,UAAU,WAAW,GAAG,WAAW,KAAK;IAClE,EACD,MACA,EACD;GACF,CACF,EACF;GAEJ;AAED,QAAO,iBACL,gBACA,cAAc,aACd;EACE,OAAO;EACP,aAAa;EACb,UAAU;EACX,EACD,aAAa,EACX,UAAU,CACR;EACE,KAAK,cAAc;EACnB,UAAU;EACV,MAAM,KAAK,UAAU,kBAAkB,EAAE,MAAM,EAAE;EAClD,CACF,EACF,EACF;AAED,QAAO,iBACL,wBACA,cAAc,qBACd;EACE,OAAO;EACP,aAAa;EACb,UAAU;EACX,EACD,aAAa,EACX,UAAU,CACR;EACE,KAAK,cAAc;EACnB,UAAU;EACV,MAAM,KAAK,UAAU,EAAE,UAAU,wBAAwB,EAAE,EAAE,MAAM,EAAE;EACtE,CACF,EACF,EACF;AAED,QAAO,eACL,YAAY,eACZ;EACE,OAAO;EACP,aACE;EACF,YAAY;GACV,WAAWL,YAAU,CAAC,UAAU;GAChC,UAAUA,YAAU,CAAC,UAAU;GAChC;EACF,EAED,OAAO,SAAc;AAKnB,SAAO,EACL,UAAU,CACR;GACE,MAAM;GACN,SAAS;IACP,MAAM;IACN,MAAM,mBATZ,OAAO,MAAM,cAAc,WAAW,KAAK,YAAY,OASd,YAPzC,OAAO,MAAM,aAAa,WAAW,KAAK,WAAW,SAOS;IACzD;GACF,CACF,EACF;GAEJ;AAED,QAAO;;AAGT,MAAM,eAAe,YAA2B;CAC9C,MAAM,SAAS,cAAc;CAC7B,MAAM,YAAY,IAAI,sBAAsB;AAC5C,OAAM,OAAO,QAAQ,UAAU"}
|
package/dist/patching.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patching.d.ts","names":[],"sources":["../src/patching.ts"],"sourcesContent":[],"mappings":";;;;AAgLgB,iBAjJA,gBAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"patching.d.ts","names":[],"sources":["../src/patching.ts"],"sourcesContent":[],"mappings":";;;;AAgLgB,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":"anthropic.d.ts","names":[],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":[],"mappings":";;;;;;AAyBM,cADO,mBACW,
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","names":[],"sources":["../../src/providers/anthropic.ts"],"sourcesContent":[],"mappings":";;;;;;AAyBM,cADO,mBACW,EAAA,OAAM;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;EAiSI,QAAA,UAAA;EAmBA,QAAA,cAAA;EACC,QAAA,iBAAA;EAAN,WAAA,CAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAxUE,OAwUF,EAAA,SAAA,EAvUI,aAuUJ,EAAA,aAAA,EAtUQ,aAsUR,GAAA,IAAA,EAAA,gBAAA,EAAA,OAAA;EAIQ,MAAA,CAAA,MAAA,EA3TP,MA2TO,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,kBAAA,CAAA,EA1TM,oBA0TN,CAAA,EAzTd,OAyTc,CAzTN,iBAyTM,GAzTc,aAyTd,CAAA,OAAA,CAAA,CAAA;EAAN,QAAA,WAAA;EAAK,QAAA,mBAAA;;;iBAxBF,4BAAA;iBAmBA,uBAAA,UACL,MAAM;;;aAIJ,MAAM"}
|
|
@@ -3,7 +3,7 @@ import { getDefaultPropagateContext, injectContext } from "../propagation.js";
|
|
|
3
3
|
import { tryRequire } from "../utils/resolve-module.js";
|
|
4
4
|
import { calculateCost } from "../utils/costs.js";
|
|
5
5
|
import { StreamingAccumulator } from "../utils/streaming.js";
|
|
6
|
-
import { BaseAIProvider, applySessionContext } from "./base.js";
|
|
6
|
+
import { BaseAIProvider, applySessionContext, contextFields } from "./base.js";
|
|
7
7
|
|
|
8
8
|
//#region src/providers/anthropic.ts
|
|
9
9
|
const _resolved = tryRequire("@anthropic-ai/sdk");
|
|
@@ -75,17 +75,12 @@ var WrappedMessages = class {
|
|
|
75
75
|
});
|
|
76
76
|
} catch {}
|
|
77
77
|
this._trackFn({
|
|
78
|
-
|
|
78
|
+
...contextFields(ctx),
|
|
79
79
|
modelName,
|
|
80
80
|
provider: "anthropic",
|
|
81
81
|
responseContent: String(firstTextBlock?.text ?? ""),
|
|
82
82
|
reasoningContent: extracted.reasoning,
|
|
83
83
|
latencyMs,
|
|
84
|
-
sessionId: ctx.sessionId,
|
|
85
|
-
traceId: ctx.traceId,
|
|
86
|
-
turnId: ctx.turnId ?? void 0,
|
|
87
|
-
agentId: ctx.agentId,
|
|
88
|
-
env: ctx.env,
|
|
89
84
|
inputTokens: normalizedInput || void 0,
|
|
90
85
|
outputTokens: usage?.output_tokens,
|
|
91
86
|
cacheReadInputTokens: cacheRead || void 0,
|
|
@@ -103,15 +98,11 @@ var WrappedMessages = class {
|
|
|
103
98
|
} catch (error) {
|
|
104
99
|
const latencyMs = performance.now() - startTime;
|
|
105
100
|
this._trackFn({
|
|
106
|
-
|
|
101
|
+
...contextFields(ctx),
|
|
107
102
|
modelName: String(requestParams.model ?? "unknown"),
|
|
108
103
|
provider: "anthropic",
|
|
109
104
|
responseContent: "",
|
|
110
105
|
latencyMs,
|
|
111
|
-
sessionId: ctx.sessionId,
|
|
112
|
-
traceId: ctx.traceId,
|
|
113
|
-
agentId: ctx.agentId,
|
|
114
|
-
env: ctx.env,
|
|
115
106
|
isError: true,
|
|
116
107
|
errorMessage: error instanceof Error ? error.message : String(error)
|
|
117
108
|
});
|
|
@@ -178,16 +169,11 @@ var WrappedMessages = class {
|
|
|
178
169
|
});
|
|
179
170
|
} catch {}
|
|
180
171
|
this._trackFn({
|
|
181
|
-
|
|
172
|
+
...contextFields(sessionCtx),
|
|
182
173
|
modelName,
|
|
183
174
|
provider: "anthropic",
|
|
184
175
|
responseContent: state.content,
|
|
185
176
|
latencyMs: accumulator.elapsedMs,
|
|
186
|
-
sessionId: sessionCtx.sessionId,
|
|
187
|
-
traceId: sessionCtx.traceId,
|
|
188
|
-
turnId: sessionCtx.turnId ?? void 0,
|
|
189
|
-
agentId: sessionCtx.agentId,
|
|
190
|
-
env: sessionCtx.env,
|
|
191
177
|
inputTokens: streamNormalizedInput || void 0,
|
|
192
178
|
outputTokens: state.outputTokens,
|
|
193
179
|
cacheReadInputTokens: streamCacheRead || void 0,
|
|
@@ -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 {\n resolveAmplitude,\n type AmplitudeLike,\n type AmplitudeOrAI,\n type AnthropicResponse,\n type 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 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 });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n userId: ctx.userId ?? 'unknown',\n modelName,\n provider: 'anthropic',\n responseContent: String(firstTextBlock?.text ?? ''),\n reasoningContent: extracted.reasoning,\n latencyMs,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\n agentId: ctx.agentId,\n env: ctx.env,\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 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 userId: ctx.userId ?? 'unknown',\n modelName: String(requestParams.model ?? 'unknown'),\n provider: 'anthropic',\n responseContent: '',\n latencyMs,\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n agentId: ctx.agentId,\n env: ctx.env,\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 });\n } catch {\n // cost calculation is best-effort\n }\n }\n\n this._trackFn({\n userId: sessionCtx.userId ?? 'unknown',\n modelName,\n provider: 'anthropic',\n responseContent: state.content,\n latencyMs: accumulator.elapsedMs,\n sessionId: sessionCtx.sessionId,\n traceId: sessionCtx.traceId,\n turnId: sessionCtx.turnId ?? undefined,\n agentId: sessionCtx.agentId,\n env: sessionCtx.env,\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 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 agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n env: ctx.env,\n groups: ctx.groups,\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"],"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 });\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 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 });\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 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 agentId: ctx.agentId,\n parentAgentId: ctx.parentAgentId,\n customerOrgId: ctx.customerOrgId,\n env: ctx.env,\n groups: ctx.groups,\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"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PrivacyConfig } from "../core/privacy.js";
|
|
2
2
|
import { AmplitudeOrAI } from "../types.js";
|
|
3
|
-
import { BaseAIProvider } from "./base.js";
|
|
3
|
+
import { BaseAIProvider, ProviderTrackOptions } from "./base.js";
|
|
4
4
|
import { OPENAI_AVAILABLE } from "./openai.js";
|
|
5
5
|
|
|
6
6
|
//#region src/providers/azure-openai.d.ts
|
|
@@ -20,8 +20,8 @@ declare class AzureOpenAI extends BaseAIProvider {
|
|
|
20
20
|
private _propagateContext;
|
|
21
21
|
readonly chat: {
|
|
22
22
|
completions: {
|
|
23
|
-
create: (params: Record<string, unknown
|
|
24
|
-
parse: (params: Record<string, unknown
|
|
23
|
+
create: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions) => Promise<unknown>;
|
|
24
|
+
parse: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions) => Promise<unknown>;
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
constructor(options: AzureOpenAIOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"azure-openai.d.ts","names":[],"sources":["../../src/providers/azure-openai.ts"],"sourcesContent":[],"mappings":";;;;;;;AAgCuB,UAhBN,kBAAA,CAgBM;
|
|
1
|
+
{"version":3,"file":"azure-openai.d.ts","names":[],"sources":["../../src/providers/azure-openai.ts"],"sourcesContent":[],"mappings":";;;;;;;AAgCuB,UAhBN,kBAAA,CAgBM;EAA8C,SAAA,EAfxD,aAewD;EAAyB,MAAA,CAAA,EAAA,MAAA;EACxE,aAAA,CAAA,EAAA,MAAA;EAA8C,UAAA,CAAA,EAAA,MAAA;EAAyB,aAAA,CAAA,EAZ3E,aAY2E,GAAA,IAAA;EAItE,gBAAA,CAAA,EAAA,OAAA;EAVU;EAAc,YAAA,CAAA,EAAA,OAAA;;cAAlC,WAAA,SAAoB,cAAA;;;;;uBAKV,8CAA8C,yBAAyB;sBACxE,8CAA8C,yBAAyB;;;uBAItE"}
|
|
@@ -25,8 +25,8 @@ var AzureOpenAI = class extends BaseAIProvider {
|
|
|
25
25
|
const originalCompletions = this._client.chat.completions;
|
|
26
26
|
const wrappedCompletions = new WrappedCompletions(originalCompletions, this.trackFn(), this._amplitude, this._privacyConfig, this._propagateContext, "azure-openai");
|
|
27
27
|
this.chat = { completions: {
|
|
28
|
-
create: (params) => wrappedCompletions.create(params),
|
|
29
|
-
parse: (params) => wrappedCompletions.parse(params)
|
|
28
|
+
create: (params, amplitudeOverrides) => wrappedCompletions.create(params, amplitudeOverrides),
|
|
29
|
+
parse: (params, amplitudeOverrides) => wrappedCompletions.parse(params, amplitudeOverrides)
|
|
30
30
|
} };
|
|
31
31
|
}
|
|
32
32
|
get client() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"azure-openai.js","names":["clientOpts: Record<string, unknown>"],"sources":["../../src/providers/azure-openai.ts"],"sourcesContent":["/**\n * Azure OpenAI provider wrapper — reuses OpenAI wrapper logic.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { getDefaultPropagateContext } from '../propagation.js';\nimport type { AmplitudeOrAI } from '../types.js';\nimport { BaseAIProvider } from './base.js';\nimport {\n _OpenAIModule,\n OPENAI_AVAILABLE,\n WrappedCompletions,\n} from './openai.js';\n\nexport { OPENAI_AVAILABLE as AZURE_OPENAI_AVAILABLE };\n\nexport interface AzureOpenAIOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n azureEndpoint?: string;\n apiVersion?: 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 AzureOpenAI extends BaseAIProvider {\n private _client: unknown;\n private _propagateContext: boolean;\n readonly chat: {\n completions: {\n create: (params: Record<string, unknown
|
|
1
|
+
{"version":3,"file":"azure-openai.js","names":["clientOpts: Record<string, unknown>"],"sources":["../../src/providers/azure-openai.ts"],"sourcesContent":["/**\n * Azure OpenAI provider wrapper — reuses OpenAI wrapper logic.\n */\n\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport { getDefaultPropagateContext } from '../propagation.js';\nimport type { AmplitudeOrAI } from '../types.js';\nimport { BaseAIProvider, type ProviderTrackOptions } from './base.js';\nimport {\n _OpenAIModule,\n OPENAI_AVAILABLE,\n WrappedCompletions,\n} from './openai.js';\n\nexport { OPENAI_AVAILABLE as AZURE_OPENAI_AVAILABLE };\n\nexport interface AzureOpenAIOptions {\n amplitude: AmplitudeOrAI;\n apiKey?: string;\n azureEndpoint?: string;\n apiVersion?: 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 AzureOpenAI extends BaseAIProvider {\n private _client: unknown;\n private _propagateContext: boolean;\n readonly chat: {\n completions: {\n create: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions) => Promise<unknown>;\n parse: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions) => Promise<unknown>;\n };\n };\n\n constructor(options: AzureOpenAIOptions) {\n super({\n amplitude: options.amplitude,\n privacyConfig: options.privacyConfig,\n providerName: 'azure-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 for Azure OpenAI. Install it with: npm install openai — or pass the module directly via the openaiModule option.',\n );\n }\n\n const AzureOpenAISDK = mod.AzureOpenAI 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.azureEndpoint) clientOpts.baseURL = options.azureEndpoint;\n if (options.apiVersion) {\n clientOpts.defaultQuery = { 'api-version': options.apiVersion };\n }\n\n this._client = new AzureOpenAISDK(clientOpts);\n this._propagateContext =\n options.propagateContext ?? getDefaultPropagateContext();\n const clientObj = this._client as Record<string, unknown>;\n const originalChat = clientObj.chat as Record<string, unknown>;\n const originalCompletions = originalChat.completions as Record<\n string,\n unknown\n >;\n const wrappedCompletions = new WrappedCompletions(\n originalCompletions,\n this.trackFn(),\n this._amplitude,\n this._privacyConfig,\n this._propagateContext,\n 'azure-openai',\n );\n\n this.chat = {\n completions: {\n create: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions): Promise<unknown> =>\n wrappedCompletions.create(params, amplitudeOverrides),\n parse: (params: Record<string, unknown>, amplitudeOverrides?: ProviderTrackOptions): Promise<unknown> =>\n wrappedCompletions.parse(params, amplitudeOverrides),\n },\n };\n }\n\n get client(): unknown {\n return this._client;\n }\n}\n"],"mappings":";;;;;AA2BA,IAAa,cAAb,cAAiC,eAAe;CAC9C,AAAQ;CACR,AAAQ;CACR,AAAS;CAOT,YAAY,SAA6B;AACvC,QAAM;GACJ,WAAW,QAAQ;GACnB,eAAe,QAAQ;GACvB,cAAc;GACf,CAAC;EAEF,MAAM,MACH,QAAQ,gBAAmD;AAC9D,MAAI,OAAO,KACT,OAAM,IAAI,MACR,8IACD;EAGH,MAAM,iBAAiB,IAAI;EAI3B,MAAMA,aAAsC,EAAE;AAC9C,MAAI,QAAQ,OAAQ,YAAW,SAAS,QAAQ;AAChD,MAAI,QAAQ,cAAe,YAAW,UAAU,QAAQ;AACxD,MAAI,QAAQ,WACV,YAAW,eAAe,EAAE,eAAe,QAAQ,YAAY;AAGjE,OAAK,UAAU,IAAI,eAAe,WAAW;AAC7C,OAAK,oBACH,QAAQ,oBAAoB,4BAA4B;EAG1D,MAAM,sBAFY,KAAK,QACQ,KACU;EAIzC,MAAM,qBAAqB,IAAI,mBAC7B,qBACA,KAAK,SAAS,EACd,KAAK,YACL,KAAK,gBACL,KAAK,mBACL,eACD;AAED,OAAK,OAAO,EACV,aAAa;GACX,SAAS,QAAiC,uBACxC,mBAAmB,OAAO,QAAQ,mBAAmB;GACvD,QAAQ,QAAiC,uBACvC,mBAAmB,MAAM,QAAQ,mBAAmB;GACvD,EACF;;CAGH,IAAI,SAAkB;AACpB,SAAO,KAAK"}
|
package/dist/providers/base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PrivacyConfig } from "../core/privacy.js";
|
|
2
|
-
import { AmplitudeLike, AmplitudeOrAI, TrackFn } from "../types.js";
|
|
2
|
+
import { AmplitudeLike, AmplitudeOrAI, TrackCallOptions, TrackFn } from "../types.js";
|
|
3
3
|
import { TrackAiMessageOptions } from "../core/tracking.js";
|
|
4
4
|
import { StreamingAccumulator } from "../utils/streaming.js";
|
|
5
5
|
|
|
@@ -22,6 +22,8 @@ interface ProviderTrackOptions {
|
|
|
22
22
|
agentId?: string | null;
|
|
23
23
|
parentAgentId?: string | null;
|
|
24
24
|
customerOrgId?: string | null;
|
|
25
|
+
agentVersion?: string | null;
|
|
26
|
+
context?: Record<string, unknown> | null;
|
|
25
27
|
env?: string | null;
|
|
26
28
|
groups?: Record<string, unknown> | null;
|
|
27
29
|
eventProperties?: Record<string, unknown> | null;
|
|
@@ -39,6 +41,13 @@ interface ProviderTrackOptions {
|
|
|
39
41
|
declare function applySessionContext(overrides?: ProviderTrackOptions): ProviderTrackOptions & {
|
|
40
42
|
userId: string;
|
|
41
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Extract all context fields from a resolved ProviderTrackOptions into a
|
|
46
|
+
* flat object suitable for spreading into _trackFn() / _track() calls.
|
|
47
|
+
* Ensures all 13 context fields propagate consistently.
|
|
48
|
+
*/
|
|
49
|
+
type TrackContextFields = Pick<TrackCallOptions, 'userId' | 'sessionId' | 'traceId' | 'turnId' | 'agentId' | 'parentAgentId' | 'customerOrgId' | 'agentVersion' | 'context' | 'env' | 'groups' | 'eventProperties'>;
|
|
50
|
+
declare function contextFields(ctx: ProviderTrackOptions): TrackContextFields;
|
|
42
51
|
declare abstract class BaseAIProvider {
|
|
43
52
|
protected _amplitude: AmplitudeLike;
|
|
44
53
|
protected _privacyConfig: PrivacyConfig | null;
|
|
@@ -66,5 +75,5 @@ declare class SimpleStreamingTracker {
|
|
|
66
75
|
finalize(overrides?: ProviderTrackOptions): string;
|
|
67
76
|
}
|
|
68
77
|
//#endregion
|
|
69
|
-
export { BaseAIProvider, ProviderTrackOptions, SimpleStreamingTracker, applySessionContext };
|
|
78
|
+
export { BaseAIProvider, ProviderTrackOptions, SimpleStreamingTracker, TrackContextFields, applySessionContext, contextFields };
|
|
70
79
|
//# sourceMappingURL=base.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/providers/base.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/providers/base.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA2DA;AAgDA;AAgBA;AAiBA;;;;AAOoB,UAjHH,oBAAA,CAiHG;EAQU,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAL,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAmCZ,OAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAKe,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAsB,OAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAKrC,aAAA,CAAA,EAAA,MAAA,GAAsB,IAAA;EAEX,aAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAIA,YAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAeK,OAAA,CAAA,EAlLjB,MAkLiB,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;EAAX,GAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAQM,MAAA,CAAA,EAxLb,MAwLa,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;EAIF,eAAA,CAAA,EA3LF,MA2LE,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;EAAyB;;;;;;;;;;;iBA9K/B,mBAAA,aACH,uBACV;;;;;;;;KA8CS,kBAAA,GAAqB,KAC/B;iBAec,aAAA,MAAmB,uBAAuB;uBAiBpC,cAAA;wBACE;4BACI;;;eAIb;oBACK;;;yBAQK,KAAK;aAmCjB;4BAKe;;cAKf,sBAAA;;wBAEW;;;wBAIA;;;kBAeN,WAAW;;wBAQL;uBAIF"}
|
package/dist/providers/base.js
CHANGED
|
@@ -25,10 +25,14 @@ function applySessionContext(overrides = {}) {
|
|
|
25
25
|
if (!result.agentId) result.agentId = ctx.agentId;
|
|
26
26
|
if (!result.parentAgentId) result.parentAgentId = ctx.parentAgentId;
|
|
27
27
|
if (!result.customerOrgId) result.customerOrgId = ctx.customerOrgId;
|
|
28
|
+
if (!result.agentVersion) result.agentVersion = ctx.agentVersion;
|
|
29
|
+
if (!result.context) result.context = ctx.context;
|
|
28
30
|
if (!result.env) result.env = ctx.env;
|
|
29
31
|
if (!result.groups) result.groups = ctx.groups;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
if (result.turnId == null) {
|
|
33
|
+
const turnId = ctx.nextTurnId();
|
|
34
|
+
if (turnId != null) result.turnId = turnId;
|
|
35
|
+
}
|
|
32
36
|
const existingEp = result.eventProperties;
|
|
33
37
|
const ep = existingEp != null ? { ...existingEp } : {};
|
|
34
38
|
if (ctx.idleTimeoutMinutes != null && !(PROP_IDLE_TIMEOUT_MINUTES in ep)) ep[PROP_IDLE_TIMEOUT_MINUTES] = ctx.idleTimeoutMinutes;
|
|
@@ -37,6 +41,22 @@ function applySessionContext(overrides = {}) {
|
|
|
37
41
|
}
|
|
38
42
|
return result;
|
|
39
43
|
}
|
|
44
|
+
function contextFields(ctx) {
|
|
45
|
+
return {
|
|
46
|
+
userId: ctx.userId ?? "unknown",
|
|
47
|
+
sessionId: ctx.sessionId,
|
|
48
|
+
traceId: ctx.traceId,
|
|
49
|
+
turnId: ctx.turnId ?? void 0,
|
|
50
|
+
agentId: ctx.agentId,
|
|
51
|
+
parentAgentId: ctx.parentAgentId,
|
|
52
|
+
customerOrgId: ctx.customerOrgId,
|
|
53
|
+
agentVersion: ctx.agentVersion,
|
|
54
|
+
context: ctx.context,
|
|
55
|
+
env: ctx.env,
|
|
56
|
+
groups: ctx.groups,
|
|
57
|
+
eventProperties: ctx.eventProperties
|
|
58
|
+
};
|
|
59
|
+
}
|
|
40
60
|
var BaseAIProvider = class {
|
|
41
61
|
_amplitude;
|
|
42
62
|
_privacyConfig;
|
|
@@ -55,8 +75,11 @@ var BaseAIProvider = class {
|
|
|
55
75
|
agentId: opts.agentId,
|
|
56
76
|
parentAgentId: opts.parentAgentId,
|
|
57
77
|
customerOrgId: opts.customerOrgId,
|
|
78
|
+
agentVersion: opts.agentVersion,
|
|
79
|
+
context: opts.context,
|
|
58
80
|
env: opts.env,
|
|
59
|
-
groups: opts.groups
|
|
81
|
+
groups: opts.groups,
|
|
82
|
+
eventProperties: opts.eventProperties
|
|
60
83
|
});
|
|
61
84
|
return trackAiMessage({
|
|
62
85
|
...opts,
|
|
@@ -68,8 +91,11 @@ var BaseAIProvider = class {
|
|
|
68
91
|
agentId: merged.agentId ?? opts.agentId,
|
|
69
92
|
parentAgentId: merged.parentAgentId ?? opts.parentAgentId,
|
|
70
93
|
customerOrgId: merged.customerOrgId ?? opts.customerOrgId,
|
|
94
|
+
agentVersion: merged.agentVersion ?? opts.agentVersion,
|
|
95
|
+
context: merged.context ?? opts.context,
|
|
71
96
|
env: merged.env ?? opts.env,
|
|
72
97
|
groups: merged.groups ?? opts.groups,
|
|
98
|
+
eventProperties: merged.eventProperties ?? opts.eventProperties,
|
|
73
99
|
privacyConfig: this._privacyConfig
|
|
74
100
|
});
|
|
75
101
|
}
|
|
@@ -109,7 +135,7 @@ var SimpleStreamingTracker = class {
|
|
|
109
135
|
finalize(overrides = {}) {
|
|
110
136
|
const state = this.accumulator.getState();
|
|
111
137
|
return this._trackFn({
|
|
112
|
-
|
|
138
|
+
...contextFields(overrides),
|
|
113
139
|
modelName: this._modelName,
|
|
114
140
|
provider: this._providerName,
|
|
115
141
|
responseContent: state.content,
|
|
@@ -123,19 +149,11 @@ var SimpleStreamingTracker = class {
|
|
|
123
149
|
finishReason: state.finishReason,
|
|
124
150
|
toolCalls: state.toolCalls.length > 0 ? state.toolCalls : null,
|
|
125
151
|
providerTtfbMs: state.ttfbMs,
|
|
126
|
-
isStreaming: true
|
|
127
|
-
sessionId: overrides.sessionId,
|
|
128
|
-
traceId: overrides.traceId,
|
|
129
|
-
turnId: overrides.turnId ?? void 0,
|
|
130
|
-
agentId: overrides.agentId,
|
|
131
|
-
parentAgentId: overrides.parentAgentId,
|
|
132
|
-
customerOrgId: overrides.customerOrgId,
|
|
133
|
-
env: overrides.env,
|
|
134
|
-
groups: overrides.groups
|
|
152
|
+
isStreaming: true
|
|
135
153
|
});
|
|
136
154
|
}
|
|
137
155
|
};
|
|
138
156
|
|
|
139
157
|
//#endregion
|
|
140
|
-
export { BaseAIProvider, SimpleStreamingTracker, applySessionContext };
|
|
158
|
+
export { BaseAIProvider, SimpleStreamingTracker, applySessionContext, contextFields };
|
|
141
159
|
//# sourceMappingURL=base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","names":["result: Record<string, unknown>"],"sources":["../../src/providers/base.ts"],"sourcesContent":["/**\n * Base class for AI provider wrappers.\n *\n * Provides shared tracking logic and session context integration.\n */\n\nimport { getActiveContext } from '../context.js';\nimport {\n PROP_IDLE_TIMEOUT_MINUTES,\n PROP_SESSION_REPLAY_ID,\n} from '../core/constants.js';\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport {\n trackAiMessage,\n type TrackAiMessageOptions,\n} from '../core/tracking.js';\nimport {\n resolveAmplitude,\n type AmplitudeLike,\n type AmplitudeOrAI,\n type TrackCallOptions,\n type TrackFn,\n} from '../types.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\n\n/**\n * Per-call context overrides for provider wrappers.\n *\n * Pass as the second argument to wrapped provider methods\n * (e.g., `openai.chat.completions.create(params, overrides)`)\n * to set Amplitude tracking context for that specific call.\n * Any fields left `null`/`undefined` are filled from the\n * active `SessionContext` via `AsyncLocalStorage`.\n */\nexport interface ProviderTrackOptions {\n userId?: string | null;\n sessionId?: string | null;\n traceId?: string | null;\n turnId?: number | null;\n agentId?: string | null;\n parentAgentId?: string | null;\n customerOrgId?: string | null;\n env?: string | null;\n groups?: Record<string, unknown> | null;\n eventProperties?: Record<string, unknown> | null;\n /**\n * Controls whether provider wrappers auto-track user input payloads.\n * Set to false when you already call `trackUserMessage()` explicitly.\n */\n trackInputMessages?: boolean;\n}\n\n/**\n * Apply session context fields from AsyncLocalStorage to tracking options.\n * Returns a merged set of fields with explicit values taking precedence.\n * Also injects idle_timeout_minutes and session_replay_id from the context.\n */\nexport function applySessionContext(\n overrides: ProviderTrackOptions = {},\n): ProviderTrackOptions & { userId: string } {\n const ctx = getActiveContext();\n const result: Record<string, unknown> = { ...overrides };\n\n if (ctx != null) {\n if (!result.userId) result.userId = ctx.userId;\n if (!result.sessionId) result.sessionId = ctx.sessionId;\n if (!result.traceId) result.traceId = ctx.traceId;\n if (!result.agentId) result.agentId = ctx.agentId;\n if (!result.parentAgentId) result.parentAgentId = ctx.parentAgentId;\n if (!result.customerOrgId) result.customerOrgId = ctx.customerOrgId;\n if (!result.env) result.env = ctx.env;\n if (!result.groups) result.groups = ctx.groups;\n\n const turnId = ctx.nextTurnId();\n if (turnId != null && result.turnId == null) result.turnId = turnId;\n\n const existingEp = result.eventProperties as Record<string, unknown> | null;\n const ep = existingEp != null ? { ...existingEp } : {};\n if (ctx.idleTimeoutMinutes != null && !(PROP_IDLE_TIMEOUT_MINUTES in ep)) {\n ep[PROP_IDLE_TIMEOUT_MINUTES] = ctx.idleTimeoutMinutes;\n }\n if (\n ctx.deviceId &&\n ctx.browserSessionId &&\n !(PROP_SESSION_REPLAY_ID in ep)\n ) {\n ep[PROP_SESSION_REPLAY_ID] = `${ctx.deviceId}/${ctx.browserSessionId}`;\n }\n if (Object.keys(ep).length > 0) {\n result.eventProperties = ep;\n }\n }\n\n return result as unknown as ProviderTrackOptions & { userId: string };\n}\n\nexport abstract class BaseAIProvider {\n protected _amplitude: AmplitudeLike;\n protected _privacyConfig: PrivacyConfig | null;\n readonly _providerName: string;\n\n constructor(options: {\n amplitude: AmplitudeOrAI;\n privacyConfig?: PrivacyConfig | null;\n providerName: string;\n }) {\n this._amplitude = resolveAmplitude(options.amplitude);\n this._privacyConfig = options.privacyConfig ?? null;\n this._providerName = options.providerName;\n }\n\n protected _track(opts: Omit<TrackAiMessageOptions, 'amplitude'>): string {\n const merged = applySessionContext({\n userId: opts.userId,\n sessionId: opts.sessionId,\n traceId: opts.traceId,\n turnId: opts.turnId,\n agentId: opts.agentId,\n parentAgentId: opts.parentAgentId,\n customerOrgId: opts.customerOrgId,\n env: opts.env,\n groups: opts.groups,\n });\n\n return trackAiMessage({\n ...opts,\n amplitude: this._amplitude,\n userId: merged.userId ?? opts.userId,\n sessionId: merged.sessionId ?? opts.sessionId,\n traceId: merged.traceId ?? opts.traceId,\n turnId: merged.turnId ?? opts.turnId,\n agentId: merged.agentId ?? opts.agentId,\n parentAgentId: merged.parentAgentId ?? opts.parentAgentId,\n customerOrgId: merged.customerOrgId ?? opts.customerOrgId,\n env: merged.env ?? opts.env,\n groups: merged.groups ?? opts.groups,\n privacyConfig: this._privacyConfig,\n });\n }\n\n trackFn(): TrackFn {\n return (opts: TrackCallOptions) =>\n this._track(opts as Omit<TrackAiMessageOptions, 'amplitude'>);\n }\n\n createStreamingTracker(): SimpleStreamingTracker {\n return new SimpleStreamingTracker(this);\n }\n}\n\nexport class SimpleStreamingTracker {\n private _trackFn: TrackFn;\n readonly accumulator: StreamingAccumulator;\n private _modelName = 'unknown';\n private _providerName: string;\n\n constructor(provider: BaseAIProvider) {\n this._trackFn = provider.trackFn();\n this._providerName = provider._providerName;\n this.accumulator = new StreamingAccumulator();\n }\n\n setModel(model: string): void {\n this._modelName = model;\n this.accumulator.model = model;\n }\n\n addContent(chunk: string): void {\n this.accumulator.addContent(chunk);\n }\n\n setUsage(usage: Parameters<StreamingAccumulator['setUsage']>[0]): void {\n this.accumulator.setUsage(usage);\n }\n\n setFinishReason(reason: string): void {\n this.accumulator.finishReason = reason;\n }\n\n addToolCall(toolCall: Record<string, unknown>): void {\n this.accumulator.addToolCall(toolCall);\n }\n\n finalize(overrides: ProviderTrackOptions = {}): string {\n const state = this.accumulator.getState();\n\n return this._trackFn({\n userId: overrides.userId ?? 'unknown',\n modelName: this._modelName,\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: this.accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n cacheReadInputTokens: state.cacheReadTokens,\n cacheCreationInputTokens: state.cacheCreationTokens,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : null,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n sessionId: overrides.sessionId,\n traceId: overrides.traceId,\n turnId: overrides.turnId ?? undefined,\n agentId: overrides.agentId,\n parentAgentId: overrides.parentAgentId,\n customerOrgId: overrides.customerOrgId,\n env: overrides.env,\n groups: overrides.groups,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base.js","names":["result: Record<string, unknown>"],"sources":["../../src/providers/base.ts"],"sourcesContent":["/**\n * Base class for AI provider wrappers.\n *\n * Provides shared tracking logic and session context integration.\n */\n\nimport { getActiveContext } from '../context.js';\nimport {\n PROP_IDLE_TIMEOUT_MINUTES,\n PROP_SESSION_REPLAY_ID,\n} from '../core/constants.js';\nimport type { PrivacyConfig } from '../core/privacy.js';\nimport {\n trackAiMessage,\n type TrackAiMessageOptions,\n} from '../core/tracking.js';\nimport {\n resolveAmplitude,\n type AmplitudeLike,\n type AmplitudeOrAI,\n type TrackCallOptions,\n type TrackFn,\n} from '../types.js';\nimport { StreamingAccumulator } from '../utils/streaming.js';\n\n/**\n * Per-call context overrides for provider wrappers.\n *\n * Pass as the second argument to wrapped provider methods\n * (e.g., `openai.chat.completions.create(params, overrides)`)\n * to set Amplitude tracking context for that specific call.\n * Any fields left `null`/`undefined` are filled from the\n * active `SessionContext` via `AsyncLocalStorage`.\n */\nexport interface ProviderTrackOptions {\n userId?: string | null;\n sessionId?: string | null;\n traceId?: string | null;\n turnId?: number | null;\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 /**\n * Controls whether provider wrappers auto-track user input payloads.\n * Set to false when you already call `trackUserMessage()` explicitly.\n */\n trackInputMessages?: boolean;\n}\n\n/**\n * Apply session context fields from AsyncLocalStorage to tracking options.\n * Returns a merged set of fields with explicit values taking precedence.\n * Also injects idle_timeout_minutes and session_replay_id from the context.\n */\nexport function applySessionContext(\n overrides: ProviderTrackOptions = {},\n): ProviderTrackOptions & { userId: string } {\n const ctx = getActiveContext();\n const result: Record<string, unknown> = { ...overrides };\n\n if (ctx != null) {\n if (!result.userId) result.userId = ctx.userId;\n if (!result.sessionId) result.sessionId = ctx.sessionId;\n if (!result.traceId) result.traceId = ctx.traceId;\n if (!result.agentId) result.agentId = ctx.agentId;\n if (!result.parentAgentId) result.parentAgentId = ctx.parentAgentId;\n if (!result.customerOrgId) result.customerOrgId = ctx.customerOrgId;\n if (!result.agentVersion) result.agentVersion = ctx.agentVersion;\n if (!result.context) result.context = ctx.context;\n if (!result.env) result.env = ctx.env;\n if (!result.groups) result.groups = ctx.groups;\n\n if (result.turnId == null) {\n const turnId = ctx.nextTurnId();\n if (turnId != null) result.turnId = turnId;\n }\n\n const existingEp = result.eventProperties as Record<string, unknown> | null;\n const ep = existingEp != null ? { ...existingEp } : {};\n if (ctx.idleTimeoutMinutes != null && !(PROP_IDLE_TIMEOUT_MINUTES in ep)) {\n ep[PROP_IDLE_TIMEOUT_MINUTES] = ctx.idleTimeoutMinutes;\n }\n if (\n ctx.deviceId &&\n ctx.browserSessionId &&\n !(PROP_SESSION_REPLAY_ID in ep)\n ) {\n ep[PROP_SESSION_REPLAY_ID] = `${ctx.deviceId}/${ctx.browserSessionId}`;\n }\n if (Object.keys(ep).length > 0) {\n result.eventProperties = ep;\n }\n }\n\n return result as unknown as ProviderTrackOptions & { userId: string };\n}\n\n/**\n * Extract all context fields from a resolved ProviderTrackOptions into a\n * flat object suitable for spreading into _trackFn() / _track() calls.\n * Ensures all 13 context fields propagate consistently.\n */\nexport type TrackContextFields = Pick<\n TrackCallOptions,\n | 'userId'\n | 'sessionId'\n | 'traceId'\n | 'turnId'\n | 'agentId'\n | 'parentAgentId'\n | 'customerOrgId'\n | 'agentVersion'\n | 'context'\n | 'env'\n | 'groups'\n | 'eventProperties'\n>;\n\nexport function contextFields(ctx: ProviderTrackOptions): TrackContextFields {\n return {\n userId: ctx.userId ?? 'unknown',\n sessionId: ctx.sessionId,\n traceId: ctx.traceId,\n turnId: ctx.turnId ?? undefined,\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 };\n}\n\nexport abstract class BaseAIProvider {\n protected _amplitude: AmplitudeLike;\n protected _privacyConfig: PrivacyConfig | null;\n readonly _providerName: string;\n\n constructor(options: {\n amplitude: AmplitudeOrAI;\n privacyConfig?: PrivacyConfig | null;\n providerName: string;\n }) {\n this._amplitude = resolveAmplitude(options.amplitude);\n this._privacyConfig = options.privacyConfig ?? null;\n this._providerName = options.providerName;\n }\n\n protected _track(opts: Omit<TrackAiMessageOptions, 'amplitude'>): string {\n const merged = applySessionContext({\n userId: opts.userId,\n sessionId: opts.sessionId,\n traceId: opts.traceId,\n turnId: opts.turnId,\n agentId: opts.agentId,\n parentAgentId: opts.parentAgentId,\n customerOrgId: opts.customerOrgId,\n agentVersion: opts.agentVersion,\n context: opts.context,\n env: opts.env,\n groups: opts.groups,\n eventProperties: opts.eventProperties,\n });\n\n return trackAiMessage({\n ...opts,\n amplitude: this._amplitude,\n userId: merged.userId ?? opts.userId,\n sessionId: merged.sessionId ?? opts.sessionId,\n traceId: merged.traceId ?? opts.traceId,\n turnId: merged.turnId ?? opts.turnId,\n agentId: merged.agentId ?? opts.agentId,\n parentAgentId: merged.parentAgentId ?? opts.parentAgentId,\n customerOrgId: merged.customerOrgId ?? opts.customerOrgId,\n agentVersion: merged.agentVersion ?? opts.agentVersion,\n context: merged.context ?? opts.context,\n env: merged.env ?? opts.env,\n groups: merged.groups ?? opts.groups,\n eventProperties: merged.eventProperties ?? opts.eventProperties,\n privacyConfig: this._privacyConfig,\n });\n }\n\n trackFn(): TrackFn {\n return (opts: TrackCallOptions) =>\n this._track(opts as Omit<TrackAiMessageOptions, 'amplitude'>);\n }\n\n createStreamingTracker(): SimpleStreamingTracker {\n return new SimpleStreamingTracker(this);\n }\n}\n\nexport class SimpleStreamingTracker {\n private _trackFn: TrackFn;\n readonly accumulator: StreamingAccumulator;\n private _modelName = 'unknown';\n private _providerName: string;\n\n constructor(provider: BaseAIProvider) {\n this._trackFn = provider.trackFn();\n this._providerName = provider._providerName;\n this.accumulator = new StreamingAccumulator();\n }\n\n setModel(model: string): void {\n this._modelName = model;\n this.accumulator.model = model;\n }\n\n addContent(chunk: string): void {\n this.accumulator.addContent(chunk);\n }\n\n setUsage(usage: Parameters<StreamingAccumulator['setUsage']>[0]): void {\n this.accumulator.setUsage(usage);\n }\n\n setFinishReason(reason: string): void {\n this.accumulator.finishReason = reason;\n }\n\n addToolCall(toolCall: Record<string, unknown>): void {\n this.accumulator.addToolCall(toolCall);\n }\n\n finalize(overrides: ProviderTrackOptions = {}): string {\n const state = this.accumulator.getState();\n\n return this._trackFn({\n ...contextFields(overrides),\n modelName: this._modelName,\n provider: this._providerName,\n responseContent: state.content,\n latencyMs: this.accumulator.elapsedMs,\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.totalTokens,\n reasoningTokens: state.reasoningTokens,\n cacheReadInputTokens: state.cacheReadTokens,\n cacheCreationInputTokens: state.cacheCreationTokens,\n finishReason: state.finishReason,\n toolCalls: state.toolCalls.length > 0 ? state.toolCalls : null,\n providerTtfbMs: state.ttfbMs,\n isStreaming: true,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bedrock.d.ts","names":[],"sources":["../../src/providers/bedrock.ts"],"sourcesContent":[],"mappings":";;;;;;AA2Ba,cAbA,iBAaQ,EAAA,OAAA;cAZf,cAgBiB,EAhBD,MAgBC,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;AAY4B,UAxBlC,cAAA,CAwBkC;
|
|
1
|
+
{"version":3,"file":"bedrock.d.ts","names":[],"sources":["../../src/providers/bedrock.ts"],"sourcesContent":[],"mappings":";;;;;;AA2Ba,cAbA,iBAaQ,EAAA,OAAA;cAZf,cAgBiB,EAhBD,MAgBC,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA;AAY4B,UAxBlC,cAAA,CAwBkC;EA+EpB,SAAA,EAtGlB,aAsGkB;EAA0B,MAAA,EAAA,OAAA;EA/F5B,aAAA,CAAA,EALX,aAKW,GAAA,IAAA;EAAc;EAiQ3B,aAAA,CAAA,EAAA,OAAA;;cAjQH,OAAA,SAAgB,cAAA;;;uBAIN;mBAYE,0BAA0B;yBA+EpB,0BAA0B;;;;iBAkKzC,sBAAA;;;;;;;;aAQH,MAAM"}
|