@revenium/anthropic 1.0.7 → 1.0.9

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.
@@ -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,38 +128,40 @@ 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.io');
153
- }
154
156
  }
155
157
  // Validate optional Anthropic API key
156
- if (!isString(cfg?.anthropicApiKey)) {
158
+ if (cfg?.anthropicApiKey !== undefined && !isString(cfg?.anthropicApiKey)) {
157
159
  errors.push('anthropicApiKey must be a string if provided');
158
160
  }
159
- else if (cfg?.anthropicApiKey?.trim()?.length === 0) {
161
+ else if (cfg?.anthropicApiKey !== undefined && cfg?.anthropicApiKey?.trim()?.length === 0) {
160
162
  warnings.push('anthropicApiKey is empty - API calls may fail');
161
163
  }
162
- else if (!cfg?.anthropicApiKey?.startsWith(VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
164
+ else if (cfg?.anthropicApiKey && !cfg?.anthropicApiKey?.startsWith(VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
163
165
  warnings.push(`anthropicApiKey does not start with "${VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX}" - verify it is correct`);
164
166
  }
165
167
  // Validate optional timeout using constants
@@ -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 } 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
@@ -34,9 +34,12 @@ function getMessagesPrototype() {
34
34
  return anthropicConstructor?._Messages?.prototype;
35
35
  // Method 3: Create a minimal instance with the real API key if available
36
36
  // Fallback approach when direct prototype access methods fail
37
- const apiKey = process.env.ANTHROPIC_API_KEY;
37
+ // Check config first, then environment variable
38
+ const config = getConfig();
39
+ const apiKey = config?.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
38
40
  if (!apiKey) {
39
- throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed');
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.");
40
43
  }
41
44
  const minimalInstance = new Anthropic({ apiKey });
42
45
  const messagesPrototype = Object.getPrototypeOf(minimalInstance.messages);
@@ -54,19 +57,19 @@ function getMessagesPrototype() {
54
57
  */
55
58
  export function patchAnthropic() {
56
59
  if (patchingContext.isPatched) {
57
- logger.debug('Anthropic SDK already patched, skipping duplicate initialization');
60
+ logger.debug("Anthropic SDK already patched, skipping duplicate initialization");
58
61
  return;
59
62
  }
60
63
  try {
61
64
  // Access the Messages class prototype using sophisticated prototype access
62
65
  const messagesPrototype = getMessagesPrototype();
63
66
  if (!messagesPrototype)
64
- throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype');
67
+ throw new AnthropicPatchingError("Unable to access Anthropic Messages prototype");
65
68
  // Store original methods
66
69
  patchingContext.originalMethods.create = messagesPrototype?.create;
67
70
  patchingContext.originalMethods.stream = messagesPrototype?.stream;
68
71
  if (!patchingContext.originalMethods?.create) {
69
- throw new AnthropicPatchingError('Unable to find original create method');
72
+ throw new AnthropicPatchingError("Unable to find original create method");
70
73
  }
71
74
  // Patch the create method
72
75
  const patchedCreateFunction = function (params, options) {
@@ -80,11 +83,11 @@ export function patchAnthropic() {
80
83
  };
81
84
  }
82
85
  patchingContext.isPatched = true;
83
- logger.info('Anthropic SDK patched successfully');
86
+ logger.info("Anthropic SDK patched successfully");
84
87
  }
85
88
  catch (error) {
86
89
  const errorContext = createErrorContext()
87
- .with('patchingAttempt', true)
90
+ .with("patchingAttempt", true)
88
91
  .build();
89
92
  handleError(error, logger, errorContext);
90
93
  if (error instanceof AnthropicPatchingError)
@@ -109,11 +112,11 @@ export function unpatchAnthropic() {
109
112
  }
110
113
  patchingContext.isPatched = false;
111
114
  patchingContext.originalMethods = {};
112
- logger.info('Anthropic SDK unpatched successfully');
115
+ logger.info("Anthropic SDK unpatched successfully");
113
116
  }
114
117
  catch (error) {
115
118
  const errorContext = createErrorContext()
116
- .with('unpatchingAttempt', true)
119
+ .with("unpatchingAttempt", true)
117
120
  .build();
118
121
  handleError(error, logger, errorContext);
119
122
  throw new AnthropicPatchingError(`Failed to unpatch Anthropic SDK: ${error instanceof Error ? error.message : String(error)}`, errorContext);
@@ -129,7 +132,7 @@ export function isAnthropicPatched() {
129
132
  * Handle streaming response by collecting chunks and extracting usage data
130
133
  */
131
134
  async function handleStreamingResponse(stream, context) {
132
- const { requestId, model, metadata, requestTime, startTime } = context;
135
+ const { requestId, model, metadata, requestTime, startTime, requestBody } = context;
133
136
  // Create a new async generator that collects chunks and tracks usage
134
137
  async function* trackingStream() {
135
138
  const chunks = [];
@@ -137,7 +140,7 @@ async function handleStreamingResponse(stream, context) {
137
140
  try {
138
141
  for await (const chunk of stream) {
139
142
  // Track first token time
140
- if (!firstTokenTime && chunk.type === 'content_block_delta') {
143
+ if (!firstTokenTime && chunk.type === "content_block_delta") {
141
144
  firstTokenTime = Date.now();
142
145
  }
143
146
  chunks.push(chunk);
@@ -147,10 +150,14 @@ async function handleStreamingResponse(stream, context) {
147
150
  const endTime = Date.now();
148
151
  const responseTime = new Date();
149
152
  const duration = endTime - startTime;
150
- logger.debug('Stream completed, extracting usage', {
153
+ const timeToFirstToken = firstTokenTime
154
+ ? firstTokenTime - startTime
155
+ : undefined;
156
+ logger.debug("Stream completed, extracting usage", {
151
157
  requestId,
152
158
  chunkCount: chunks.length,
153
- duration
159
+ duration,
160
+ timeToFirstToken,
154
161
  });
155
162
  const usage = extractUsageFromStream(chunks);
156
163
  // Create tracking data
@@ -166,22 +173,24 @@ async function handleStreamingResponse(stream, context) {
166
173
  stopReason: usage.stopReason,
167
174
  metadata,
168
175
  requestTime,
169
- responseTime
176
+ responseTime,
177
+ timeToFirstToken,
178
+ requestBody: requestBody,
170
179
  };
171
180
  // Track usage asynchronously
172
181
  trackUsageAsync(trackingData);
173
- logger.debug('Anthropic streaming request completed successfully', {
182
+ logger.debug("Anthropic streaming request completed successfully", {
174
183
  requestId,
175
184
  model,
176
185
  inputTokens: usage.inputTokens,
177
186
  outputTokens: usage.outputTokens,
178
- duration
187
+ duration,
179
188
  });
180
189
  }
181
190
  catch (error) {
182
- logger.error('Error processing streaming response', {
191
+ logger.error("Error processing streaming response", {
183
192
  requestId,
184
- error: error instanceof Error ? error.message : String(error)
193
+ error: error instanceof Error ? error.message : String(error),
185
194
  });
186
195
  throw error;
187
196
  }
@@ -195,19 +204,19 @@ async function patchedCreateMethod(params, options) {
195
204
  const requestId = randomUUID();
196
205
  const startTime = Date.now();
197
206
  const requestTime = new Date();
198
- logger.debug('Intercepted Anthropic messages.create call', {
207
+ logger.debug("Intercepted Anthropic messages.create call", {
199
208
  requestId,
200
209
  model: params.model,
201
210
  hasMetadata: !!params.usageMetadata,
202
- isStreaming: !!params.stream
211
+ isStreaming: !!params.stream,
203
212
  });
204
213
  // Validate parameters
205
214
  const validation = validateAnthropicMessageParams(params);
206
215
  if (!validation.isValid) {
207
- logger.warn('Invalid Anthropic parameters detected', {
216
+ logger.warn("Invalid Anthropic parameters detected", {
208
217
  requestId,
209
218
  errors: validation.errors,
210
- warnings: validation.warnings
219
+ warnings: validation.warnings,
211
220
  });
212
221
  }
213
222
  // Extract and validate metadata
@@ -218,7 +227,7 @@ async function patchedCreateMethod(params, options) {
218
227
  // Call original method
219
228
  const originalCreate = patchingContext.originalMethods.create;
220
229
  if (!originalCreate)
221
- throw new RequestProcessingError('Original create method not available');
230
+ throw new RequestProcessingError("Original create method not available");
222
231
  const response = await originalCreate.call(this, cleanParams, options);
223
232
  // Check if this is a streaming response
224
233
  const isStreaming = !!params.stream;
@@ -241,16 +250,17 @@ async function patchedCreateMethod(params, options) {
241
250
  stopReason: usage.stopReason,
242
251
  metadata,
243
252
  requestTime,
244
- responseTime
253
+ responseTime,
254
+ requestBody: params,
245
255
  };
246
256
  // Track usage asynchronously
247
257
  trackUsageAsync(trackingData);
248
- logger.debug('Anthropic request completed successfully', {
258
+ logger.debug("Anthropic request completed successfully", {
249
259
  requestId,
250
260
  model: params.model,
251
261
  inputTokens: usage.inputTokens,
252
262
  outputTokens: usage.outputTokens,
253
- duration
263
+ duration,
254
264
  });
255
265
  return response;
256
266
  }
@@ -260,7 +270,8 @@ async function patchedCreateMethod(params, options) {
260
270
  model: params.model,
261
271
  metadata,
262
272
  requestTime,
263
- startTime
273
+ startTime,
274
+ requestBody: params,
264
275
  });
265
276
  }
266
277
  catch (error) {
@@ -285,18 +296,18 @@ async function* patchedStreamMethod(params, options) {
285
296
  const responseTime = new Date();
286
297
  const chunks = [];
287
298
  let firstTokenTime;
288
- logger.debug('Intercepted Anthropic messages.stream call', {
299
+ logger.debug("Intercepted Anthropic messages.stream call", {
289
300
  requestId,
290
301
  model: params.model,
291
- hasMetadata: !!params.usageMetadata
302
+ hasMetadata: !!params.usageMetadata,
292
303
  });
293
304
  // Validate parameters
294
305
  const validation = validateAnthropicMessageParams(params);
295
306
  if (!validation.isValid) {
296
- logger.warn('Invalid Anthropic streaming parameters detected', {
307
+ logger.warn("Invalid Anthropic streaming parameters detected", {
297
308
  requestId,
298
309
  errors: validation.errors,
299
- warnings: validation.warnings
310
+ warnings: validation.warnings,
300
311
  });
301
312
  }
302
313
  // Extract and validate metadata
@@ -307,12 +318,12 @@ async function* patchedStreamMethod(params, options) {
307
318
  // Call original stream method
308
319
  const originalStream = patchingContext.originalMethods?.stream;
309
320
  if (!originalStream) {
310
- throw new StreamProcessingError('Original stream method not available');
321
+ throw new StreamProcessingError("Original stream method not available");
311
322
  }
312
323
  const stream = originalStream.call(this, cleanParams, options);
313
324
  for await (const chunk of stream) {
314
325
  // Track first token time
315
- if (!firstTokenTime && chunk.type === 'content_block_delta') {
326
+ if (!firstTokenTime && chunk.type === "content_block_delta") {
316
327
  firstTokenTime = Date.now();
317
328
  }
318
329
  chunks.push(chunk);
@@ -320,7 +331,9 @@ async function* patchedStreamMethod(params, options) {
320
331
  }
321
332
  const endTime = Date.now();
322
333
  const duration = endTime - startTime;
323
- const timeToFirstToken = firstTokenTime ? firstTokenTime - startTime : undefined;
334
+ const timeToFirstToken = firstTokenTime
335
+ ? firstTokenTime - startTime
336
+ : undefined;
324
337
  // Extract usage information from all chunks
325
338
  const usage = extractUsageFromStream(chunks);
326
339
  // Create tracking data
@@ -337,18 +350,19 @@ async function* patchedStreamMethod(params, options) {
337
350
  metadata,
338
351
  requestTime,
339
352
  responseTime,
340
- timeToFirstToken
353
+ timeToFirstToken,
354
+ requestBody: params,
341
355
  };
342
356
  // Track usage asynchronously
343
357
  trackUsageAsync(trackingData);
344
- logger.debug('Anthropic streaming request completed successfully', {
358
+ logger.debug("Anthropic streaming request completed successfully", {
345
359
  requestId,
346
360
  model: params.model,
347
361
  inputTokens: usage.inputTokens,
348
362
  outputTokens: usage.outputTokens,
349
363
  duration,
350
364
  timeToFirstToken,
351
- chunkCount: chunks.length
365
+ chunkCount: chunks.length,
352
366
  });
353
367
  }
354
368
  catch (error) {
@@ -358,8 +372,8 @@ async function* patchedStreamMethod(params, options) {
358
372
  .withRequestId(requestId)
359
373
  .withModel(params.model)
360
374
  .withDuration(duration)
361
- .with('isStreaming', true)
362
- .with('chunkCount', chunks.length)
375
+ .with("isStreaming", true)
376
+ .with("chunkCount", chunks.length)
363
377
  .build();
364
378
  handleError(error, logger, errorContext);
365
379
  throw error;
@@ -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
  /**
@@ -7,7 +7,7 @@
7
7
  */
8
8
  export declare const DEFAULT_CONFIG: {
9
9
  /** Default Revenium API base URL */
10
- readonly REVENIUM_BASE_URL: "https://api.revenium.io";
10
+ readonly REVENIUM_BASE_URL: "https://api.revenium.ai";
11
11
  /** Default API timeout in milliseconds */
12
12
  readonly API_TIMEOUT: 5000;
13
13
  /** Default maximum retries for failed API calls */
@@ -109,6 +109,21 @@ export declare const ENV_VARS: {
109
109
  readonly FAIL_SILENT: "REVENIUM_FAIL_SILENT";
110
110
  /** Maximum retries */
111
111
  readonly MAX_RETRIES: "REVENIUM_MAX_RETRIES";
112
+ /** Print summary mode (true/false/human/json) */
113
+ readonly PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY";
114
+ /** Team ID for cost metrics retrieval */
115
+ readonly TEAM_ID: "REVENIUM_TEAM_ID";
116
+ };
117
+ /**
118
+ * Summary printer configuration
119
+ */
120
+ export declare const SUMMARY_PRINTER_CONFIG: {
121
+ /** Maximum number of retries when fetching cost metrics */
122
+ readonly MAX_RETRIES: 3;
123
+ /** Delay between retries in milliseconds */
124
+ readonly RETRY_DELAY: 2000;
125
+ /** Fetch timeout in milliseconds (prevents hung requests from keeping Node process alive) */
126
+ readonly FETCH_TIMEOUT: 10000;
112
127
  };
113
128
  /**
114
129
  * 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
  }