@revenium/anthropic 1.0.8 → 1.1.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,106 @@
1
+ import { getLogger } from "../config.js";
2
+ const logger = getLogger();
3
+ let cachedRegion = null;
4
+ let regionCached = false;
5
+ export function getEnvironment() {
6
+ const env = process.env.REVENIUM_ENVIRONMENT ||
7
+ process.env.NODE_ENV ||
8
+ process.env.DEPLOYMENT_ENV ||
9
+ null;
10
+ if (env && env.length > 255) {
11
+ logger.warn(`environment exceeds max length of 255 characters. Truncating.`);
12
+ return env.substring(0, 255).trim();
13
+ }
14
+ return env ? env.trim() : null;
15
+ }
16
+ export async function getRegion() {
17
+ if (regionCached) {
18
+ return cachedRegion;
19
+ }
20
+ const envRegion = process.env.AWS_REGION ||
21
+ process.env.AZURE_REGION ||
22
+ process.env.GCP_REGION ||
23
+ process.env.REVENIUM_REGION;
24
+ if (envRegion) {
25
+ cachedRegion = envRegion.trim();
26
+ regionCached = true;
27
+ return cachedRegion;
28
+ }
29
+ try {
30
+ const controller = new AbortController();
31
+ const timeoutId = setTimeout(() => controller.abort(), 1000);
32
+ const response = await fetch("http://169.254.169.254/latest/meta-data/placement/region", {
33
+ signal: controller.signal,
34
+ });
35
+ clearTimeout(timeoutId);
36
+ if (!response.ok) {
37
+ cachedRegion = null;
38
+ regionCached = true;
39
+ return null;
40
+ }
41
+ const text = await response.text();
42
+ cachedRegion = text.trim();
43
+ regionCached = true;
44
+ return cachedRegion;
45
+ }
46
+ catch (error) {
47
+ cachedRegion = null;
48
+ regionCached = true;
49
+ return null;
50
+ }
51
+ }
52
+ export function getCredentialAlias() {
53
+ const alias = process.env.REVENIUM_CREDENTIAL_ALIAS || null;
54
+ if (alias && alias.length > 255) {
55
+ logger.warn(`credentialAlias exceeds max length of 255 characters. Truncating.`);
56
+ return alias.substring(0, 255).trim();
57
+ }
58
+ return alias ? alias.trim() : null;
59
+ }
60
+ export function getTraceType() {
61
+ const traceType = process.env.REVENIUM_TRACE_TYPE;
62
+ if (!traceType) {
63
+ return null;
64
+ }
65
+ if (!/^[a-zA-Z0-9_-]+$/.test(traceType)) {
66
+ logger.warn(`Invalid trace_type format: ${traceType}. Must be alphanumeric with hyphens/underscores only.`);
67
+ return null;
68
+ }
69
+ if (traceType.length > 128) {
70
+ logger.warn(`trace_type exceeds max length of 128 characters: ${traceType}. Truncating.`);
71
+ return traceType.substring(0, 128);
72
+ }
73
+ return traceType;
74
+ }
75
+ export function getTraceName() {
76
+ const traceName = process.env.REVENIUM_TRACE_NAME;
77
+ if (!traceName) {
78
+ return null;
79
+ }
80
+ if (traceName.length > 256) {
81
+ logger.warn(`trace_name exceeds max length of 256 characters. Truncating.`);
82
+ return traceName.substring(0, 256);
83
+ }
84
+ return traceName;
85
+ }
86
+ export function detectOperationSubtype(requestBody) {
87
+ if (requestBody && requestBody.tools && requestBody.tools.length > 0) {
88
+ return "function_call";
89
+ }
90
+ return null;
91
+ }
92
+ export function getParentTransactionId() {
93
+ return process.env.REVENIUM_PARENT_TRANSACTION_ID || null;
94
+ }
95
+ export function getTransactionName() {
96
+ return process.env.REVENIUM_TRANSACTION_NAME || null;
97
+ }
98
+ export function getRetryNumber() {
99
+ const retryNum = process.env.REVENIUM_RETRY_NUMBER;
100
+ if (retryNum) {
101
+ const parsed = parseInt(retryNum, 10);
102
+ return isNaN(parsed) ? 0 : parsed;
103
+ }
104
+ return 0;
105
+ }
106
+ //# sourceMappingURL=trace-fields.js.map
@@ -2,7 +2,7 @@
2
2
  * Validation utilities for Anthropic middleware
3
3
  * Provides type-safe validation with detailed error reporting
4
4
  */
5
- import { VALIDATION_CONFIG, ANTHROPIC_PATTERNS } from '../constants.js';
5
+ import { VALIDATION_CONFIG, ANTHROPIC_PATTERNS, DEFAULT_CONFIG } from '../constants.js';
6
6
  /**
7
7
  * Type guard for checking if a value is a non-null object
8
8
  */
@@ -128,29 +128,31 @@ export function validateReveniumConfig(config) {
128
128
  else if (cfg?.reveniumApiKey?.length < VALIDATION_CONFIG.MIN_API_KEY_LENGTH) {
129
129
  warnings.push('reveniumApiKey appears to be too short - verify it is correct');
130
130
  }
131
- // Validate Revenium base URL
132
- if (!isString(cfg?.reveniumBaseUrl)) {
133
- errors.push('reveniumBaseUrl is required and must be a string');
134
- }
135
- else if (!cfg?.reveniumBaseUrl?.trim()) {
136
- errors.push('reveniumBaseUrl cannot be empty');
137
- }
138
- else {
139
- try {
140
- const url = new URL(cfg?.reveniumBaseUrl);
141
- if (!url.protocol.startsWith('http')) {
142
- errors.push('reveniumBaseUrl must use HTTP or HTTPS protocol');
131
+ // Validate Revenium base URL (optional - defaults to https://api.revenium.ai)
132
+ if (cfg?.reveniumBaseUrl !== undefined) {
133
+ if (!isString(cfg?.reveniumBaseUrl)) {
134
+ errors.push('reveniumBaseUrl must be a string if provided');
135
+ }
136
+ else if (!cfg?.reveniumBaseUrl?.trim()) {
137
+ errors.push('reveniumBaseUrl cannot be empty if provided');
138
+ }
139
+ else {
140
+ try {
141
+ const url = new URL(cfg?.reveniumBaseUrl);
142
+ if (!url.protocol.startsWith('http')) {
143
+ errors.push('reveniumBaseUrl must use HTTP or HTTPS protocol');
144
+ }
145
+ // Check for localhost/development hostnames (IPv4, IPv6, and named)
146
+ const localhostHostnames = ['localhost', '127.0.0.1', '::1', '[::1]'];
147
+ if (localhostHostnames.includes(url.hostname)) {
148
+ warnings.push('Using localhost for Revenium API - ensure this is intended for development');
149
+ }
143
150
  }
144
- // Check for localhost/development hostnames (IPv4, IPv6, and named)
145
- const localhostHostnames = ['localhost', '127.0.0.1', '::1', '[::1]'];
146
- if (localhostHostnames.includes(url.hostname)) {
147
- warnings.push('Using localhost for Revenium API - ensure this is intended for development');
151
+ catch {
152
+ errors.push('reveniumBaseUrl must be a valid URL');
153
+ suggestions.push('Use format: https://api.revenium.ai');
148
154
  }
149
155
  }
150
- catch {
151
- errors.push('reveniumBaseUrl must be a valid URL');
152
- suggestions.push('Use format: https://api.revenium.ai');
153
- }
154
156
  }
155
157
  // Validate optional Anthropic API key
156
158
  if (cfg?.anthropicApiKey !== undefined && !isString(cfg?.anthropicApiKey)) {
@@ -192,6 +194,23 @@ export function validateReveniumConfig(config) {
192
194
  else if (cfg?.maxRetries !== undefined && cfg?.maxRetries === 0) {
193
195
  warnings.push('maxRetries is 0 - no retry attempts will be made');
194
196
  }
197
+ // Validate optional printSummary
198
+ if (cfg?.printSummary !== undefined) {
199
+ const validPrintSummaryValues = [true, false, 'human', 'json'];
200
+ if (!validPrintSummaryValues.includes(cfg?.printSummary)) {
201
+ errors.push("printSummary must be a boolean or one of: 'human', 'json'");
202
+ suggestions.push("Use printSummary: true, 'human', or 'json' to enable summary output");
203
+ }
204
+ }
205
+ // Validate optional teamId
206
+ if (cfg?.teamId !== undefined) {
207
+ if (!isString(cfg?.teamId)) {
208
+ errors.push('teamId must be a string if provided');
209
+ }
210
+ else if (cfg?.teamId?.trim()?.length === 0) {
211
+ errors.push('teamId cannot be empty if provided');
212
+ }
213
+ }
195
214
  if (errors.length > 0) {
196
215
  return {
197
216
  isValid: false,
@@ -200,14 +219,27 @@ export function validateReveniumConfig(config) {
200
219
  suggestions
201
220
  };
202
221
  }
203
- // Build validated config
222
+ // Determine validated printSummary value
223
+ let validatedPrintSummary;
224
+ if (cfg?.printSummary === true || cfg?.printSummary === 'human') {
225
+ validatedPrintSummary = 'human';
226
+ }
227
+ else if (cfg?.printSummary === 'json') {
228
+ validatedPrintSummary = 'json';
229
+ }
230
+ else if (cfg?.printSummary === false) {
231
+ validatedPrintSummary = false;
232
+ }
233
+ // Build validated config (apply default for reveniumBaseUrl if not provided)
204
234
  const validatedConfig = {
205
235
  reveniumApiKey: cfg?.reveniumApiKey,
206
- reveniumBaseUrl: cfg?.reveniumBaseUrl,
236
+ reveniumBaseUrl: isString(cfg?.reveniumBaseUrl) ? cfg?.reveniumBaseUrl : DEFAULT_CONFIG.REVENIUM_BASE_URL,
207
237
  anthropicApiKey: isString(cfg?.anthropicApiKey) ? cfg?.anthropicApiKey : undefined,
208
238
  apiTimeout: isNumber(cfg?.apiTimeout) ? cfg?.apiTimeout : undefined,
209
239
  failSilent: isBoolean(cfg?.failSilent) ? cfg?.failSilent : undefined,
210
- maxRetries: isNumber(cfg?.maxRetries) ? cfg?.maxRetries : undefined
240
+ maxRetries: isNumber(cfg?.maxRetries) ? cfg?.maxRetries : undefined,
241
+ printSummary: validatedPrintSummary,
242
+ teamId: isString(cfg?.teamId) ? cfg?.teamId?.trim() : undefined
211
243
  };
212
244
  return {
213
245
  isValid: true,
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Anthropic SDK wrapper with type safety and structured error handling
3
3
  */
4
- import Anthropic from '@anthropic-ai/sdk';
5
- import { getLogger, getConfig } from './config.js';
6
- import { trackUsageAsync, extractUsageFromResponse, extractUsageFromStream } from './tracking.js';
7
- import { validateAnthropicMessageParams, validateUsageMetadata } from './utils/validation.js';
8
- import { AnthropicPatchingError, RequestProcessingError, StreamProcessingError, createErrorContext, handleError } from './utils/error-handling.js';
9
- import { randomUUID } from 'crypto';
4
+ import Anthropic from "@anthropic-ai/sdk";
5
+ import { getLogger, getConfig } from "./config.js";
6
+ import { trackUsageAsync, extractUsageFromResponse, extractUsageFromStream, } from "./tracking.js";
7
+ import { validateAnthropicMessageParams, validateUsageMetadata, } from "./utils/validation.js";
8
+ import { AnthropicPatchingError, RequestProcessingError, StreamProcessingError, createErrorContext, handleError, } from "./utils/error-handling.js";
9
+ import { randomUUID } from "crypto";
10
10
  // Global logger
11
11
  const logger = getLogger();
12
12
  /**
@@ -15,7 +15,7 @@ const logger = getLogger();
15
15
  const patchingContext = {
16
16
  originalMethods: {},
17
17
  isPatched: false,
18
- patchedInstances: new WeakSet()
18
+ patchedInstances: new WeakSet(),
19
19
  };
20
20
  /**
21
21
  * Get the Messages prototype using sophisticated prototype access
@@ -38,8 +38,8 @@ function getMessagesPrototype() {
38
38
  const config = getConfig();
39
39
  const apiKey = config?.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
40
40
  if (!apiKey) {
41
- throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed. ' +
42
- 'Provide ANTHROPIC_API_KEY environment variable or pass anthropicApiKey in config.');
41
+ throw new AnthropicPatchingError("Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed. " +
42
+ "Provide ANTHROPIC_API_KEY environment variable or pass anthropicApiKey in config.");
43
43
  }
44
44
  const minimalInstance = new Anthropic({ apiKey });
45
45
  const messagesPrototype = Object.getPrototypeOf(minimalInstance.messages);
@@ -57,19 +57,19 @@ function getMessagesPrototype() {
57
57
  */
58
58
  export function patchAnthropic() {
59
59
  if (patchingContext.isPatched) {
60
- logger.debug('Anthropic SDK already patched, skipping duplicate initialization');
60
+ logger.debug("Anthropic SDK already patched, skipping duplicate initialization");
61
61
  return;
62
62
  }
63
63
  try {
64
64
  // Access the Messages class prototype using sophisticated prototype access
65
65
  const messagesPrototype = getMessagesPrototype();
66
66
  if (!messagesPrototype)
67
- throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype');
67
+ throw new AnthropicPatchingError("Unable to access Anthropic Messages prototype");
68
68
  // Store original methods
69
69
  patchingContext.originalMethods.create = messagesPrototype?.create;
70
70
  patchingContext.originalMethods.stream = messagesPrototype?.stream;
71
71
  if (!patchingContext.originalMethods?.create) {
72
- throw new AnthropicPatchingError('Unable to find original create method');
72
+ throw new AnthropicPatchingError("Unable to find original create method");
73
73
  }
74
74
  // Patch the create method
75
75
  const patchedCreateFunction = function (params, options) {
@@ -83,11 +83,11 @@ export function patchAnthropic() {
83
83
  };
84
84
  }
85
85
  patchingContext.isPatched = true;
86
- logger.info('Anthropic SDK patched successfully');
86
+ logger.info("Anthropic SDK patched successfully");
87
87
  }
88
88
  catch (error) {
89
89
  const errorContext = createErrorContext()
90
- .with('patchingAttempt', true)
90
+ .with("patchingAttempt", true)
91
91
  .build();
92
92
  handleError(error, logger, errorContext);
93
93
  if (error instanceof AnthropicPatchingError)
@@ -112,11 +112,11 @@ export function unpatchAnthropic() {
112
112
  }
113
113
  patchingContext.isPatched = false;
114
114
  patchingContext.originalMethods = {};
115
- logger.info('Anthropic SDK unpatched successfully');
115
+ logger.info("Anthropic SDK unpatched successfully");
116
116
  }
117
117
  catch (error) {
118
118
  const errorContext = createErrorContext()
119
- .with('unpatchingAttempt', true)
119
+ .with("unpatchingAttempt", true)
120
120
  .build();
121
121
  handleError(error, logger, errorContext);
122
122
  throw new AnthropicPatchingError(`Failed to unpatch Anthropic SDK: ${error instanceof Error ? error.message : String(error)}`, errorContext);
@@ -132,7 +132,7 @@ export function isAnthropicPatched() {
132
132
  * Handle streaming response by collecting chunks and extracting usage data
133
133
  */
134
134
  async function handleStreamingResponse(stream, context) {
135
- const { requestId, model, metadata, requestTime, startTime } = context;
135
+ const { requestId, model, metadata, requestTime, startTime, requestBody } = context;
136
136
  // Create a new async generator that collects chunks and tracks usage
137
137
  async function* trackingStream() {
138
138
  const chunks = [];
@@ -140,7 +140,7 @@ async function handleStreamingResponse(stream, context) {
140
140
  try {
141
141
  for await (const chunk of stream) {
142
142
  // Track first token time
143
- if (!firstTokenTime && chunk.type === 'content_block_delta') {
143
+ if (!firstTokenTime && chunk.type === "content_block_delta") {
144
144
  firstTokenTime = Date.now();
145
145
  }
146
146
  chunks.push(chunk);
@@ -150,12 +150,14 @@ async function handleStreamingResponse(stream, context) {
150
150
  const endTime = Date.now();
151
151
  const responseTime = new Date();
152
152
  const duration = endTime - startTime;
153
- const timeToFirstToken = firstTokenTime ? firstTokenTime - startTime : undefined;
154
- logger.debug('Stream completed, extracting usage', {
153
+ const timeToFirstToken = firstTokenTime
154
+ ? firstTokenTime - startTime
155
+ : undefined;
156
+ logger.debug("Stream completed, extracting usage", {
155
157
  requestId,
156
158
  chunkCount: chunks.length,
157
159
  duration,
158
- timeToFirstToken
160
+ timeToFirstToken,
159
161
  });
160
162
  const usage = extractUsageFromStream(chunks);
161
163
  // Create tracking data
@@ -172,22 +174,23 @@ async function handleStreamingResponse(stream, context) {
172
174
  metadata,
173
175
  requestTime,
174
176
  responseTime,
175
- timeToFirstToken
177
+ timeToFirstToken,
178
+ requestBody: requestBody,
176
179
  };
177
180
  // Track usage asynchronously
178
181
  trackUsageAsync(trackingData);
179
- logger.debug('Anthropic streaming request completed successfully', {
182
+ logger.debug("Anthropic streaming request completed successfully", {
180
183
  requestId,
181
184
  model,
182
185
  inputTokens: usage.inputTokens,
183
186
  outputTokens: usage.outputTokens,
184
- duration
187
+ duration,
185
188
  });
186
189
  }
187
190
  catch (error) {
188
- logger.error('Error processing streaming response', {
191
+ logger.error("Error processing streaming response", {
189
192
  requestId,
190
- error: error instanceof Error ? error.message : String(error)
193
+ error: error instanceof Error ? error.message : String(error),
191
194
  });
192
195
  throw error;
193
196
  }
@@ -201,19 +204,19 @@ async function patchedCreateMethod(params, options) {
201
204
  const requestId = randomUUID();
202
205
  const startTime = Date.now();
203
206
  const requestTime = new Date();
204
- logger.debug('Intercepted Anthropic messages.create call', {
207
+ logger.debug("Intercepted Anthropic messages.create call", {
205
208
  requestId,
206
209
  model: params.model,
207
210
  hasMetadata: !!params.usageMetadata,
208
- isStreaming: !!params.stream
211
+ isStreaming: !!params.stream,
209
212
  });
210
213
  // Validate parameters
211
214
  const validation = validateAnthropicMessageParams(params);
212
215
  if (!validation.isValid) {
213
- logger.warn('Invalid Anthropic parameters detected', {
216
+ logger.warn("Invalid Anthropic parameters detected", {
214
217
  requestId,
215
218
  errors: validation.errors,
216
- warnings: validation.warnings
219
+ warnings: validation.warnings,
217
220
  });
218
221
  }
219
222
  // Extract and validate metadata
@@ -224,7 +227,7 @@ async function patchedCreateMethod(params, options) {
224
227
  // Call original method
225
228
  const originalCreate = patchingContext.originalMethods.create;
226
229
  if (!originalCreate)
227
- throw new RequestProcessingError('Original create method not available');
230
+ throw new RequestProcessingError("Original create method not available");
228
231
  const response = await originalCreate.call(this, cleanParams, options);
229
232
  // Check if this is a streaming response
230
233
  const isStreaming = !!params.stream;
@@ -247,16 +250,17 @@ async function patchedCreateMethod(params, options) {
247
250
  stopReason: usage.stopReason,
248
251
  metadata,
249
252
  requestTime,
250
- responseTime
253
+ responseTime,
254
+ requestBody: params,
251
255
  };
252
256
  // Track usage asynchronously
253
257
  trackUsageAsync(trackingData);
254
- logger.debug('Anthropic request completed successfully', {
258
+ logger.debug("Anthropic request completed successfully", {
255
259
  requestId,
256
260
  model: params.model,
257
261
  inputTokens: usage.inputTokens,
258
262
  outputTokens: usage.outputTokens,
259
- duration
263
+ duration,
260
264
  });
261
265
  return response;
262
266
  }
@@ -266,7 +270,8 @@ async function patchedCreateMethod(params, options) {
266
270
  model: params.model,
267
271
  metadata,
268
272
  requestTime,
269
- startTime
273
+ startTime,
274
+ requestBody: params,
270
275
  });
271
276
  }
272
277
  catch (error) {
@@ -291,18 +296,18 @@ async function* patchedStreamMethod(params, options) {
291
296
  const responseTime = new Date();
292
297
  const chunks = [];
293
298
  let firstTokenTime;
294
- logger.debug('Intercepted Anthropic messages.stream call', {
299
+ logger.debug("Intercepted Anthropic messages.stream call", {
295
300
  requestId,
296
301
  model: params.model,
297
- hasMetadata: !!params.usageMetadata
302
+ hasMetadata: !!params.usageMetadata,
298
303
  });
299
304
  // Validate parameters
300
305
  const validation = validateAnthropicMessageParams(params);
301
306
  if (!validation.isValid) {
302
- logger.warn('Invalid Anthropic streaming parameters detected', {
307
+ logger.warn("Invalid Anthropic streaming parameters detected", {
303
308
  requestId,
304
309
  errors: validation.errors,
305
- warnings: validation.warnings
310
+ warnings: validation.warnings,
306
311
  });
307
312
  }
308
313
  // Extract and validate metadata
@@ -313,12 +318,12 @@ async function* patchedStreamMethod(params, options) {
313
318
  // Call original stream method
314
319
  const originalStream = patchingContext.originalMethods?.stream;
315
320
  if (!originalStream) {
316
- throw new StreamProcessingError('Original stream method not available');
321
+ throw new StreamProcessingError("Original stream method not available");
317
322
  }
318
323
  const stream = originalStream.call(this, cleanParams, options);
319
324
  for await (const chunk of stream) {
320
325
  // Track first token time
321
- if (!firstTokenTime && chunk.type === 'content_block_delta') {
326
+ if (!firstTokenTime && chunk.type === "content_block_delta") {
322
327
  firstTokenTime = Date.now();
323
328
  }
324
329
  chunks.push(chunk);
@@ -326,7 +331,9 @@ async function* patchedStreamMethod(params, options) {
326
331
  }
327
332
  const endTime = Date.now();
328
333
  const duration = endTime - startTime;
329
- const timeToFirstToken = firstTokenTime ? firstTokenTime - startTime : undefined;
334
+ const timeToFirstToken = firstTokenTime
335
+ ? firstTokenTime - startTime
336
+ : undefined;
330
337
  // Extract usage information from all chunks
331
338
  const usage = extractUsageFromStream(chunks);
332
339
  // Create tracking data
@@ -343,18 +350,19 @@ async function* patchedStreamMethod(params, options) {
343
350
  metadata,
344
351
  requestTime,
345
352
  responseTime,
346
- timeToFirstToken
353
+ timeToFirstToken,
354
+ requestBody: params,
347
355
  };
348
356
  // Track usage asynchronously
349
357
  trackUsageAsync(trackingData);
350
- logger.debug('Anthropic streaming request completed successfully', {
358
+ logger.debug("Anthropic streaming request completed successfully", {
351
359
  requestId,
352
360
  model: params.model,
353
361
  inputTokens: usage.inputTokens,
354
362
  outputTokens: usage.outputTokens,
355
363
  duration,
356
364
  timeToFirstToken,
357
- chunkCount: chunks.length
365
+ chunkCount: chunks.length,
358
366
  });
359
367
  }
360
368
  catch (error) {
@@ -364,8 +372,8 @@ async function* patchedStreamMethod(params, options) {
364
372
  .withRequestId(requestId)
365
373
  .withModel(params.model)
366
374
  .withDuration(duration)
367
- .with('isStreaming', true)
368
- .with('chunkCount', chunks.length)
375
+ .with("isStreaming", true)
376
+ .with("chunkCount", chunks.length)
369
377
  .build();
370
378
  handleError(error, logger, errorContext);
371
379
  throw error;
@@ -1,4 +1,4 @@
1
- import { ReveniumConfig, Logger } from './types';
1
+ import { ReveniumConfig, Logger } from "./types";
2
2
  /**
3
3
  * Default console logger implementation
4
4
  */
@@ -13,6 +13,7 @@ export declare function validateConfig(config: ReveniumConfig): void;
13
13
  export declare function getConfig(): ReveniumConfig | null;
14
14
  /**
15
15
  * Set the global configuration
16
+ * Uses the normalized config from validation (with defaults applied and fields trimmed)
16
17
  */
17
18
  export declare function setConfig(config: ReveniumConfig): void;
18
19
  /**
@@ -22,6 +22,10 @@ export declare const DEFAULT_CONFIG: {
22
22
  readonly MAX_RETRY_ATTEMPTS: 10;
23
23
  /** Warning threshold for low API timeout */
24
24
  readonly LOW_TIMEOUT_WARNING_THRESHOLD: 3000;
25
+ /** Default prompt capture behavior */
26
+ readonly CAPTURE_PROMPTS: false;
27
+ /** Maximum size for each prompt field in characters (50KB) */
28
+ readonly MAX_PROMPT_SIZE: 50000;
25
29
  };
26
30
  /**
27
31
  * Circuit breaker configuration constants
@@ -109,6 +113,23 @@ export declare const ENV_VARS: {
109
113
  readonly FAIL_SILENT: "REVENIUM_FAIL_SILENT";
110
114
  /** Maximum retries */
111
115
  readonly MAX_RETRIES: "REVENIUM_MAX_RETRIES";
116
+ /** Print summary mode (true/false/human/json) */
117
+ readonly PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY";
118
+ /** Team ID for cost metrics retrieval */
119
+ readonly TEAM_ID: "REVENIUM_TEAM_ID";
120
+ /** Prompt capture mode */
121
+ readonly CAPTURE_PROMPTS: "REVENIUM_CAPTURE_PROMPTS";
122
+ };
123
+ /**
124
+ * Summary printer configuration
125
+ */
126
+ export declare const SUMMARY_PRINTER_CONFIG: {
127
+ /** Maximum number of retries when fetching cost metrics */
128
+ readonly MAX_RETRIES: 3;
129
+ /** Delay between retries in milliseconds */
130
+ readonly RETRY_DELAY: 2000;
131
+ /** Fetch timeout in milliseconds (prevents hung requests from keeping Node process alive) */
132
+ readonly FETCH_TIMEOUT: 10000;
112
133
  };
113
134
  /**
114
135
  * API endpoints
@@ -18,68 +18,6 @@
18
18
  * - **Automatic Validation**: TypeScript validates the structure at compile time
19
19
  * - **Better Developer Experience**: Auto-completion and error detection
20
20
  *
21
- * ## Usage Examples:
22
- *
23
- * ### Basic Usage:
24
- * ```typescript
25
- * import '@revenium/anthropic';
26
- * import Anthropic from '@anthropic-ai/sdk';
27
- *
28
- * const anthropic = new Anthropic();
29
- *
30
- * const response = await anthropic.messages.create({
31
- * model: 'claude-3-5-sonnet-latest',
32
- * max_tokens: 1024,
33
- * messages: [{ role: 'user', content: 'Hello!' }],
34
- * usageMetadata: { // TypeScript recognizes this natively
35
- * subscriber: { id: 'user-123', email: 'user@example.com' },
36
- * organizationId: 'my-company',
37
- * taskType: 'customer-support',
38
- * traceId: 'session-abc-123'
39
- * }
40
- * });
41
- * ```
42
- *
43
- * ### Streaming Usage:
44
- * ```typescript
45
- * const stream = await anthropic.messages.stream({
46
- * model: 'claude-3-5-sonnet-latest',
47
- * max_tokens: 1024,
48
- * messages: [{ role: 'user', content: 'Generate a report' }],
49
- * usageMetadata: {
50
- * taskType: 'content-generation',
51
- * productId: 'report-generator',
52
- * responseQualityScore: 0.95
53
- * }
54
- * });
55
- * ```
56
- *
57
- * ### Advanced Usage with All Fields:
58
- * ```typescript
59
- * const response = await anthropic.messages.create({
60
- * model: 'claude-3-5-sonnet-latest',
61
- * max_tokens: 2048,
62
- * messages: [{ role: 'user', content: 'Complex analysis task' }],
63
- * usageMetadata: {
64
- * subscriber: {
65
- * id: 'user-456',
66
- * email: 'analyst@company.com',
67
- * credential: { name: 'api-key', value: 'sk-...' }
68
- * },
69
- * traceId: 'analysis-session-789',
70
- * taskType: 'data-analysis',
71
- * organizationId: 'enterprise-client',
72
- * subscriptionId: 'premium-plan',
73
- * productId: 'analytics-suite',
74
- * agent: 'data-analyst-bot',
75
- * responseQualityScore: 0.98,
76
- * customField: 'custom-value' // Extensible with custom fields
77
- * }
78
- * });
79
- * ```
80
- *
81
- * @public
82
- * @since 1.1.0
83
21
  */
84
22
  import { UsageMetadata } from "../types";
85
23
  export {};
@@ -109,36 +47,6 @@ declare module "@anthropic-ai/sdk/resources/messages" {
109
47
  * - **Multi-tenancy**: Organize usage by organizationId
110
48
  * - **Quality Monitoring**: Track response quality scores
111
49
  * - **Custom Analytics**: Add custom fields for specific business needs
112
- *
113
- * @example Basic user tracking
114
- * ```typescript
115
- * usageMetadata: {
116
- * subscriber: { id: 'user-123', email: 'user@example.com' },
117
- * organizationId: 'my-company'
118
- * }
119
- * ```
120
- *
121
- * @example Session and task tracking
122
- * ```typescript
123
- * usageMetadata: {
124
- * traceId: 'session-abc-123',
125
- * taskType: 'customer-support',
126
- * productId: 'help-desk'
127
- * }
128
- * ```
129
- *
130
- * @example Advanced analytics
131
- * ```typescript
132
- * usageMetadata: {
133
- * subscriber: { id: 'user-456' },
134
- * taskType: 'content-generation',
135
- * responseQualityScore: 0.95,
136
- * customMetric: 'high-priority'
137
- * }
138
- * ```
139
- *
140
- * @public
141
- * @since 1.1.0
142
50
  */
143
51
  usageMetadata?: UsageMetadata;
144
52
  }