@juspay/neurolink 8.26.0 → 8.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +47 -25
  3. package/dist/adapters/providerImageAdapter.js +11 -0
  4. package/dist/cli/commands/config.js +16 -23
  5. package/dist/cli/commands/setup-anthropic.js +3 -26
  6. package/dist/cli/commands/setup-azure.js +3 -22
  7. package/dist/cli/commands/setup-bedrock.js +3 -26
  8. package/dist/cli/commands/setup-google-ai.js +3 -22
  9. package/dist/cli/commands/setup-mistral.js +3 -31
  10. package/dist/cli/commands/setup-openai.js +3 -22
  11. package/dist/cli/factories/commandFactory.js +32 -0
  12. package/dist/cli/factories/ollamaCommandFactory.js +5 -17
  13. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  14. package/dist/cli/loop/optionsSchema.js +13 -0
  15. package/dist/config/modelSpecificPrompts.d.ts +9 -0
  16. package/dist/config/modelSpecificPrompts.js +38 -0
  17. package/dist/constants/enums.d.ts +8 -0
  18. package/dist/constants/enums.js +8 -0
  19. package/dist/constants/tokens.d.ts +25 -0
  20. package/dist/constants/tokens.js +18 -0
  21. package/dist/core/analytics.js +7 -28
  22. package/dist/core/baseProvider.js +1 -0
  23. package/dist/core/constants.d.ts +1 -0
  24. package/dist/core/constants.js +1 -0
  25. package/dist/core/modules/GenerationHandler.js +43 -5
  26. package/dist/core/streamAnalytics.d.ts +1 -0
  27. package/dist/core/streamAnalytics.js +8 -16
  28. package/dist/lib/adapters/providerImageAdapter.js +11 -0
  29. package/dist/lib/config/modelSpecificPrompts.d.ts +9 -0
  30. package/dist/lib/config/modelSpecificPrompts.js +39 -0
  31. package/dist/lib/constants/enums.d.ts +8 -0
  32. package/dist/lib/constants/enums.js +8 -0
  33. package/dist/lib/constants/tokens.d.ts +25 -0
  34. package/dist/lib/constants/tokens.js +18 -0
  35. package/dist/lib/core/analytics.js +7 -28
  36. package/dist/lib/core/baseProvider.js +1 -0
  37. package/dist/lib/core/constants.d.ts +1 -0
  38. package/dist/lib/core/constants.js +1 -0
  39. package/dist/lib/core/modules/GenerationHandler.js +43 -5
  40. package/dist/lib/core/streamAnalytics.d.ts +1 -0
  41. package/dist/lib/core/streamAnalytics.js +8 -16
  42. package/dist/lib/providers/googleAiStudio.d.ts +15 -0
  43. package/dist/lib/providers/googleAiStudio.js +659 -3
  44. package/dist/lib/providers/googleVertex.d.ts +25 -0
  45. package/dist/lib/providers/googleVertex.js +978 -3
  46. package/dist/lib/types/analytics.d.ts +4 -0
  47. package/dist/lib/types/cli.d.ts +16 -0
  48. package/dist/lib/types/conversation.d.ts +72 -4
  49. package/dist/lib/types/conversation.js +30 -0
  50. package/dist/lib/types/generateTypes.d.ts +135 -0
  51. package/dist/lib/types/groundingTypes.d.ts +231 -0
  52. package/dist/lib/types/groundingTypes.js +12 -0
  53. package/dist/lib/types/providers.d.ts +29 -0
  54. package/dist/lib/types/streamTypes.d.ts +54 -0
  55. package/dist/lib/utils/analyticsUtils.js +22 -2
  56. package/dist/lib/utils/modelChoices.d.ts +82 -0
  57. package/dist/lib/utils/modelChoices.js +402 -0
  58. package/dist/lib/utils/modelDetection.d.ts +9 -0
  59. package/dist/lib/utils/modelDetection.js +81 -0
  60. package/dist/lib/utils/schemaConversion.d.ts +12 -0
  61. package/dist/lib/utils/schemaConversion.js +90 -0
  62. package/dist/lib/utils/thinkingConfig.d.ts +108 -0
  63. package/dist/lib/utils/thinkingConfig.js +105 -0
  64. package/dist/lib/utils/tokenUtils.d.ts +124 -0
  65. package/dist/lib/utils/tokenUtils.js +240 -0
  66. package/dist/lib/utils/transformationUtils.js +15 -26
  67. package/dist/providers/googleAiStudio.d.ts +15 -0
  68. package/dist/providers/googleAiStudio.js +659 -3
  69. package/dist/providers/googleVertex.d.ts +25 -0
  70. package/dist/providers/googleVertex.js +978 -3
  71. package/dist/types/analytics.d.ts +4 -0
  72. package/dist/types/cli.d.ts +16 -0
  73. package/dist/types/conversation.d.ts +72 -4
  74. package/dist/types/conversation.js +30 -0
  75. package/dist/types/generateTypes.d.ts +135 -0
  76. package/dist/types/groundingTypes.d.ts +231 -0
  77. package/dist/types/groundingTypes.js +11 -0
  78. package/dist/types/providers.d.ts +29 -0
  79. package/dist/types/streamTypes.d.ts +54 -0
  80. package/dist/utils/analyticsUtils.js +22 -2
  81. package/dist/utils/modelChoices.d.ts +82 -0
  82. package/dist/utils/modelChoices.js +401 -0
  83. package/dist/utils/modelDetection.d.ts +9 -0
  84. package/dist/utils/modelDetection.js +80 -0
  85. package/dist/utils/schemaConversion.d.ts +12 -0
  86. package/dist/utils/schemaConversion.js +90 -0
  87. package/dist/utils/thinkingConfig.d.ts +108 -0
  88. package/dist/utils/thinkingConfig.js +104 -0
  89. package/dist/utils/tokenUtils.d.ts +124 -0
  90. package/dist/utils/tokenUtils.js +239 -0
  91. package/dist/utils/transformationUtils.js +15 -26
  92. package/package.json +4 -3
@@ -2,6 +2,96 @@ import { zodToJsonSchema } from "zod-to-json-schema";
2
2
  import { jsonSchemaToZod } from "json-schema-to-zod";
3
3
  import { z } from "zod";
4
4
  import { logger } from "./logger.js";
5
+ /**
6
+ * Inline a JSON Schema by recursively resolving all $ref references.
7
+ * zodToJsonSchema with 'name' option produces schemas with $ref pointing to definitions.
8
+ * Some SDKs (like @google/genai) expect flat schemas without $ref.
9
+ *
10
+ * This function handles:
11
+ * - Top-level $ref resolution
12
+ * - Nested $ref within properties, items, additionalProperties
13
+ * - $ref within allOf, anyOf, oneOf arrays
14
+ * - Circular reference detection to prevent infinite loops
15
+ */
16
+ export function inlineJsonSchema(schema, definitions, visited = new Set()) {
17
+ // Use definitions from schema if not provided
18
+ const defs = definitions ||
19
+ schema.definitions;
20
+ // Handle $ref at current level
21
+ if (typeof schema.$ref === "string" &&
22
+ schema.$ref.startsWith("#/definitions/")) {
23
+ const defName = schema.$ref.replace("#/definitions/", "");
24
+ // Prevent circular reference infinite loops
25
+ if (visited.has(defName)) {
26
+ logger.debug(`[SCHEMA-INLINE] Circular reference detected for: ${defName}`);
27
+ // Return a simple object placeholder for circular refs
28
+ return { type: "object" };
29
+ }
30
+ if (defs && defs[defName]) {
31
+ visited.add(defName);
32
+ // Recursively inline the resolved definition
33
+ const resolved = inlineJsonSchema({ ...defs[defName] }, defs, visited);
34
+ visited.delete(defName);
35
+ return resolved;
36
+ }
37
+ }
38
+ // Create result without $ref and definitions
39
+ const result = {};
40
+ for (const [key, value] of Object.entries(schema)) {
41
+ // Skip $ref and definitions keys
42
+ if (key === "$ref" || key === "definitions") {
43
+ continue;
44
+ }
45
+ // Recursively process nested schemas
46
+ if (key === "properties" && value && typeof value === "object") {
47
+ const properties = {};
48
+ for (const [propName, propSchema] of Object.entries(value)) {
49
+ if (propSchema && typeof propSchema === "object") {
50
+ properties[propName] = inlineJsonSchema(propSchema, defs, visited);
51
+ }
52
+ else {
53
+ properties[propName] = propSchema;
54
+ }
55
+ }
56
+ result[key] = properties;
57
+ }
58
+ else if (key === "items" && value && typeof value === "object") {
59
+ // Handle array items schema
60
+ if (Array.isArray(value)) {
61
+ result[key] = value.map((item) => item && typeof item === "object"
62
+ ? inlineJsonSchema(item, defs, visited)
63
+ : item);
64
+ }
65
+ else {
66
+ result[key] = inlineJsonSchema(value, defs, visited);
67
+ }
68
+ }
69
+ else if (key === "additionalProperties" &&
70
+ value &&
71
+ typeof value === "object") {
72
+ result[key] = inlineJsonSchema(value, defs, visited);
73
+ }
74
+ else if ((key === "allOf" || key === "anyOf" || key === "oneOf") &&
75
+ Array.isArray(value)) {
76
+ // Handle composition schemas
77
+ result[key] = value.map((item) => item && typeof item === "object"
78
+ ? inlineJsonSchema(item, defs, visited)
79
+ : item);
80
+ }
81
+ else if (key === "not" && value && typeof value === "object") {
82
+ result[key] = inlineJsonSchema(value, defs, visited);
83
+ }
84
+ else if ((key === "if" || key === "then" || key === "else") &&
85
+ value &&
86
+ typeof value === "object") {
87
+ result[key] = inlineJsonSchema(value, defs, visited);
88
+ }
89
+ else {
90
+ result[key] = value;
91
+ }
92
+ }
93
+ return result;
94
+ }
5
95
  /**
6
96
  * Convert Zod schema to JSON Schema format for Claude AI
7
97
  */
@@ -0,0 +1,108 @@
1
+ /**
2
+ * ThinkingConfig utility functions for constructing thinking configuration objects.
3
+ *
4
+ * This module provides helper functions to create thinkingConfig objects consistently
5
+ * across the codebase, reducing duplication in CLI and providers.
6
+ */
7
+ /**
8
+ * ThinkingLevel type for Gemini 3 models
9
+ */
10
+ export type ThinkingLevel = "minimal" | "low" | "medium" | "high";
11
+ /**
12
+ * ThinkingConfig interface matching the SDK's expected structure
13
+ */
14
+ export interface ThinkingConfig {
15
+ enabled?: boolean;
16
+ type?: "enabled" | "disabled";
17
+ /** Token budget for thinking (Anthropic models: 5000-100000) */
18
+ budgetTokens?: number;
19
+ /** Thinking level for Gemini 3 models */
20
+ thinkingLevel?: ThinkingLevel;
21
+ }
22
+ /**
23
+ * Options for creating a thinkingConfig from CLI-style options
24
+ */
25
+ export interface CreateThinkingConfigOptions {
26
+ /** Enable thinking mode */
27
+ thinking?: boolean;
28
+ /** Token budget for thinking (defaults to 10000) */
29
+ thinkingBudget?: number;
30
+ /** Thinking level for Gemini 3 models */
31
+ thinkingLevel?: ThinkingLevel;
32
+ }
33
+ /**
34
+ * Native SDK thinkingConfig structure for Gemini native SDK.
35
+ */
36
+ export interface NativeThinkingConfig {
37
+ includeThoughts: boolean;
38
+ thinkingLevel: ThinkingLevel;
39
+ }
40
+ /**
41
+ * Default token budget for thinking operations
42
+ */
43
+ export declare const DEFAULT_THINKING_BUDGET_TOKENS = 10000;
44
+ /**
45
+ * Default thinking level for Gemini 3 models
46
+ */
47
+ export declare const DEFAULT_THINKING_LEVEL: ThinkingLevel;
48
+ /**
49
+ * Creates a thinkingConfig object from CLI-style options.
50
+ *
51
+ * This helper consolidates the pattern used in CLI command handlers
52
+ * to convert simple CLI flags into the full thinkingConfig structure.
53
+ *
54
+ * @param options - CLI-style options with thinking, thinkingBudget, thinkingLevel
55
+ * @returns ThinkingConfig object or undefined if thinking is not enabled
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // From CLI options
60
+ * const config = createThinkingConfig({
61
+ * thinking: true,
62
+ * thinkingBudget: 15000,
63
+ * thinkingLevel: "high"
64
+ * });
65
+ * // Returns: { enabled: true, budgetTokens: 15000, thinkingLevel: "high" }
66
+ * ```
67
+ */
68
+ export declare function createThinkingConfig(options: CreateThinkingConfigOptions): ThinkingConfig | undefined;
69
+ /**
70
+ * Creates a thinkingConfig from record-style options (useful for CLI handlers).
71
+ *
72
+ * This handles the type casting that's commonly needed when working with
73
+ * CLI argument records.
74
+ *
75
+ * @param options - Record-style options from CLI argv
76
+ * @returns ThinkingConfig object or undefined if thinking is not enabled
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const config = createThinkingConfigFromRecord(argv as Record<string, unknown>);
81
+ * ```
82
+ */
83
+ export declare function createThinkingConfigFromRecord(options: Record<string, unknown>): ThinkingConfig | undefined;
84
+ /**
85
+ * Creates thinkingConfig for native Gemini SDK (not AI SDK).
86
+ *
87
+ * This is used for direct calls to the Gemini SDK where the config
88
+ * structure is different from the AI SDK providerOptions.
89
+ *
90
+ * @param config - The thinkingConfig from options
91
+ * @returns NativeThinkingConfig object or undefined
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig);
96
+ * if (nativeConfig) {
97
+ * sdkConfig.thinkingConfig = nativeConfig;
98
+ * }
99
+ * ```
100
+ */
101
+ export declare function createNativeThinkingConfig(config: ThinkingConfig | undefined): NativeThinkingConfig | undefined;
102
+ /**
103
+ * Checks if thinkingConfig should be applied based on options.
104
+ *
105
+ * @param config - The thinkingConfig from options
106
+ * @returns true if thinking should be enabled
107
+ */
108
+ export declare function shouldEnableThinking(config: ThinkingConfig | undefined): boolean;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ThinkingConfig utility functions for constructing thinking configuration objects.
3
+ *
4
+ * This module provides helper functions to create thinkingConfig objects consistently
5
+ * across the codebase, reducing duplication in CLI and providers.
6
+ */
7
+ /**
8
+ * Default token budget for thinking operations
9
+ */
10
+ export const DEFAULT_THINKING_BUDGET_TOKENS = 10000;
11
+ /**
12
+ * Default thinking level for Gemini 3 models
13
+ */
14
+ export const DEFAULT_THINKING_LEVEL = "high";
15
+ /**
16
+ * Creates a thinkingConfig object from CLI-style options.
17
+ *
18
+ * This helper consolidates the pattern used in CLI command handlers
19
+ * to convert simple CLI flags into the full thinkingConfig structure.
20
+ *
21
+ * @param options - CLI-style options with thinking, thinkingBudget, thinkingLevel
22
+ * @returns ThinkingConfig object or undefined if thinking is not enabled
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // From CLI options
27
+ * const config = createThinkingConfig({
28
+ * thinking: true,
29
+ * thinkingBudget: 15000,
30
+ * thinkingLevel: "high"
31
+ * });
32
+ * // Returns: { enabled: true, budgetTokens: 15000, thinkingLevel: "high" }
33
+ * ```
34
+ */
35
+ export function createThinkingConfig(options) {
36
+ // Only create config if thinking is explicitly enabled or thinkingLevel is set
37
+ if (!options.thinking && !options.thinkingLevel) {
38
+ return undefined;
39
+ }
40
+ return {
41
+ enabled: true,
42
+ budgetTokens: options.thinkingBudget ?? DEFAULT_THINKING_BUDGET_TOKENS,
43
+ thinkingLevel: options.thinkingLevel,
44
+ };
45
+ }
46
+ /**
47
+ * Creates a thinkingConfig from record-style options (useful for CLI handlers).
48
+ *
49
+ * This handles the type casting that's commonly needed when working with
50
+ * CLI argument records.
51
+ *
52
+ * @param options - Record-style options from CLI argv
53
+ * @returns ThinkingConfig object or undefined if thinking is not enabled
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const config = createThinkingConfigFromRecord(argv as Record<string, unknown>);
58
+ * ```
59
+ */
60
+ export function createThinkingConfigFromRecord(options) {
61
+ const thinking = options.thinking;
62
+ const thinkingLevel = options.thinkingLevel;
63
+ const thinkingBudget = options.thinkingBudget;
64
+ return createThinkingConfig({
65
+ thinking,
66
+ thinkingLevel,
67
+ thinkingBudget,
68
+ });
69
+ }
70
+ /**
71
+ * Creates thinkingConfig for native Gemini SDK (not AI SDK).
72
+ *
73
+ * This is used for direct calls to the Gemini SDK where the config
74
+ * structure is different from the AI SDK providerOptions.
75
+ *
76
+ * @param config - The thinkingConfig from options
77
+ * @returns NativeThinkingConfig object or undefined
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const nativeConfig = createNativeThinkingConfig(options.thinkingConfig);
82
+ * if (nativeConfig) {
83
+ * sdkConfig.thinkingConfig = nativeConfig;
84
+ * }
85
+ * ```
86
+ */
87
+ export function createNativeThinkingConfig(config) {
88
+ if (!config?.enabled && !config?.thinkingLevel) {
89
+ return undefined;
90
+ }
91
+ return {
92
+ includeThoughts: true,
93
+ thinkingLevel: config.thinkingLevel ?? DEFAULT_THINKING_LEVEL,
94
+ };
95
+ }
96
+ /**
97
+ * Checks if thinkingConfig should be applied based on options.
98
+ *
99
+ * @param config - The thinkingConfig from options
100
+ * @returns true if thinking should be enabled
101
+ */
102
+ export function shouldEnableThinking(config) {
103
+ return Boolean(config?.enabled || config?.thinkingLevel);
104
+ }
105
+ //# sourceMappingURL=thinkingConfig.js.map
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Centralized token usage extraction utilities
3
+ * Handles multiple provider formats and optional fields
4
+ *
5
+ * Consolidates token extraction logic from:
6
+ * - GenerationHandler.ts
7
+ * - analytics.ts
8
+ * - streamAnalytics.ts
9
+ */
10
+ import type { TokenUsage } from "../types/analytics.js";
11
+ /**
12
+ * Raw usage object that may come from various AI providers
13
+ * Supports multiple naming conventions and nested structures
14
+ */
15
+ export interface RawUsageObject {
16
+ input?: number;
17
+ output?: number;
18
+ total?: number;
19
+ inputTokens?: number;
20
+ outputTokens?: number;
21
+ totalTokens?: number;
22
+ promptTokens?: number;
23
+ completionTokens?: number;
24
+ cacheCreationInputTokens?: number;
25
+ cacheReadInputTokens?: number;
26
+ cacheCreationTokens?: number;
27
+ cacheReadTokens?: number;
28
+ reasoningTokens?: number;
29
+ reasoning?: number;
30
+ reasoning_tokens?: number;
31
+ thinkingTokens?: number;
32
+ usage?: RawUsageObject;
33
+ }
34
+ /**
35
+ * Options for token extraction behavior
36
+ */
37
+ export interface TokenExtractionOptions {
38
+ /**
39
+ * Whether to calculate cache savings percentage
40
+ * @default true
41
+ */
42
+ calculateCacheSavings?: boolean;
43
+ /**
44
+ * How to handle missing optional fields
45
+ * - "zero": Return 0 for missing optional fields
46
+ * - "undefined": Return undefined for missing optional fields (default)
47
+ */
48
+ missingOptionalBehavior?: "zero" | "undefined";
49
+ }
50
+ /**
51
+ * Extract input token count from various provider formats
52
+ * Priority: input > inputTokens > promptTokens
53
+ */
54
+ export declare function extractInputTokens(usage: RawUsageObject): number;
55
+ /**
56
+ * Extract output token count from various provider formats
57
+ * Priority: output > outputTokens > completionTokens
58
+ */
59
+ export declare function extractOutputTokens(usage: RawUsageObject): number;
60
+ /**
61
+ * Extract total token count from various provider formats
62
+ * Falls back to input + output if total is not provided
63
+ */
64
+ export declare function extractTotalTokens(usage: RawUsageObject, input: number, output: number): number;
65
+ /**
66
+ * Extract reasoning/thinking token count from various provider formats
67
+ * Supports: reasoningTokens, thinkingTokens, reasoning_tokens, reasoning
68
+ */
69
+ export declare function extractReasoningTokens(usage: RawUsageObject): number | undefined;
70
+ /**
71
+ * Extract cache creation token count from various provider formats
72
+ * Supports: cacheCreationInputTokens, cacheCreationTokens
73
+ */
74
+ export declare function extractCacheCreationTokens(usage: RawUsageObject): number | undefined;
75
+ /**
76
+ * Extract cache read token count from various provider formats
77
+ * Supports: cacheReadInputTokens, cacheReadTokens
78
+ */
79
+ export declare function extractCacheReadTokens(usage: RawUsageObject): number | undefined;
80
+ /**
81
+ * Calculate cache savings percentage
82
+ *
83
+ * This represents the percentage of input tokens served from cache.
84
+ * For Anthropic, cache read tokens cost 0.1x, so actual cost savings = cacheSavingsPercent * 0.9
85
+ * For other providers, cost savings may vary based on their cache pricing.
86
+ *
87
+ * @param cacheReadTokens Number of tokens read from cache
88
+ * @param inputTokens Number of non-cached input tokens
89
+ * @returns Percentage of tokens served from cache (0-100), or undefined if no cache usage
90
+ */
91
+ export declare function calculateCacheSavingsPercent(cacheReadTokens: number | undefined, inputTokens: number): number | undefined;
92
+ /**
93
+ * Extract token usage from various provider response formats
94
+ *
95
+ * Handles multiple input formats:
96
+ * - BaseProvider normalized format (input/output/total)
97
+ * - AI SDK format (inputTokens/outputTokens/totalTokens)
98
+ * - OpenAI/Mistral format (promptTokens/completionTokens)
99
+ * - Nested usage objects
100
+ *
101
+ * Also extracts optional fields:
102
+ * - Cache creation and read tokens (Anthropic-style)
103
+ * - Reasoning/thinking tokens (OpenAI o1, Anthropic, Google)
104
+ * - Cache savings percentage
105
+ *
106
+ * @param result Raw usage object from provider response
107
+ * @param options Extraction options
108
+ * @returns Normalized TokenUsage object
109
+ */
110
+ export declare function extractTokenUsage(result: RawUsageObject | undefined | null, options?: TokenExtractionOptions): TokenUsage;
111
+ /**
112
+ * Create a default/empty TokenUsage object
113
+ * Useful for error handling and fallback scenarios
114
+ */
115
+ export declare function createEmptyTokenUsage(): TokenUsage;
116
+ /**
117
+ * Check if a TokenUsage object has any non-zero values
118
+ */
119
+ export declare function hasTokenUsage(usage: TokenUsage): boolean;
120
+ /**
121
+ * Merge two TokenUsage objects by summing their values
122
+ * Useful for aggregating usage across multiple calls
123
+ */
124
+ export declare function mergeTokenUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Centralized token usage extraction utilities
3
+ * Handles multiple provider formats and optional fields
4
+ *
5
+ * Consolidates token extraction logic from:
6
+ * - GenerationHandler.ts
7
+ * - analytics.ts
8
+ * - streamAnalytics.ts
9
+ */
10
+ /**
11
+ * Extract input token count from various provider formats
12
+ * Priority: input > inputTokens > promptTokens
13
+ */
14
+ export function extractInputTokens(usage) {
15
+ if (typeof usage.input === "number") {
16
+ return usage.input;
17
+ }
18
+ if (typeof usage.inputTokens === "number") {
19
+ return usage.inputTokens;
20
+ }
21
+ if (typeof usage.promptTokens === "number") {
22
+ return usage.promptTokens;
23
+ }
24
+ return 0;
25
+ }
26
+ /**
27
+ * Extract output token count from various provider formats
28
+ * Priority: output > outputTokens > completionTokens
29
+ */
30
+ export function extractOutputTokens(usage) {
31
+ if (typeof usage.output === "number") {
32
+ return usage.output;
33
+ }
34
+ if (typeof usage.outputTokens === "number") {
35
+ return usage.outputTokens;
36
+ }
37
+ if (typeof usage.completionTokens === "number") {
38
+ return usage.completionTokens;
39
+ }
40
+ return 0;
41
+ }
42
+ /**
43
+ * Extract total token count from various provider formats
44
+ * Falls back to input + output if total is not provided
45
+ */
46
+ export function extractTotalTokens(usage, input, output) {
47
+ if (typeof usage.total === "number") {
48
+ return usage.total;
49
+ }
50
+ if (typeof usage.totalTokens === "number") {
51
+ return usage.totalTokens;
52
+ }
53
+ return input + output;
54
+ }
55
+ /**
56
+ * Extract reasoning/thinking token count from various provider formats
57
+ * Supports: reasoningTokens, thinkingTokens, reasoning_tokens, reasoning
58
+ */
59
+ export function extractReasoningTokens(usage) {
60
+ if (typeof usage.reasoningTokens === "number" && usage.reasoningTokens > 0) {
61
+ return usage.reasoningTokens;
62
+ }
63
+ if (typeof usage.thinkingTokens === "number" && usage.thinkingTokens > 0) {
64
+ return usage.thinkingTokens;
65
+ }
66
+ if (typeof usage.reasoning_tokens === "number" &&
67
+ usage.reasoning_tokens > 0) {
68
+ return usage.reasoning_tokens;
69
+ }
70
+ if (typeof usage.reasoning === "number" && usage.reasoning > 0) {
71
+ return usage.reasoning;
72
+ }
73
+ return undefined;
74
+ }
75
+ /**
76
+ * Extract cache creation token count from various provider formats
77
+ * Supports: cacheCreationInputTokens, cacheCreationTokens
78
+ */
79
+ export function extractCacheCreationTokens(usage) {
80
+ if (typeof usage.cacheCreationInputTokens === "number" &&
81
+ usage.cacheCreationInputTokens > 0) {
82
+ return usage.cacheCreationInputTokens;
83
+ }
84
+ if (typeof usage.cacheCreationTokens === "number" &&
85
+ usage.cacheCreationTokens > 0) {
86
+ return usage.cacheCreationTokens;
87
+ }
88
+ return undefined;
89
+ }
90
+ /**
91
+ * Extract cache read token count from various provider formats
92
+ * Supports: cacheReadInputTokens, cacheReadTokens
93
+ */
94
+ export function extractCacheReadTokens(usage) {
95
+ if (typeof usage.cacheReadInputTokens === "number" &&
96
+ usage.cacheReadInputTokens > 0) {
97
+ return usage.cacheReadInputTokens;
98
+ }
99
+ if (typeof usage.cacheReadTokens === "number" && usage.cacheReadTokens > 0) {
100
+ return usage.cacheReadTokens;
101
+ }
102
+ return undefined;
103
+ }
104
+ /**
105
+ * Calculate cache savings percentage
106
+ *
107
+ * This represents the percentage of input tokens served from cache.
108
+ * For Anthropic, cache read tokens cost 0.1x, so actual cost savings = cacheSavingsPercent * 0.9
109
+ * For other providers, cost savings may vary based on their cache pricing.
110
+ *
111
+ * @param cacheReadTokens Number of tokens read from cache
112
+ * @param inputTokens Number of non-cached input tokens
113
+ * @returns Percentage of tokens served from cache (0-100), or undefined if no cache usage
114
+ */
115
+ export function calculateCacheSavingsPercent(cacheReadTokens, inputTokens) {
116
+ if (cacheReadTokens === undefined || cacheReadTokens <= 0) {
117
+ return undefined;
118
+ }
119
+ const totalInputWithCache = inputTokens + cacheReadTokens;
120
+ if (totalInputWithCache <= 0) {
121
+ return undefined;
122
+ }
123
+ return Math.round((cacheReadTokens / totalInputWithCache) * 100);
124
+ }
125
+ /**
126
+ * Extract token usage from various provider response formats
127
+ *
128
+ * Handles multiple input formats:
129
+ * - BaseProvider normalized format (input/output/total)
130
+ * - AI SDK format (inputTokens/outputTokens/totalTokens)
131
+ * - OpenAI/Mistral format (promptTokens/completionTokens)
132
+ * - Nested usage objects
133
+ *
134
+ * Also extracts optional fields:
135
+ * - Cache creation and read tokens (Anthropic-style)
136
+ * - Reasoning/thinking tokens (OpenAI o1, Anthropic, Google)
137
+ * - Cache savings percentage
138
+ *
139
+ * @param result Raw usage object from provider response
140
+ * @param options Extraction options
141
+ * @returns Normalized TokenUsage object
142
+ */
143
+ export function extractTokenUsage(result, options = {}) {
144
+ const { calculateCacheSavings = true, missingOptionalBehavior = "undefined", } = options;
145
+ // Handle null/undefined input
146
+ if (!result) {
147
+ return { input: 0, output: 0, total: 0 };
148
+ }
149
+ // Handle nested usage object (some providers wrap usage in a usage property)
150
+ const usage = result.usage && typeof result.usage === "object" ? result.usage : result;
151
+ // Extract base token counts
152
+ const input = extractInputTokens(usage);
153
+ const output = extractOutputTokens(usage);
154
+ const total = extractTotalTokens(usage, input, output);
155
+ // Extract optional token fields
156
+ const reasoning = extractReasoningTokens(usage);
157
+ const cacheCreationTokens = extractCacheCreationTokens(usage);
158
+ const cacheReadTokens = extractCacheReadTokens(usage);
159
+ // Calculate cache savings if enabled
160
+ const cacheSavingsPercent = calculateCacheSavings
161
+ ? calculateCacheSavingsPercent(cacheReadTokens, input)
162
+ : undefined;
163
+ // Build result object
164
+ const tokenUsage = {
165
+ input,
166
+ output,
167
+ total,
168
+ };
169
+ // Add optional fields based on behavior setting
170
+ if (missingOptionalBehavior === "zero") {
171
+ tokenUsage.cacheCreationTokens = cacheCreationTokens ?? 0;
172
+ tokenUsage.cacheReadTokens = cacheReadTokens ?? 0;
173
+ tokenUsage.reasoning = reasoning ?? 0;
174
+ tokenUsage.cacheSavingsPercent = cacheSavingsPercent ?? 0;
175
+ }
176
+ else {
177
+ // Only include optional fields if they have values
178
+ if (cacheCreationTokens !== undefined) {
179
+ tokenUsage.cacheCreationTokens = cacheCreationTokens;
180
+ }
181
+ if (cacheReadTokens !== undefined) {
182
+ tokenUsage.cacheReadTokens = cacheReadTokens;
183
+ }
184
+ if (reasoning !== undefined) {
185
+ tokenUsage.reasoning = reasoning;
186
+ }
187
+ if (cacheSavingsPercent !== undefined) {
188
+ tokenUsage.cacheSavingsPercent = cacheSavingsPercent;
189
+ }
190
+ }
191
+ return tokenUsage;
192
+ }
193
+ /**
194
+ * Create a default/empty TokenUsage object
195
+ * Useful for error handling and fallback scenarios
196
+ */
197
+ export function createEmptyTokenUsage() {
198
+ return {
199
+ input: 0,
200
+ output: 0,
201
+ total: 0,
202
+ };
203
+ }
204
+ /**
205
+ * Check if a TokenUsage object has any non-zero values
206
+ */
207
+ export function hasTokenUsage(usage) {
208
+ return usage.input > 0 || usage.output > 0 || usage.total > 0;
209
+ }
210
+ /**
211
+ * Merge two TokenUsage objects by summing their values
212
+ * Useful for aggregating usage across multiple calls
213
+ */
214
+ export function mergeTokenUsage(a, b) {
215
+ const merged = {
216
+ input: a.input + b.input,
217
+ output: a.output + b.output,
218
+ total: a.total + b.total,
219
+ };
220
+ // Merge optional fields if present in either
221
+ const cacheCreationTokens = (a.cacheCreationTokens ?? 0) + (b.cacheCreationTokens ?? 0);
222
+ const cacheReadTokens = (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0);
223
+ const reasoning = (a.reasoning ?? 0) + (b.reasoning ?? 0);
224
+ if (cacheCreationTokens > 0) {
225
+ merged.cacheCreationTokens = cacheCreationTokens;
226
+ }
227
+ if (cacheReadTokens > 0) {
228
+ merged.cacheReadTokens = cacheReadTokens;
229
+ }
230
+ if (reasoning > 0) {
231
+ merged.reasoning = reasoning;
232
+ }
233
+ // Recalculate cache savings for merged usage
234
+ const cacheSavingsPercent = calculateCacheSavingsPercent(merged.cacheReadTokens, merged.input);
235
+ if (cacheSavingsPercent !== undefined) {
236
+ merged.cacheSavingsPercent = cacheSavingsPercent;
237
+ }
238
+ return merged;
239
+ }
240
+ //# sourceMappingURL=tokenUtils.js.map