@revenium/anthropic 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultLogger = void 0;
4
+ exports.validateConfig = validateConfig;
5
+ exports.getConfig = getConfig;
6
+ exports.setConfig = setConfig;
7
+ exports.getLogger = getLogger;
8
+ exports.setLogger = setLogger;
9
+ exports.initializeConfig = initializeConfig;
10
+ exports.getConfigStatus = getConfigStatus;
11
+ exports.validateCurrentConfig = validateCurrentConfig;
12
+ const validation_1 = require("./utils/validation");
13
+ const constants_1 = require("./constants");
14
+ /**
15
+ * Simple console logger implementation for Anthropic middleware
16
+ */
17
+ class ConsoleLogger {
18
+ isDebugEnabled() {
19
+ return process.env[constants_1.ENV_VARS.DEBUG] === 'true';
20
+ }
21
+ formatMessage(level, message, context) {
22
+ const timestamp = new Date().toISOString();
23
+ const prefix = `[${constants_1.LOGGING_CONFIG.MIDDLEWARE_NAME}${level === 'DEBUG' ? ' Debug' : ''}]`;
24
+ const contextStr = context ? ` ${JSON.stringify(context)}` : '';
25
+ return `${timestamp} ${prefix} ${message}${contextStr}`;
26
+ }
27
+ debug(message, context) {
28
+ if (this.isDebugEnabled()) {
29
+ console.debug(this.formatMessage('DEBUG', message, context));
30
+ }
31
+ }
32
+ info(message, context) {
33
+ console.info(this.formatMessage('INFO', message, context));
34
+ }
35
+ warn(message, context) {
36
+ console.warn(this.formatMessage('WARN', message, context));
37
+ }
38
+ error(message, context) {
39
+ console.error(this.formatMessage('ERROR', message, context));
40
+ }
41
+ }
42
+ /**
43
+ * Default console logger implementation
44
+ */
45
+ exports.defaultLogger = new ConsoleLogger();
46
+ /**
47
+ * Load configuration from environment variables
48
+ */
49
+ function loadConfigFromEnvironment() {
50
+ const env = {
51
+ reveniumApiKey: process.env[constants_1.ENV_VARS.REVENIUM_API_KEY],
52
+ reveniumBaseUrl: process.env[constants_1.ENV_VARS.REVENIUM_BASE_URL],
53
+ anthropicApiKey: process.env[constants_1.ENV_VARS.ANTHROPIC_API_KEY],
54
+ debug: process.env[constants_1.ENV_VARS.DEBUG] === 'true',
55
+ logLevel: process.env[constants_1.ENV_VARS.LOG_LEVEL],
56
+ apiTimeout: process.env[constants_1.ENV_VARS.API_TIMEOUT],
57
+ failSilent: process.env[constants_1.ENV_VARS.FAIL_SILENT],
58
+ maxRetries: process.env[constants_1.ENV_VARS.MAX_RETRIES]
59
+ };
60
+ return env;
61
+ }
62
+ /**
63
+ * Convert environment config to Revenium config
64
+ */
65
+ function createConfigFromEnvironment(env) {
66
+ if (!env.reveniumApiKey) {
67
+ return null;
68
+ }
69
+ const apiTimeout = env.apiTimeout ? parseInt(env.apiTimeout, 10) : undefined;
70
+ const failSilent = env.failSilent !== 'false'; // Default to true
71
+ const maxRetries = env.maxRetries ? parseInt(env.maxRetries, 10) : undefined;
72
+ return {
73
+ reveniumApiKey: env.reveniumApiKey,
74
+ reveniumBaseUrl: env.reveniumBaseUrl || constants_1.DEFAULT_CONFIG.REVENIUM_BASE_URL,
75
+ anthropicApiKey: env.anthropicApiKey,
76
+ apiTimeout,
77
+ failSilent,
78
+ maxRetries
79
+ };
80
+ }
81
+ /**
82
+ * Validate Revenium configuration with enhanced error reporting
83
+ */
84
+ function validateConfig(config) {
85
+ const validation = (0, validation_1.validateReveniumConfig)(config);
86
+ if (!validation.isValid) {
87
+ // Log detailed validation errors
88
+ getLogger().error('Configuration validation failed', {
89
+ errors: validation.errors,
90
+ warnings: validation.warnings,
91
+ suggestions: validation.suggestions
92
+ });
93
+ // Create detailed error message
94
+ let errorMessage = 'Configuration validation failed:\n';
95
+ validation.errors.forEach((error, index) => {
96
+ errorMessage += ` ${index + 1}. ${error}\n`;
97
+ });
98
+ if (validation.suggestions && validation.suggestions.length > 0) {
99
+ errorMessage += '\nSuggestions:\n';
100
+ validation.suggestions.forEach((suggestion) => {
101
+ errorMessage += ` • ${suggestion}\n`;
102
+ });
103
+ }
104
+ throw new Error(errorMessage.trim());
105
+ }
106
+ // Log warnings if any
107
+ if (validation.warnings && validation.warnings.length > 0) {
108
+ getLogger().warn('Configuration warnings', {
109
+ warnings: validation.warnings
110
+ });
111
+ }
112
+ }
113
+ /**
114
+ * Global configuration instance
115
+ */
116
+ let globalConfig = null;
117
+ let globalLogger = exports.defaultLogger;
118
+ /**
119
+ * Get the current global configuration
120
+ */
121
+ function getConfig() {
122
+ return globalConfig;
123
+ }
124
+ /**
125
+ * Set the global configuration
126
+ */
127
+ function setConfig(config) {
128
+ validateConfig(config);
129
+ globalConfig = config;
130
+ globalLogger.debug('Revenium configuration updated', {
131
+ baseUrl: config.reveniumBaseUrl,
132
+ hasApiKey: !!config.reveniumApiKey,
133
+ hasAnthropicKey: !!config.anthropicApiKey
134
+ });
135
+ }
136
+ /**
137
+ * Get the current logger
138
+ */
139
+ function getLogger() {
140
+ return globalLogger;
141
+ }
142
+ /**
143
+ * Set a custom logger
144
+ */
145
+ function setLogger(logger) {
146
+ globalLogger = logger;
147
+ globalLogger.debug('Custom logger set for Revenium middleware');
148
+ }
149
+ /**
150
+ * Initialize configuration from environment variables
151
+ */
152
+ function initializeConfig() {
153
+ const env = loadConfigFromEnvironment();
154
+ const config = createConfigFromEnvironment(env);
155
+ if (config) {
156
+ try {
157
+ setConfig(config);
158
+ globalLogger.debug('Revenium middleware initialized from environment variables');
159
+ return true;
160
+ }
161
+ catch (error) {
162
+ globalLogger.error('Failed to initialize Revenium configuration', {
163
+ error: error instanceof Error ? error.message : String(error)
164
+ });
165
+ return false;
166
+ }
167
+ }
168
+ // Log what's missing for easier debugging
169
+ if (!env.reveniumApiKey) {
170
+ globalLogger.warn(`Revenium middleware not initialized. Missing ${constants_1.ENV_VARS.REVENIUM_API_KEY} environment variable`);
171
+ globalLogger.info(`Set ${constants_1.ENV_VARS.REVENIUM_API_KEY} to enable automatic tracking`);
172
+ }
173
+ return false;
174
+ }
175
+ /**
176
+ * Get configuration status
177
+ */
178
+ function getConfigStatus() {
179
+ if (!globalConfig) {
180
+ return {
181
+ hasConfig: false,
182
+ hasApiKey: false,
183
+ hasAnthropicKey: false,
184
+ baseUrl: ''
185
+ };
186
+ }
187
+ return {
188
+ hasConfig: true,
189
+ hasApiKey: !!globalConfig.reveniumApiKey,
190
+ hasAnthropicKey: !!globalConfig.anthropicApiKey,
191
+ baseUrl: globalConfig.reveniumBaseUrl
192
+ };
193
+ }
194
+ /**
195
+ * Validate current configuration
196
+ */
197
+ function validateCurrentConfig() {
198
+ if (!globalConfig)
199
+ return false;
200
+ try {
201
+ const validation = (0, validation_1.validateReveniumConfig)(globalConfig);
202
+ return validation.isValid;
203
+ }
204
+ catch {
205
+ return false;
206
+ }
207
+ }
208
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration constants for Revenium Anthropic middleware
4
+ * Centralizes all magic numbers and default values
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ANTHROPIC_PATTERNS = exports.API_ENDPOINTS = exports.ENV_VARS = exports.LOGGING_CONFIG = exports.VALIDATION_CONFIG = exports.RETRY_CONFIG = exports.CIRCUIT_BREAKER_CONFIG = exports.DEFAULT_CONFIG = void 0;
8
+ /**
9
+ * Default configuration values
10
+ */
11
+ exports.DEFAULT_CONFIG = {
12
+ /** Default Revenium API base URL */
13
+ REVENIUM_BASE_URL: 'https://api.revenium.io/meter',
14
+ /** Default API timeout in milliseconds */
15
+ API_TIMEOUT: 5000,
16
+ /** Default maximum retries for failed API calls */
17
+ MAX_RETRIES: 3,
18
+ /** Default fail silent behavior */
19
+ FAIL_SILENT: true,
20
+ /** Minimum allowed API timeout */
21
+ MIN_API_TIMEOUT: 1000,
22
+ /** Maximum allowed API timeout */
23
+ MAX_API_TIMEOUT: 60000,
24
+ /** Maximum allowed retry attempts */
25
+ MAX_RETRY_ATTEMPTS: 10,
26
+ /** Warning threshold for low API timeout */
27
+ LOW_TIMEOUT_WARNING_THRESHOLD: 3000,
28
+ };
29
+ /**
30
+ * Circuit breaker configuration constants
31
+ */
32
+ exports.CIRCUIT_BREAKER_CONFIG = {
33
+ /** Default number of failures before opening circuit */
34
+ FAILURE_THRESHOLD: 5,
35
+ /** Default recovery timeout in milliseconds (30 seconds) */
36
+ RECOVERY_TIMEOUT: 30000,
37
+ /** Default number of successful calls needed to close circuit */
38
+ SUCCESS_THRESHOLD: 3,
39
+ /** Default time window for counting failures (1 minute) */
40
+ TIME_WINDOW: 60000,
41
+ /** Maximum failure history size to prevent memory leaks */
42
+ MAX_FAILURE_HISTORY_SIZE: 1000,
43
+ /** Periodic cleanup interval (5 minutes) */
44
+ CLEANUP_INTERVAL: 300000,
45
+ /** Cleanup trigger threshold for failures array size */
46
+ CLEANUP_SIZE_THRESHOLD: 100,
47
+ };
48
+ /**
49
+ * Retry configuration constants
50
+ */
51
+ exports.RETRY_CONFIG = {
52
+ /** Base delay for exponential backoff in milliseconds */
53
+ BASE_DELAY: 1000,
54
+ /** Maximum delay for exponential backoff */
55
+ MAX_DELAY: 5000,
56
+ /** Jitter factor for randomizing delays */
57
+ JITTER_FACTOR: 0.1,
58
+ };
59
+ /**
60
+ * Validation constants
61
+ */
62
+ exports.VALIDATION_CONFIG = {
63
+ /** Minimum API key length */
64
+ MIN_API_KEY_LENGTH: 20,
65
+ /** Required API key prefix for Revenium */
66
+ REVENIUM_API_KEY_PREFIX: 'hak_',
67
+ /** Required API key prefix for Anthropic */
68
+ ANTHROPIC_API_KEY_PREFIX: 'sk-ant-',
69
+ /** Maximum tokens warning threshold */
70
+ HIGH_MAX_TOKENS_THRESHOLD: 4096,
71
+ /** Temperature range */
72
+ MIN_TEMPERATURE: 0,
73
+ MAX_TEMPERATURE: 1,
74
+ /** Response quality score range */
75
+ MIN_QUALITY_SCORE: 0,
76
+ MAX_QUALITY_SCORE: 1,
77
+ /** API timeout constraints */
78
+ MIN_API_TIMEOUT: 1000,
79
+ MAX_API_TIMEOUT: 60000,
80
+ LOW_TIMEOUT_WARNING_THRESHOLD: 3000,
81
+ /** Retry constraints */
82
+ MAX_RETRY_ATTEMPTS: 10,
83
+ };
84
+ /**
85
+ * Logging constants
86
+ */
87
+ exports.LOGGING_CONFIG = {
88
+ /** Middleware name for log prefixes */
89
+ MIDDLEWARE_NAME: 'Revenium',
90
+ /** User agent string for API requests */
91
+ USER_AGENT: 'revenium-middleware-anthropic-node/1.0.0',
92
+ /** Debug environment variable name */
93
+ DEBUG_ENV_VAR: 'REVENIUM_DEBUG',
94
+ };
95
+ /**
96
+ * Environment variable names
97
+ */
98
+ exports.ENV_VARS = {
99
+ /** Revenium API key */
100
+ REVENIUM_API_KEY: 'REVENIUM_METERING_API_KEY',
101
+ /** Revenium base URL */
102
+ REVENIUM_BASE_URL: 'REVENIUM_METERING_BASE_URL',
103
+ /** Anthropic API key */
104
+ ANTHROPIC_API_KEY: 'ANTHROPIC_API_KEY',
105
+ /** Debug mode */
106
+ DEBUG: 'REVENIUM_DEBUG',
107
+ /** Log level */
108
+ LOG_LEVEL: 'REVENIUM_LOG_LEVEL',
109
+ /** API timeout */
110
+ API_TIMEOUT: 'REVENIUM_API_TIMEOUT',
111
+ /** Fail silent mode */
112
+ FAIL_SILENT: 'REVENIUM_FAIL_SILENT',
113
+ /** Maximum retries */
114
+ MAX_RETRIES: 'REVENIUM_MAX_RETRIES',
115
+ };
116
+ /**
117
+ * API endpoints
118
+ */
119
+ exports.API_ENDPOINTS = {
120
+ /** Revenium AI completions endpoint */
121
+ AI_COMPLETIONS: '/v2/ai/completions',
122
+ };
123
+ /**
124
+ * Anthropic model patterns
125
+ */
126
+ exports.ANTHROPIC_PATTERNS = {
127
+ /** Pattern to identify Claude models */
128
+ CLAUDE_MODEL_PATTERN: /claude/i,
129
+ /** Known Anthropic stop reasons */
130
+ STOP_REASONS: {
131
+ END_TURN: 'end_turn',
132
+ MAX_TOKENS: 'max_tokens',
133
+ STOP_SEQUENCE: 'stop_sequence',
134
+ TOOL_USE: 'tool_use',
135
+ },
136
+ /** Revenium stop reason mappings */
137
+ REVENIUM_STOP_REASON_MAP: {
138
+ 'end_turn': 'END',
139
+ 'max_tokens': 'TOKEN_LIMIT',
140
+ 'stop_sequence': 'END_SEQUENCE',
141
+ 'tool_use': 'END',
142
+ },
143
+ };
144
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * Modern Revenium Anthropic Middleware
4
+ * Clean architecture without backward compatibility constraints
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.validateUsageMetadata = exports.validateAnthropicMessageParams = exports.validateReveniumConfig = exports.canExecuteRequest = exports.resetCircuitBreaker = exports.getCircuitBreakerStats = exports.extractUsageFromStream = exports.trackUsageAsync = exports.sendReveniumMetrics = exports.isAnthropicPatched = exports.unpatchAnthropic = exports.patchAnthropic = exports.validateCurrentConfig = exports.getConfigStatus = exports.getConfig = exports.getLogger = exports.setLogger = exports.setConfig = void 0;
8
+ exports.initialize = initialize;
9
+ exports.configure = configure;
10
+ exports.isInitialized = isInitialized;
11
+ exports.getStatus = getStatus;
12
+ exports.trackAnthropicCall = trackAnthropicCall;
13
+ exports.reset = reset;
14
+ // Import type augmentations to extend Anthropic types with usageMetadata
15
+ require("./types/anthropic-augmentation");
16
+ const config_1 = require("./config");
17
+ const wrapper_1 = require("./wrapper");
18
+ const tracking_1 = require("./tracking");
19
+ const circuit_breaker_1 = require("./utils/circuit-breaker");
20
+ // Export configuration functions
21
+ var config_2 = require("./config");
22
+ Object.defineProperty(exports, "setConfig", { enumerable: true, get: function () { return config_2.setConfig; } });
23
+ Object.defineProperty(exports, "setLogger", { enumerable: true, get: function () { return config_2.setLogger; } });
24
+ Object.defineProperty(exports, "getLogger", { enumerable: true, get: function () { return config_2.getLogger; } });
25
+ Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return config_2.getConfig; } });
26
+ Object.defineProperty(exports, "getConfigStatus", { enumerable: true, get: function () { return config_2.getConfigStatus; } });
27
+ Object.defineProperty(exports, "validateCurrentConfig", { enumerable: true, get: function () { return config_2.validateCurrentConfig; } });
28
+ // Export wrapper control functions
29
+ var wrapper_2 = require("./wrapper");
30
+ Object.defineProperty(exports, "patchAnthropic", { enumerable: true, get: function () { return wrapper_2.patchAnthropic; } });
31
+ Object.defineProperty(exports, "unpatchAnthropic", { enumerable: true, get: function () { return wrapper_2.unpatchAnthropic; } });
32
+ Object.defineProperty(exports, "isAnthropicPatched", { enumerable: true, get: function () { return wrapper_2.isAnthropicPatched; } });
33
+ // Export tracking functions
34
+ var tracking_2 = require("./tracking");
35
+ Object.defineProperty(exports, "sendReveniumMetrics", { enumerable: true, get: function () { return tracking_2.sendReveniumMetrics; } });
36
+ Object.defineProperty(exports, "trackUsageAsync", { enumerable: true, get: function () { return tracking_2.trackUsageAsync; } });
37
+ Object.defineProperty(exports, "extractUsageFromStream", { enumerable: true, get: function () { return tracking_2.extractUsageFromStream; } });
38
+ // Export utility functions
39
+ var circuit_breaker_2 = require("./utils/circuit-breaker");
40
+ Object.defineProperty(exports, "getCircuitBreakerStats", { enumerable: true, get: function () { return circuit_breaker_2.getCircuitBreakerStats; } });
41
+ Object.defineProperty(exports, "resetCircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_2.resetCircuitBreaker; } });
42
+ Object.defineProperty(exports, "canExecuteRequest", { enumerable: true, get: function () { return circuit_breaker_2.canExecuteRequest; } });
43
+ var validation_1 = require("./utils/validation");
44
+ Object.defineProperty(exports, "validateReveniumConfig", { enumerable: true, get: function () { return validation_1.validateReveniumConfig; } });
45
+ Object.defineProperty(exports, "validateAnthropicMessageParams", { enumerable: true, get: function () { return validation_1.validateAnthropicMessageParams; } });
46
+ Object.defineProperty(exports, "validateUsageMetadata", { enumerable: true, get: function () { return validation_1.validateUsageMetadata; } });
47
+ /**
48
+ * Initialize the Revenium middleware with configuration from environment variables
49
+ * This function can be called explicitly for better error handling and control
50
+ *
51
+ *
52
+ *
53
+ */
54
+ // Global logger
55
+ const logger = (0, config_1.getLogger)();
56
+ function initialize() {
57
+ const initialized = (0, config_1.initializeConfig)();
58
+ if (!initialized) {
59
+ throw new Error("Failed to initialize Revenium middleware: missing required environment variables. " +
60
+ "Set REVENIUM_METERING_API_KEY or call configure() with manual configuration.");
61
+ }
62
+ try {
63
+ (0, wrapper_1.patchAnthropic)();
64
+ logger.info("Revenium Anthropic middleware initialized successfully");
65
+ logger.debug("Environment variables found and configuration loaded");
66
+ }
67
+ catch (patchError) {
68
+ const errorMessage = patchError instanceof Error ? patchError.message : String(patchError);
69
+ throw new Error(`Failed to patch Anthropic SDK: ${errorMessage}`);
70
+ }
71
+ }
72
+ /**
73
+ * Auto-initialization with graceful fallback
74
+ * Attempts to initialize automatically but doesn't throw on failure
75
+ */
76
+ function autoInitialize() {
77
+ try {
78
+ initialize();
79
+ }
80
+ catch (error) {
81
+ // Log debug message but don't throw - allow manual configuration later
82
+ logger.debug("Auto-initialization failed, manual configuration required", {
83
+ error: error instanceof Error ? error.message : String(error),
84
+ suggestion: "Call initialize() or configure() explicitly for detailed error information",
85
+ });
86
+ }
87
+ }
88
+ // Perform auto-initialization with graceful fallback
89
+ autoInitialize();
90
+ /**
91
+ * Manual initialization with custom configuration
92
+ */
93
+ function configure(config) {
94
+ (0, config_1.setConfig)(config);
95
+ (0, wrapper_1.patchAnthropic)();
96
+ (0, config_1.getLogger)().info("Revenium Anthropic middleware configured successfully");
97
+ }
98
+ /**
99
+ * Check if the middleware is properly initialized
100
+ */
101
+ function isInitialized() {
102
+ return (0, wrapper_1.isAnthropicPatched)() && !!(0, config_1.getConfig)();
103
+ }
104
+ /**
105
+ * Get comprehensive middleware status
106
+ */
107
+ function getStatus() {
108
+ const configStatus = (0, config_1.getConfigStatus)();
109
+ const circuitBreakerStats = (0, circuit_breaker_1.getCircuitBreakerStats)();
110
+ let anthropicVersion;
111
+ try {
112
+ // Try to get Anthropic version - use dynamic require for compatibility
113
+ const anthropicPackage = globalThis.require?.("@anthropic-ai/sdk/package.json");
114
+ anthropicVersion = anthropicPackage?.version;
115
+ }
116
+ catch {
117
+ // Ignore if we can't get the version
118
+ }
119
+ return {
120
+ initialized: isInitialized(),
121
+ patched: (0, wrapper_1.isAnthropicPatched)(),
122
+ hasConfig: configStatus.hasConfig,
123
+ anthropicVersion,
124
+ circuitBreakerState: circuitBreakerStats.state,
125
+ };
126
+ }
127
+ /**
128
+ * Manually track an Anthropic API call (for cases where auto-patching isn't used)
129
+ */
130
+ function trackAnthropicCall(trackingData) {
131
+ return (0, tracking_1.trackUsageAsync)(trackingData);
132
+ }
133
+ /**
134
+ * Reset middleware to initial state (useful for testing)
135
+ */
136
+ function reset() {
137
+ try {
138
+ (0, wrapper_1.unpatchAnthropic)();
139
+ (0, circuit_breaker_1.resetCircuitBreaker)();
140
+ logger.debug("Middleware reset completed");
141
+ }
142
+ catch (error) {
143
+ logger.error("Error during middleware reset", {
144
+ error: error instanceof Error ? error.message : String(error),
145
+ });
146
+ }
147
+ }
148
+ //# sourceMappingURL=index.js.map