@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.
- package/CHANGELOG.md +46 -1
- package/README.md +208 -49
- package/dist/cjs/config.js +80 -29
- package/dist/cjs/constants.js +45 -24
- package/dist/cjs/tracking.js +82 -20
- package/dist/cjs/types/anthropic-augmentation.js +0 -62
- package/dist/cjs/utils/prompt-extraction.js +158 -0
- package/dist/cjs/utils/summary-printer.js +189 -0
- package/dist/cjs/utils/trace-fields.js +117 -0
- package/dist/cjs/utils/validation.js +55 -23
- package/dist/cjs/wrapper.js +49 -41
- package/dist/esm/config.js +82 -31
- package/dist/esm/constants.js +44 -23
- package/dist/esm/tracking.js +82 -20
- package/dist/esm/types/anthropic-augmentation.js +0 -62
- package/dist/esm/utils/prompt-extraction.js +154 -0
- package/dist/esm/utils/summary-printer.js +186 -0
- package/dist/esm/utils/trace-fields.js +106 -0
- package/dist/esm/utils/validation.js +56 -24
- package/dist/esm/wrapper.js +55 -47
- package/dist/types/config.d.ts +2 -1
- package/dist/types/constants.d.ts +21 -0
- package/dist/types/types/anthropic-augmentation.d.ts +0 -92
- package/dist/types/types.d.ts +41 -198
- package/dist/types/utils/prompt-extraction.d.ts +10 -0
- package/dist/types/utils/summary-printer.d.ts +3 -0
- package/dist/types/utils/trace-fields.d.ts +10 -0
- package/examples/advanced.ts +128 -0
- package/examples/basic.ts +132 -0
- package/examples/getting_started.ts +6 -6
- package/examples/metadata.ts +58 -0
- package/package.json +4 -6
- package/examples/advanced-features.ts +0 -469
- package/examples/basic-usage.ts +0 -314
package/dist/types/types.d.ts
CHANGED
|
@@ -3,15 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Credential information for subscriber authentication
|
|
6
|
-
*
|
|
7
|
-
* @public
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* const credential: Credential = {
|
|
11
|
-
* name: 'api-key',
|
|
12
|
-
* value: 'sk-1234567890abcdef'
|
|
13
|
-
* };
|
|
14
|
-
* ```
|
|
15
6
|
*/
|
|
16
7
|
export interface Credential {
|
|
17
8
|
/** The name/type of the credential (e.g., 'api-key', 'token', 'bearer') */
|
|
@@ -22,19 +13,6 @@ export interface Credential {
|
|
|
22
13
|
/**
|
|
23
14
|
* Subscriber information for Revenium API
|
|
24
15
|
* All fields are optional to allow flexible usage
|
|
25
|
-
*
|
|
26
|
-
* @public
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* const subscriber: Subscriber = {
|
|
30
|
-
* id: 'user-123',
|
|
31
|
-
* email: 'user@example.com',
|
|
32
|
-
* credential: {
|
|
33
|
-
* name: 'api-key',
|
|
34
|
-
* value: 'sk-1234567890abcdef'
|
|
35
|
-
* }
|
|
36
|
-
* };
|
|
37
|
-
* ```
|
|
38
16
|
*/
|
|
39
17
|
export interface Subscriber {
|
|
40
18
|
/** Unique identifier for the subscriber */
|
|
@@ -46,19 +24,6 @@ export interface Subscriber {
|
|
|
46
24
|
}
|
|
47
25
|
/**
|
|
48
26
|
* Revenium configuration interface
|
|
49
|
-
*
|
|
50
|
-
* @public
|
|
51
|
-
* @example
|
|
52
|
-
* ```typescript
|
|
53
|
-
* const config: ReveniumConfig = {
|
|
54
|
-
* reveniumApiKey: 'hak_your_key_value_here',
|
|
55
|
-
* reveniumBaseUrl: 'https://api.revenium.ai',
|
|
56
|
-
* anthropicApiKey: 'sk-ant-your_api_key_here',
|
|
57
|
-
* apiTimeout: 8000,
|
|
58
|
-
* failSilent: true,
|
|
59
|
-
* maxRetries: 3
|
|
60
|
-
* };
|
|
61
|
-
* ```
|
|
62
27
|
*/
|
|
63
28
|
export interface ReveniumConfig {
|
|
64
29
|
/** Revenium API key (starts with hak_) - required for tracking */
|
|
@@ -73,25 +38,20 @@ export interface ReveniumConfig {
|
|
|
73
38
|
failSilent?: boolean;
|
|
74
39
|
/** Maximum retries for failed Revenium API calls (default: 3) */
|
|
75
40
|
maxRetries?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Enable cost/metrics summary output to terminal after each API request.
|
|
43
|
+
* - true or 'human': Human-readable format with emojis
|
|
44
|
+
* - 'json': JSON format for automation
|
|
45
|
+
* - false: Disabled (default)
|
|
46
|
+
*/
|
|
47
|
+
printSummary?: boolean | SummaryFormat;
|
|
48
|
+
/** Revenium team ID for fetching cost metrics from the API. If not provided, the summary will still be printed but without cost information. */
|
|
49
|
+
teamId?: string;
|
|
50
|
+
/** Whether to capture prompts and responses for analysis (default: false) */
|
|
51
|
+
capturePrompts?: boolean;
|
|
76
52
|
}
|
|
77
53
|
/**
|
|
78
54
|
* Usage metadata for enhanced tracking and analytics
|
|
79
|
-
*
|
|
80
|
-
* @public
|
|
81
|
-
* @example
|
|
82
|
-
* ```typescript
|
|
83
|
-
* const metadata: UsageMetadata = {
|
|
84
|
-
* subscriber: {
|
|
85
|
-
* id: 'user-123',
|
|
86
|
-
* email: 'user@example.com'
|
|
87
|
-
* },
|
|
88
|
-
* traceId: 'trace-abc-123',
|
|
89
|
-
* taskType: 'customer-support',
|
|
90
|
-
* organizationId: 'org-456',
|
|
91
|
-
* productId: 'chat-assistant',
|
|
92
|
-
* responseQualityScore: 0.95
|
|
93
|
-
* };
|
|
94
|
-
* ```
|
|
95
55
|
*/
|
|
96
56
|
export interface UsageMetadata {
|
|
97
57
|
/** User identification information with nested structure for detailed tracking */
|
|
@@ -110,22 +70,13 @@ export interface UsageMetadata {
|
|
|
110
70
|
agent?: string;
|
|
111
71
|
/** Quality score of AI response (0.0-1.0) for performance tracking */
|
|
112
72
|
responseQualityScore?: number;
|
|
73
|
+
/** Whether to capture prompts and responses for this request (overrides global config) */
|
|
74
|
+
capturePrompts?: boolean;
|
|
113
75
|
/** Allow additional custom fields for extensibility */
|
|
114
76
|
[key: string]: unknown;
|
|
115
77
|
}
|
|
116
78
|
/**
|
|
117
79
|
* Logger interface for consistent logging across the middleware
|
|
118
|
-
*
|
|
119
|
-
* @public
|
|
120
|
-
* @example
|
|
121
|
-
* ```typescript
|
|
122
|
-
* const customLogger: Logger = {
|
|
123
|
-
* debug: (msg, ctx) => console.debug(`[DEBUG] ${msg}`, ctx),
|
|
124
|
-
* info: (msg, ctx) => console.info(`[INFO] ${msg}`, ctx),
|
|
125
|
-
* warn: (msg, ctx) => console.warn(`[WARN] ${msg}`, ctx),
|
|
126
|
-
* error: (msg, ctx) => console.error(`[ERROR] ${msg}`, ctx)
|
|
127
|
-
* };
|
|
128
|
-
* ```
|
|
129
80
|
*/
|
|
130
81
|
export interface Logger {
|
|
131
82
|
/** Log debug messages (only shown when debug mode is enabled) */
|
|
@@ -139,18 +90,6 @@ export interface Logger {
|
|
|
139
90
|
}
|
|
140
91
|
/**
|
|
141
92
|
* Middleware status and health information
|
|
142
|
-
*
|
|
143
|
-
* @public
|
|
144
|
-
* @example
|
|
145
|
-
* ```typescript
|
|
146
|
-
* const status: MiddlewareStatus = {
|
|
147
|
-
* initialized: true,
|
|
148
|
-
* patched: true,
|
|
149
|
-
* hasConfig: true,
|
|
150
|
-
* anthropicVersion: '0.55.1',
|
|
151
|
-
* circuitBreakerState: 'CLOSED'
|
|
152
|
-
* };
|
|
153
|
-
* ```
|
|
154
93
|
*/
|
|
155
94
|
export interface MiddlewareStatus {
|
|
156
95
|
/** Whether the middleware has been successfully initialized */
|
|
@@ -166,22 +105,6 @@ export interface MiddlewareStatus {
|
|
|
166
105
|
}
|
|
167
106
|
/**
|
|
168
107
|
* Tracking data structure for manual usage reporting to Revenium API
|
|
169
|
-
*
|
|
170
|
-
* @public
|
|
171
|
-
* @example
|
|
172
|
-
* ```typescript
|
|
173
|
-
* const trackingData: TrackingData = {
|
|
174
|
-
* requestId: 'req-123',
|
|
175
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
176
|
-
* inputTokens: 150,
|
|
177
|
-
* outputTokens: 75,
|
|
178
|
-
* duration: 1250,
|
|
179
|
-
* isStreamed: false,
|
|
180
|
-
* stopReason: 'end_turn',
|
|
181
|
-
* requestTime: new Date('2024-01-01T10:00:00Z'),
|
|
182
|
-
* responseTime: new Date('2024-01-01T10:00:01Z')
|
|
183
|
-
* };
|
|
184
|
-
* ```
|
|
185
108
|
*/
|
|
186
109
|
export interface TrackingData {
|
|
187
110
|
/** Unique identifier for the API request */
|
|
@@ -210,32 +133,12 @@ export interface TrackingData {
|
|
|
210
133
|
responseTime: Date;
|
|
211
134
|
/** Time to first token in milliseconds (for streaming responses) */
|
|
212
135
|
timeToFirstToken?: number;
|
|
136
|
+
/** Request body containing Anthropic message parameters */
|
|
137
|
+
requestBody?: AnthropicMessageParams;
|
|
213
138
|
}
|
|
214
139
|
/**
|
|
215
140
|
* Internal payload structure for Revenium API
|
|
216
141
|
* This interface represents the exact format expected by Revenium's tracking endpoint
|
|
217
|
-
*
|
|
218
|
-
* @internal
|
|
219
|
-
* @example
|
|
220
|
-
* ```typescript
|
|
221
|
-
* const payload: ReveniumPayload = {
|
|
222
|
-
* stopReason: 'end_turn',
|
|
223
|
-
* costType: 'AI',
|
|
224
|
-
* isStreamed: false,
|
|
225
|
-
* operationType: 'CHAT',
|
|
226
|
-
* inputTokenCount: 150,
|
|
227
|
-
* outputTokenCount: 75,
|
|
228
|
-
* reasoningTokenCount: 0,
|
|
229
|
-
* cacheCreationTokenCount: 0,
|
|
230
|
-
* cacheReadTokenCount: 0,
|
|
231
|
-
* totalTokenCount: 225,
|
|
232
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
233
|
-
* transactionId: 'txn-123',
|
|
234
|
-
* responseTime: '2024-01-01T10:00:01.000Z',
|
|
235
|
-
* requestDuration: 1250,
|
|
236
|
-
* provider: 'anthropic'
|
|
237
|
-
* };
|
|
238
|
-
* ```
|
|
239
142
|
*/
|
|
240
143
|
export interface ReveniumPayload {
|
|
241
144
|
/** Reason why the AI completion stopped */
|
|
@@ -292,17 +195,22 @@ export interface ReveniumPayload {
|
|
|
292
195
|
responseQualityScore?: number;
|
|
293
196
|
/** Source identifier for the middleware */
|
|
294
197
|
middlewareSource: string;
|
|
198
|
+
environment?: string;
|
|
199
|
+
operationSubtype?: string;
|
|
200
|
+
retryNumber?: number;
|
|
201
|
+
parentTransactionId?: string;
|
|
202
|
+
transactionName?: string;
|
|
203
|
+
region?: string;
|
|
204
|
+
credentialAlias?: string;
|
|
205
|
+
traceType?: string;
|
|
206
|
+
traceName?: string;
|
|
295
207
|
}
|
|
296
208
|
/**
|
|
297
209
|
* Anthropic content block types for message validation
|
|
298
210
|
* These interfaces match Anthropic's API specification for different content types
|
|
299
|
-
*
|
|
300
|
-
* @public
|
|
301
211
|
*/
|
|
302
212
|
/**
|
|
303
213
|
* Text content block for Anthropic messages
|
|
304
|
-
*
|
|
305
|
-
* @public
|
|
306
214
|
*/
|
|
307
215
|
export interface AnthropicTextContent {
|
|
308
216
|
/** Content type identifier */
|
|
@@ -312,8 +220,6 @@ export interface AnthropicTextContent {
|
|
|
312
220
|
}
|
|
313
221
|
/**
|
|
314
222
|
* Image content block for Anthropic messages
|
|
315
|
-
*
|
|
316
|
-
* @public
|
|
317
223
|
*/
|
|
318
224
|
export interface AnthropicImageContent {
|
|
319
225
|
/** Content type identifier */
|
|
@@ -330,8 +236,6 @@ export interface AnthropicImageContent {
|
|
|
330
236
|
}
|
|
331
237
|
/**
|
|
332
238
|
* Tool use content block for Anthropic messages
|
|
333
|
-
*
|
|
334
|
-
* @public
|
|
335
239
|
*/
|
|
336
240
|
export interface AnthropicToolUseContent {
|
|
337
241
|
/** Content type identifier */
|
|
@@ -345,8 +249,6 @@ export interface AnthropicToolUseContent {
|
|
|
345
249
|
}
|
|
346
250
|
/**
|
|
347
251
|
* Tool result content block for Anthropic messages
|
|
348
|
-
*
|
|
349
|
-
* @public
|
|
350
252
|
*/
|
|
351
253
|
export interface AnthropicToolResultContent {
|
|
352
254
|
/** Content type identifier */
|
|
@@ -360,21 +262,10 @@ export interface AnthropicToolResultContent {
|
|
|
360
262
|
}
|
|
361
263
|
/**
|
|
362
264
|
* Union type for all possible Anthropic content blocks
|
|
363
|
-
*
|
|
364
|
-
* @public
|
|
365
265
|
*/
|
|
366
266
|
export type AnthropicContentBlock = AnthropicTextContent | AnthropicImageContent | AnthropicToolUseContent | AnthropicToolResultContent;
|
|
367
267
|
/**
|
|
368
268
|
* Anthropic message structure for validation
|
|
369
|
-
*
|
|
370
|
-
* @public
|
|
371
|
-
* @example
|
|
372
|
-
* ```typescript
|
|
373
|
-
* const message: AnthropicMessage = {
|
|
374
|
-
* role: 'user',
|
|
375
|
-
* content: 'Hello, how can you help me today?'
|
|
376
|
-
* };
|
|
377
|
-
* ```
|
|
378
269
|
*/
|
|
379
270
|
export interface AnthropicMessage {
|
|
380
271
|
/** Role of the message sender */
|
|
@@ -384,25 +275,6 @@ export interface AnthropicMessage {
|
|
|
384
275
|
}
|
|
385
276
|
/**
|
|
386
277
|
* Anthropic tool definition for function calling
|
|
387
|
-
*
|
|
388
|
-
* @public
|
|
389
|
-
* @example
|
|
390
|
-
* ```typescript
|
|
391
|
-
* const tool: AnthropicTool = {
|
|
392
|
-
* name: 'get_weather',
|
|
393
|
-
* description: 'Get current weather for a location',
|
|
394
|
-
* input_schema: {
|
|
395
|
-
* type: 'object',
|
|
396
|
-
* properties: {
|
|
397
|
-
* location: {
|
|
398
|
-
* type: 'string',
|
|
399
|
-
* description: 'City name'
|
|
400
|
-
* }
|
|
401
|
-
* },
|
|
402
|
-
* required: ['location']
|
|
403
|
-
* }
|
|
404
|
-
* };
|
|
405
|
-
* ```
|
|
406
278
|
*/
|
|
407
279
|
export interface AnthropicTool {
|
|
408
280
|
/** Name of the tool function */
|
|
@@ -432,15 +304,6 @@ export interface AnthropicTool {
|
|
|
432
304
|
}
|
|
433
305
|
/**
|
|
434
306
|
* Anthropic tool choice configuration for controlling tool usage
|
|
435
|
-
*
|
|
436
|
-
* @public
|
|
437
|
-
* @example
|
|
438
|
-
* ```typescript
|
|
439
|
-
* const toolChoice: AnthropicToolChoice = {
|
|
440
|
-
* type: 'tool',
|
|
441
|
-
* name: 'get_weather'
|
|
442
|
-
* };
|
|
443
|
-
* ```
|
|
444
307
|
*/
|
|
445
308
|
export interface AnthropicToolChoice {
|
|
446
309
|
/** How the model should choose tools ('auto', 'any', or 'tool') */
|
|
@@ -451,20 +314,6 @@ export interface AnthropicToolChoice {
|
|
|
451
314
|
/**
|
|
452
315
|
* Anthropic message creation parameters
|
|
453
316
|
* Complete interface for all parameters supported by Anthropic's messages API
|
|
454
|
-
*
|
|
455
|
-
* @public
|
|
456
|
-
* @example
|
|
457
|
-
* ```typescript
|
|
458
|
-
* const params: AnthropicMessageParams = {
|
|
459
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
460
|
-
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
461
|
-
* max_tokens: 1024,
|
|
462
|
-
* temperature: 0.7,
|
|
463
|
-
* usageMetadata: {
|
|
464
|
-
* subscriber: { id: 'user-123' }
|
|
465
|
-
* }
|
|
466
|
-
* };
|
|
467
|
-
* ```
|
|
468
317
|
*/
|
|
469
318
|
export interface AnthropicMessageParams {
|
|
470
319
|
/** AI model to use (e.g., 'claude-3-5-sonnet-latest') */
|
|
@@ -483,8 +332,14 @@ export interface AnthropicMessageParams {
|
|
|
483
332
|
stream?: boolean;
|
|
484
333
|
/** Sequences that will stop generation */
|
|
485
334
|
stop_sequences?: string[];
|
|
486
|
-
/** System message to set context */
|
|
487
|
-
system?: string
|
|
335
|
+
/** System message to set context - can be string or array of content blocks */
|
|
336
|
+
system?: string | Array<{
|
|
337
|
+
type: "text";
|
|
338
|
+
text: string;
|
|
339
|
+
} | {
|
|
340
|
+
type: "image";
|
|
341
|
+
source: unknown;
|
|
342
|
+
}>;
|
|
488
343
|
/** Available tools for function calling */
|
|
489
344
|
tools?: AnthropicTool[];
|
|
490
345
|
/** Tool usage configuration */
|
|
@@ -556,17 +411,6 @@ export interface AnthropicStreamChunk {
|
|
|
556
411
|
}
|
|
557
412
|
/**
|
|
558
413
|
* Configuration validation result with detailed feedback
|
|
559
|
-
*
|
|
560
|
-
* @public
|
|
561
|
-
* @example
|
|
562
|
-
* ```typescript
|
|
563
|
-
* const result: ConfigValidationResult = {
|
|
564
|
-
* isValid: false,
|
|
565
|
-
* errors: ['Missing reveniumApiKey'],
|
|
566
|
-
* warnings: ['apiTimeout is very high'],
|
|
567
|
-
* suggestions: ['Set REVENIUM_METERING_API_KEY environment variable']
|
|
568
|
-
* };
|
|
569
|
-
* ```
|
|
570
414
|
*/
|
|
571
415
|
export interface ConfigValidationResult {
|
|
572
416
|
/** Whether the configuration is valid and ready to use */
|
|
@@ -582,16 +426,6 @@ export interface ConfigValidationResult {
|
|
|
582
426
|
}
|
|
583
427
|
/**
|
|
584
428
|
* Request validation result for API call validation
|
|
585
|
-
*
|
|
586
|
-
* @public
|
|
587
|
-
* @example
|
|
588
|
-
* ```typescript
|
|
589
|
-
* const result: RequestValidationResult = {
|
|
590
|
-
* isValid: true,
|
|
591
|
-
* errors: [],
|
|
592
|
-
* warnings: ['Large message count may impact performance']
|
|
593
|
-
* };
|
|
594
|
-
* ```
|
|
595
429
|
*/
|
|
596
430
|
export interface RequestValidationResult {
|
|
597
431
|
/** Whether the request parameters are valid */
|
|
@@ -643,5 +477,14 @@ export interface EnvironmentConfig {
|
|
|
643
477
|
apiTimeout?: string;
|
|
644
478
|
failSilent?: string;
|
|
645
479
|
maxRetries?: string;
|
|
480
|
+
printSummary?: string;
|
|
481
|
+
teamId?: string;
|
|
482
|
+
capturePrompts?: string;
|
|
646
483
|
}
|
|
484
|
+
/**
|
|
485
|
+
* Summary output format options
|
|
486
|
+
* - 'human': Human-readable formatted output with emojis (default when enabled)
|
|
487
|
+
* - 'json': JSON formatted output for automation/parsing
|
|
488
|
+
*/
|
|
489
|
+
export type SummaryFormat = "human" | "json";
|
|
647
490
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnthropicMessageParams, AnthropicResponse, UsageMetadata } from "../types";
|
|
2
|
+
export interface PromptData {
|
|
3
|
+
systemPrompt?: string;
|
|
4
|
+
inputMessages?: string;
|
|
5
|
+
outputResponse?: string;
|
|
6
|
+
promptsTruncated: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function shouldCapturePrompts(metadata?: UsageMetadata): boolean;
|
|
9
|
+
export declare function extractPrompts(params: AnthropicMessageParams, response: AnthropicResponse, metadata?: UsageMetadata): PromptData | null;
|
|
10
|
+
//# sourceMappingURL=prompt-extraction.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function getEnvironment(): string | null;
|
|
2
|
+
export declare function getRegion(): Promise<string | null>;
|
|
3
|
+
export declare function getCredentialAlias(): string | null;
|
|
4
|
+
export declare function getTraceType(): string | null;
|
|
5
|
+
export declare function getTraceName(): string | null;
|
|
6
|
+
export declare function detectOperationSubtype(requestBody?: any): string | null;
|
|
7
|
+
export declare function getParentTransactionId(): string | null;
|
|
8
|
+
export declare function getTransactionName(): string | null;
|
|
9
|
+
export declare function getRetryNumber(): number;
|
|
10
|
+
//# sourceMappingURL=trace-fields.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import "@revenium/anthropic";
|
|
3
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
4
|
+
import type { UsageMetadata, TrackingData } from "@revenium/anthropic";
|
|
5
|
+
import { trackUsageAsync, getStatus } from "@revenium/anthropic";
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
await streamingWithMetadata();
|
|
9
|
+
await toolUsage();
|
|
10
|
+
await manualTracking();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const streamingWithMetadata = async () => {
|
|
14
|
+
console.log("Revenium Anthropic Middleware - Streaming Example\n");
|
|
15
|
+
const anthropic = new Anthropic();
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const metadata: UsageMetadata = {
|
|
19
|
+
subscriber: { id: "user-123", email: "user@example.com" },
|
|
20
|
+
organizationId: "my-org",
|
|
21
|
+
productId: "my-product",
|
|
22
|
+
taskType: "streaming-demo",
|
|
23
|
+
traceId: `session_${Date.now()}`,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const stream = await anthropic.messages.create({
|
|
27
|
+
model: "claude-haiku-4-5",
|
|
28
|
+
max_tokens: 100,
|
|
29
|
+
messages: [{ role: "user", content: "Write a haiku about coding." }],
|
|
30
|
+
stream: true,
|
|
31
|
+
usageMetadata: metadata,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log("Response:");
|
|
35
|
+
for await (const event of stream) {
|
|
36
|
+
if (
|
|
37
|
+
event.type === "content_block_delta" &&
|
|
38
|
+
event.delta.type === "text_delta"
|
|
39
|
+
) {
|
|
40
|
+
process.stdout.write(event.delta.text);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
console.log("\n");
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("Error:", error);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const toolUsage = async () => {
|
|
50
|
+
console.log("Revenium Anthropic Middleware - Tool Usage Example\n");
|
|
51
|
+
const anthropic = new Anthropic();
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const response = await anthropic.messages.create({
|
|
55
|
+
model: "claude-haiku-4-5",
|
|
56
|
+
max_tokens: 200,
|
|
57
|
+
tools: [
|
|
58
|
+
{
|
|
59
|
+
name: "get_weather",
|
|
60
|
+
description: "Get weather for a location",
|
|
61
|
+
input_schema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
location: { type: "string", description: "City name" },
|
|
65
|
+
},
|
|
66
|
+
required: ["location"],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
messages: [{ role: "user", content: "What's the weather in Tokyo?" }],
|
|
71
|
+
usageMetadata: {
|
|
72
|
+
subscriber: { id: "tool-user" },
|
|
73
|
+
taskType: "tool-demo",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
for (const block of response.content) {
|
|
78
|
+
if (block.type === "tool_use") {
|
|
79
|
+
console.log(`Tool called: ${block.name}`);
|
|
80
|
+
console.log(`Input: ${JSON.stringify(block.input)}\n`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error("Error:", error);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const manualTracking = async () => {
|
|
89
|
+
console.log("Revenium Anthropic Middleware - Manual Tracking Example\n");
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const now = new Date();
|
|
93
|
+
const trackingData: TrackingData = {
|
|
94
|
+
requestId: `manual_${Date.now()}`,
|
|
95
|
+
model: "claude-haiku-4-5",
|
|
96
|
+
inputTokens: 25,
|
|
97
|
+
outputTokens: 150,
|
|
98
|
+
duration: 2500,
|
|
99
|
+
isStreamed: false,
|
|
100
|
+
requestTime: new Date(now.getTime() - 2500),
|
|
101
|
+
responseTime: now,
|
|
102
|
+
metadata: {
|
|
103
|
+
subscriber: { id: "manual-user" },
|
|
104
|
+
organizationId: "manual-org",
|
|
105
|
+
taskType: "manual-tracking",
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
trackUsageAsync(trackingData);
|
|
110
|
+
console.log("Manual tracking sent successfully");
|
|
111
|
+
console.log(
|
|
112
|
+
`Tracked: ${
|
|
113
|
+
trackingData.inputTokens + trackingData.outputTokens
|
|
114
|
+
} tokens\n`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const status = getStatus();
|
|
118
|
+
console.log("Middleware Status:", {
|
|
119
|
+
initialized: status.initialized,
|
|
120
|
+
patched: status.patched,
|
|
121
|
+
hasConfig: status.hasConfig,
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("Error:", error);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import "@revenium/anthropic";
|
|
3
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
4
|
+
import {
|
|
5
|
+
configure,
|
|
6
|
+
getConfig,
|
|
7
|
+
getStatus,
|
|
8
|
+
initialize,
|
|
9
|
+
} from "@revenium/anthropic";
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
await basicUsage();
|
|
13
|
+
await explicitInitialization();
|
|
14
|
+
await manualConfiguration();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const basicUsage = async () => {
|
|
18
|
+
console.log("Revenium Anthropic Middleware - Basic Example\n");
|
|
19
|
+
const anthropic = new Anthropic();
|
|
20
|
+
try {
|
|
21
|
+
const response = await anthropic.messages.create({
|
|
22
|
+
model: "claude-haiku-4-5",
|
|
23
|
+
max_tokens: 50,
|
|
24
|
+
messages: [
|
|
25
|
+
{ role: "user", content: "What is the capital of France? Be concise." },
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const textResponse =
|
|
30
|
+
response.content[0].type === "text"
|
|
31
|
+
? response.content[0].text
|
|
32
|
+
: "Non-text response";
|
|
33
|
+
console.log("RESPONSE: \n", textResponse);
|
|
34
|
+
console.log(
|
|
35
|
+
`Tokens: ${response.usage?.input_tokens} input + ${response.usage?.output_tokens} output\n`
|
|
36
|
+
);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Error: ", error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const explicitInitialization = async () => {
|
|
43
|
+
console.log(
|
|
44
|
+
"Revenium Anthropic Middleware - Explicit Initialization Example\n"
|
|
45
|
+
);
|
|
46
|
+
try {
|
|
47
|
+
initialize();
|
|
48
|
+
const status = getStatus();
|
|
49
|
+
console.log("Middleware status:", {
|
|
50
|
+
initialized: status.initialized,
|
|
51
|
+
patched: status.patched,
|
|
52
|
+
hasConfig: status.hasConfig,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const anthropic = new Anthropic();
|
|
56
|
+
const response = await anthropic.messages.create({
|
|
57
|
+
model: "claude-haiku-4-5",
|
|
58
|
+
max_tokens: 50,
|
|
59
|
+
messages: [
|
|
60
|
+
{
|
|
61
|
+
role: "user",
|
|
62
|
+
content: "What are the benefits of explicit initialization?",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
const textResponse =
|
|
67
|
+
response.content[0].type === "text"
|
|
68
|
+
? response.content[0].text
|
|
69
|
+
: "Non-text response";
|
|
70
|
+
console.log("RESPONSE: \n", textResponse);
|
|
71
|
+
console.log(
|
|
72
|
+
`Tokens: ${response.usage?.input_tokens} input + ${response.usage?.output_tokens} output\n`
|
|
73
|
+
);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("Error: ", error);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const manualConfiguration = async () => {
|
|
80
|
+
console.log("Revenium Anthropic Middleware - Manual Configuration Example\n");
|
|
81
|
+
try {
|
|
82
|
+
// Manual configuration with all options
|
|
83
|
+
configure({
|
|
84
|
+
// Required: Revenium API configuration
|
|
85
|
+
reveniumApiKey:
|
|
86
|
+
process.env.REVENIUM_METERING_API_KEY || "hak_your_api_key_here",
|
|
87
|
+
reveniumBaseUrl:
|
|
88
|
+
process.env.REVENIUM_METERING_BASE_URL || "https://api.revenium.ai",
|
|
89
|
+
|
|
90
|
+
// Optional: Anthropic API key (can also be set in Anthropic client)
|
|
91
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
92
|
+
|
|
93
|
+
// Optional: Performance and reliability settings
|
|
94
|
+
apiTimeout: 8000, // 8 second timeout (default: 5000)
|
|
95
|
+
maxRetries: 5, // 5 retry attempts (default: 3)
|
|
96
|
+
failSilent: false, // Throw errors instead of silent failure (default: true)
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Verify configuration
|
|
100
|
+
const config = getConfig();
|
|
101
|
+
console.log("Configuration:", {
|
|
102
|
+
hasReveniumKey: !!config?.reveniumApiKey,
|
|
103
|
+
baseUrl: config?.reveniumBaseUrl,
|
|
104
|
+
timeout: config?.apiTimeout,
|
|
105
|
+
maxRetries: config?.maxRetries,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const anthropic = new Anthropic({
|
|
109
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "sk-ant-your_anthropic_key_here",
|
|
110
|
+
});
|
|
111
|
+
const response = await anthropic.messages.create({
|
|
112
|
+
model: "claude-haiku-4-5",
|
|
113
|
+
max_tokens: 50,
|
|
114
|
+
messages: [
|
|
115
|
+
{
|
|
116
|
+
role: "user",
|
|
117
|
+
content:
|
|
118
|
+
"What are the advantages of manual configuration in enterprise software?",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
});
|
|
122
|
+
const textResponse =
|
|
123
|
+
response.content[0].type === "text"
|
|
124
|
+
? response.content[0].text
|
|
125
|
+
: "Non-text response";
|
|
126
|
+
console.log("RESPONSE: \n", textResponse);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("Error: ", error);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
main().catch(console.error);
|