@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 CHANGED
@@ -2,19 +2,52 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.1.0] - 2026-01-20
6
+
7
+ ### Added
8
+
9
+ - Prompt capture functionality with credential sanitization
10
+ - Environment variable: REVENIUM_CAPTURE_PROMPTS (default: false)
11
+ - Automatic redaction of sensitive credentials in captured prompts
12
+
13
+ ### Security
14
+
15
+ - Added sanitization for API keys, tokens, passwords, and Bearer tokens in prompt data
16
+
17
+ ## [1.0.9] - 2026-01-06
18
+
19
+ ### Added
20
+
21
+ - Added terminal cost/metrics summary output after each API call
22
+ - Added distributed tracing support with 10 visualization fields
23
+
24
+ ### Fixed
25
+
26
+ - Fixed config validation to use normalized values in setConfig()
27
+ - Fixed reveniumBaseUrl to be optional with default value
28
+ - Fixed teamId whitespace trimming to prevent cost lookup issues
29
+ - Fixed usage summary to print even when Revenium tracking fails
30
+
31
+ ### Changed
32
+
33
+ - Improved error messages to use generic 'environment variable' wording
34
+
5
35
  ## [1.0.8] - 2025-11-07
6
36
 
7
37
  ### Fixed
38
+
8
39
  - Fixed `anthropicApiKey` configuration parameter to honor config value before environment variable
9
40
  - Fixed `failSilent=false` configuration to properly propagate tracking errors
10
41
  - Fixed `maxRetries=0` handling to allow zero retries when explicitly configured
11
42
 
12
43
  ### Added
44
+
13
45
  - Added `timeToFirstToken` metric tracking for streaming requests
14
46
  - Added custom metadata field preservation beyond standard fields
15
47
  - Added website link (www.revenium.ai) to README Support section
16
48
 
17
49
  ### Changed
50
+
18
51
  - Updated Revenium API base URL from `api.revenium.io` to `api.revenium.ai`
19
52
  - Updated Node.js requirement from 16+ to 18+
20
53
  - Updated `.gitignore` to exclude `dist/` directory and `.env.test`
@@ -24,6 +57,7 @@ All notable changes to this project will be documented in this file.
24
57
  ## [1.0.7] - 2025-10-25
25
58
 
26
59
  ### Changed
60
+
27
61
  - Updated all examples to use `claude-haiku-4-5` (validated Anthropic model identifier)
28
62
  - Improved examples documentation with getting_started.ts reference
29
63
  - Streamlined README by removing OpenRouter section for clarity
@@ -31,21 +65,25 @@ All notable changes to this project will be documented in this file.
31
65
  ## [1.0.6] - 2025-10-24
32
66
 
33
67
  ### Added
68
+
34
69
  - Comprehensive metadata fields table in README with practical use cases for all 11 fields
35
70
  - New `getting_started.ts` example showing complete metadata integration
36
71
 
37
72
  ### Changed
73
+
38
74
  - Streamlined Getting Started tutorial with clearer step-by-step instructions
39
75
  - Improved documentation with direct links to example files
40
76
 
41
77
  ## [1.0.5] - 2025-10-23
42
78
 
43
79
  ### Changed
44
- - Improved .env.example with realistic key format examples (hak_, sk-ant-)
80
+
81
+ - Improved .env.example with realistic key format examples (hak\_, sk-ant-)
45
82
 
46
83
  ## [1.0.4] - 2025-10-21
47
84
 
48
85
  ### Changed
86
+
49
87
  - Simplified README documentation and consolidated examples
50
88
  - Updated documentation links to use GitHub HEAD references
51
89
  - Enhanced .gitignore setup instructions with industry-standard reference
@@ -53,16 +91,19 @@ All notable changes to this project will be documented in this file.
53
91
  ## [1.0.3] - 2025-10-17
54
92
 
55
93
  ### Changed
94
+
56
95
  - Updated publishing documentation with validated release workflow
57
96
 
58
97
  ## [1.0.2] - 2025-10-16
59
98
 
60
99
  ### Changed
100
+
61
101
  - Package maintenance and stability improvements
62
102
 
63
103
  ## [1.0.1] - 2025-10-15
64
104
 
65
105
  ### Changed
106
+
66
107
  - Updated all package name references from `revenium-middleware-anthropic-node` to `@revenium/anthropic` throughout documentation
67
108
  - Removed emojis from all documentation and examples for professional presentation
68
109
  - Updated repository references to point to public repository
@@ -72,6 +113,7 @@ All notable changes to this project will be documented in this file.
72
113
  ## [1.0.0] - 2025-10-14
73
114
 
74
115
  ### Added
116
+
75
117
  - Transparent middleware for Anthropic Claude usage tracking
76
118
  - Automatic metadata integration with native TypeScript support
77
119
  - Streaming support for real-time responses
@@ -86,6 +128,9 @@ All notable changes to this project will be documented in this file.
86
128
  - Configurable retry logic
87
129
  - Debug logging support
88
130
 
131
+ [1.0.9]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.9
132
+ [1.0.8]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.8
133
+ [1.0.7]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.7
89
134
  [1.0.6]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.6
90
135
  [1.0.5]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.5
91
136
  [1.0.4]: https://github.com/revenium/revenium-middleware-anthropic-node/releases/tag/v1.0.4
package/README.md CHANGED
@@ -12,6 +12,7 @@ Automatically track and meter your Anthropic Claude API usage with Revenium. Thi
12
12
 
13
13
  - **Seamless Integration**: Drop-in replacement with zero code changes required
14
14
  - **Complete Metering**: Track tokens, costs, and performance metrics automatically
15
+ - **Prompt Capture**: Optional capture of prompts and responses with automatic credential sanitization
15
16
  - **Custom Metadata**: Add business context with native TypeScript support
16
17
  - **Streaming Support**: Real-time streaming with comprehensive analytics
17
18
  - **Tool Use Support**: Full support for Anthropic's function calling and tools
@@ -87,6 +88,112 @@ The middleware automatically captures:
87
88
  - **Streaming Metrics**: Time to first token for streaming responses
88
89
  - **Custom Metadata**: Business context you provide
89
90
 
91
+ ## Terminal Summary Output
92
+
93
+ The middleware can print a usage summary to the terminal after each API request. This is useful for development, debugging, and cost monitoring.
94
+
95
+ ### Configuration
96
+
97
+ Enable via environment variables:
98
+
99
+ ```bash
100
+ # Human-readable format (with emojis)
101
+ REVENIUM_PRINT_SUMMARY=true
102
+
103
+ # JSON format (for automation/log parsing)
104
+ REVENIUM_PRINT_SUMMARY=json
105
+
106
+ # Team ID for cost retrieval (optional)
107
+ REVENIUM_TEAM_ID=your-team-id
108
+ ```
109
+
110
+ Or configure programmatically:
111
+
112
+ ```typescript
113
+ import { configure } from "@revenium/anthropic";
114
+
115
+ configure({
116
+ reveniumApiKey: "hak_your_key",
117
+ reveniumBaseUrl: "https://api.revenium.ai", // optional, this is the default
118
+ printSummary: "human", // or "json" or true
119
+ teamId: "your-team-id", // optional, for cost data
120
+ });
121
+ ```
122
+
123
+ ### Output Formats
124
+
125
+ **Human-readable format** (`printSummary: true` or `printSummary: 'human'`):
126
+
127
+ ```
128
+ ============================================================
129
+ 📊 REVENIUM USAGE SUMMARY
130
+ ============================================================
131
+ 🤖 Model: claude-sonnet-4-20250514
132
+ 🏢 Provider: Anthropic
133
+ ⏱️ Duration: 1.23s
134
+
135
+ 💬 Token Usage:
136
+ 📥 Input Tokens: 150
137
+ 📤 Output Tokens: 75
138
+ 📊 Total Tokens: 225
139
+
140
+ 💰 Cost: $0.001234
141
+ ============================================================
142
+ ```
143
+
144
+ **JSON format** (`printSummary: 'json'`):
145
+
146
+ ```json
147
+ {
148
+ "model": "claude-sonnet-4-20250514",
149
+ "provider": "Anthropic",
150
+ "durationSeconds": 1.23,
151
+ "inputTokenCount": 150,
152
+ "outputTokenCount": 75,
153
+ "totalTokenCount": 225,
154
+ "cost": 0.001234
155
+ }
156
+ ```
157
+
158
+ > **Note**: Cost data requires `teamId` to be configured. Without it, the summary will show token usage but not cost.
159
+ >
160
+ > **Optional fields**: The JSON output may include additional fields depending on the context:
161
+ >
162
+ > - `costStatus`: `"pending"` (when `teamId` is set but cost is not yet available) or `"unavailable"` (when `teamId` is not configured). Only present when `cost` is `null`.
163
+ > - `traceId`: The trace ID for request correlation (only present if `traceId` was provided in `usageMetadata`).
164
+
165
+ ## Trace Visualization Fields
166
+
167
+ The middleware automatically captures trace visualization fields for distributed tracing and analytics:
168
+
169
+ | Field | Type | Description | Environment Variable |
170
+ | --------------------- | ------ | ------------------------------------------------------------------------------- | ---------------------------------- |
171
+ | `environment` | string | Deployment environment (production, staging, development) | `REVENIUM_ENVIRONMENT`, `NODE_ENV` |
172
+ | `operationType` | string | Operation classification (CHAT) - automatically detected | N/A (auto-detected) |
173
+ | `operationSubtype` | string | Additional detail (function_call, etc.) - automatically detected | N/A (auto-detected) |
174
+ | `retryNumber` | number | Retry attempt number (0 for first attempt, 1+ for retries) | `REVENIUM_RETRY_NUMBER` |
175
+ | `parentTransactionId` | string | Parent transaction reference for distributed tracing | `REVENIUM_PARENT_TRANSACTION_ID` |
176
+ | `transactionName` | string | Human-friendly operation label | `REVENIUM_TRANSACTION_NAME` |
177
+ | `region` | string | Cloud region (us-east-1, etc.) - auto-detected from AWS/Azure/GCP | `AWS_REGION`, `REVENIUM_REGION` |
178
+ | `credentialAlias` | string | Human-readable credential name | `REVENIUM_CREDENTIAL_ALIAS` |
179
+ | `traceType` | string | Categorical identifier (alphanumeric, hyphens, underscores only, max 128 chars) | `REVENIUM_TRACE_TYPE` |
180
+ | `traceName` | string | Human-readable label for trace instances (max 256 chars) | `REVENIUM_TRACE_NAME` |
181
+
182
+ **All trace visualization fields are optional.** The middleware will automatically detect and populate these fields when possible.
183
+
184
+ ### Example Configuration
185
+
186
+ ```env
187
+ REVENIUM_ENVIRONMENT=production
188
+ REVENIUM_REGION=us-east-1
189
+ REVENIUM_CREDENTIAL_ALIAS=Anthropic Production Key
190
+ REVENIUM_TRACE_TYPE=customer_support
191
+ REVENIUM_TRACE_NAME=Support Ticket #12345
192
+ REVENIUM_PARENT_TRANSACTION_ID=parent-txn-123
193
+ REVENIUM_TRANSACTION_NAME=Answer Customer Question
194
+ REVENIUM_RETRY_NUMBER=0
195
+ ```
196
+
90
197
  ## Advanced Usage
91
198
 
92
199
  ### Initialization Options
@@ -119,75 +226,127 @@ See [examples/advanced-features.ts](https://github.com/revenium/revenium-middlew
119
226
 
120
227
  Add business context to track usage by organization, user, task type, or custom fields. Pass a `usageMetadata` object with any of these optional fields:
121
228
 
122
- | Field | Description | Use Case |
123
- |-------|-------------|----------|
124
- | `traceId` | Unique identifier for session or conversation tracking | Link multiple API calls together for debugging, user session analytics, or distributed tracing across services |
125
- | `taskType` | Type of AI task being performed | Categorize usage by workload (e.g., "chat", "code-generation", "doc-summary") for cost analysis and optimization |
126
- | `subscriber.id` | Unique user identifier | Track individual user consumption for billing, rate limiting, or user analytics |
127
- | `subscriber.email` | User email address | Identify users for support, compliance, or usage reports |
128
- | `subscriber.credential.name` | Authentication credential name | Track which API key or service account made the request |
129
- | `subscriber.credential.value` | Authentication credential value | Associate usage with specific credentials for security auditing |
130
- | `organizationId` | Organization or company identifier | Multi-tenant cost allocation, usage quotas per organization |
131
- | `subscriptionId` | Subscription plan identifier | Track usage against subscription limits, identify plan upgrade opportunities |
132
- | `productId` | Your product or feature identifier | Attribute AI costs to specific features in your application (e.g., "chatbot", "email-assistant") |
133
- | `agent` | AI agent or bot identifier | Distinguish between multiple AI agents or automation workflows in your system |
134
- | `responseQualityScore` | Custom quality rating (0.0-1.0) | Track user satisfaction or automated quality metrics for model performance analysis |
229
+ | Field | Description | Use Case |
230
+ | ----------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
231
+ | `traceId` | Unique identifier for session or conversation tracking | Link multiple API calls together for debugging, user session analytics, or distributed tracing across services |
232
+ | `taskType` | Type of AI task being performed | Categorize usage by workload (e.g., "chat", "code-generation", "doc-summary") for cost analysis and optimization |
233
+ | `subscriber.id` | Unique user identifier | Track individual user consumption for billing, rate limiting, or user analytics |
234
+ | `subscriber.email` | User email address | Identify users for support, compliance, or usage reports |
235
+ | `subscriber.credential.name` | Authentication credential name | Track which API key or service account made the request |
236
+ | `subscriber.credential.value` | Authentication credential value | Associate usage with specific credentials for security auditing |
237
+ | `organizationId` | Organization or company identifier | Multi-tenant cost allocation, usage quotas per organization |
238
+ | `subscriptionId` | Subscription plan identifier | Track usage against subscription limits, identify plan upgrade opportunities |
239
+ | `productId` | Your product or feature identifier | Attribute AI costs to specific features in your application (e.g., "chatbot", "email-assistant") |
240
+ | `agent` | AI agent or bot identifier | Distinguish between multiple AI agents or automation workflows in your system |
241
+ | `responseQualityScore` | Custom quality rating (0.0-1.0) | Track user satisfaction or automated quality metrics for model performance analysis |
135
242
 
136
243
  **All metadata fields are optional.** Custom fields beyond the standard ones are automatically preserved and sent to Revenium.
137
244
 
138
245
  **Resources:**
246
+
139
247
  - [examples/advanced-features.ts](https://github.com/revenium/revenium-middleware-anthropic-node/blob/HEAD/examples/advanced-features.ts) - Working examples
140
248
 
141
249
  ## Metadata Fields
142
250
 
143
251
  The middleware automatically sends the following fields to Revenium's `/meter/v2/ai/completions` endpoint:
144
252
 
145
- | Field | Type | Source | Description |
146
- |-------|------|--------|-------------|
147
- | `stopReason` | string | Anthropic Response | Why completion stopped: "END", "MAX_TOKENS", "STOP_SEQUENCE", "TOOL_USE" |
148
- | `costType` | string | Fixed | Always "AI" for AI completions |
149
- | `isStreamed` | boolean | Request Type | Whether response was streamed |
150
- | `taskType` | string | usageMetadata | Optional task categorization |
151
- | `agent` | string | usageMetadata | Optional agent identifier |
152
- | `operationType` | string | Fixed | Always "CHAT" for message completions |
153
- | `inputTokenCount` | number | Anthropic Usage | Input tokens consumed |
154
- | `outputTokenCount` | number | Anthropic Usage | Output tokens generated |
155
- | `reasoningTokenCount` | number | Fixed | Always 0 (Anthropic doesn't report reasoning tokens) |
156
- | `cacheCreationTokenCount` | number | Anthropic Usage | Tokens used for prompt caching creation |
157
- | `cacheReadTokenCount` | number | Anthropic Usage | Tokens read from prompt cache |
158
- | `totalTokenCount` | number | Calculated | Sum of input + output tokens |
159
- | `organizationId` | string | usageMetadata | Optional organization identifier |
160
- | `productId` | string | usageMetadata | Optional product identifier |
161
- | `subscriber` | object | usageMetadata | Optional subscriber info (id, email, credential) |
162
- | `subscriptionId` | string | usageMetadata | Optional subscription plan identifier |
163
- | `model` | string | Request | Anthropic model used (e.g., "claude-3-5-haiku-20241022") |
164
- | `transactionId` | string | Generated | Unique request identifier (UUID) |
165
- | `responseTime` | string | Timestamp | ISO 8601 timestamp of response completion |
166
- | `requestDuration` | number | Measured | Total request duration in milliseconds |
167
- | `provider` | string | Fixed | Always "Anthropic" |
168
- | `requestTime` | string | Timestamp | ISO 8601 timestamp when request started |
169
- | `completionStartTime` | string | Timestamp | ISO 8601 timestamp when completion generation started |
170
- | `timeToFirstToken` | number | Measured | Milliseconds from request start to first token (streaming only) |
171
- | `traceId` | string | usageMetadata | Optional trace identifier for request correlation |
172
- | `responseQualityScore` | number | usageMetadata | Optional quality rating (0.0-1.0) |
173
- | `middlewareSource` | string | Fixed | Always "nodejs" to identify this middleware |
174
- | Custom Fields | any | usageMetadata | Any additional fields in usageMetadata are preserved |
253
+ | Field | Type | Source | Description |
254
+ | ------------------------- | ------- | ------------------ | ------------------------------------------------------------------------ |
255
+ | `stopReason` | string | Anthropic Response | Why completion stopped: "END", "MAX_TOKENS", "STOP_SEQUENCE", "TOOL_USE" |
256
+ | `costType` | string | Fixed | Always "AI" for AI completions |
257
+ | `isStreamed` | boolean | Request Type | Whether response was streamed |
258
+ | `taskType` | string | usageMetadata | Optional task categorization |
259
+ | `agent` | string | usageMetadata | Optional agent identifier |
260
+ | `operationType` | string | Fixed | Always "CHAT" for message completions |
261
+ | `inputTokenCount` | number | Anthropic Usage | Input tokens consumed |
262
+ | `outputTokenCount` | number | Anthropic Usage | Output tokens generated |
263
+ | `reasoningTokenCount` | number | Fixed | Always 0 (Anthropic doesn't report reasoning tokens) |
264
+ | `cacheCreationTokenCount` | number | Anthropic Usage | Tokens used for prompt caching creation |
265
+ | `cacheReadTokenCount` | number | Anthropic Usage | Tokens read from prompt cache |
266
+ | `totalTokenCount` | number | Calculated | Sum of input + output tokens |
267
+ | `organizationId` | string | usageMetadata | Optional organization identifier |
268
+ | `productId` | string | usageMetadata | Optional product identifier |
269
+ | `subscriber` | object | usageMetadata | Optional subscriber info (id, email, credential) |
270
+ | `subscriptionId` | string | usageMetadata | Optional subscription plan identifier |
271
+ | `model` | string | Request | Anthropic model used (e.g., "claude-3-5-haiku-20241022") |
272
+ | `transactionId` | string | Generated | Unique request identifier (UUID) |
273
+ | `responseTime` | string | Timestamp | ISO 8601 timestamp of response completion |
274
+ | `requestDuration` | number | Measured | Total request duration in milliseconds |
275
+ | `provider` | string | Fixed | Always "Anthropic" |
276
+ | `requestTime` | string | Timestamp | ISO 8601 timestamp when request started |
277
+ | `completionStartTime` | string | Timestamp | ISO 8601 timestamp when completion generation started |
278
+ | `timeToFirstToken` | number | Measured | Milliseconds from request start to first token (streaming only) |
279
+ | `traceId` | string | usageMetadata | Optional trace identifier for request correlation |
280
+ | `responseQualityScore` | number | usageMetadata | Optional quality rating (0.0-1.0) |
281
+ | `middlewareSource` | string | Fixed | Always "nodejs" to identify this middleware |
282
+ | Custom Fields | any | usageMetadata | Any additional fields in usageMetadata are preserved |
175
283
 
176
284
  **Note:** Fields marked as "usageMetadata" come from the optional `usageMetadata` object you pass to `messages.create()`.
177
285
 
178
286
  **Resources:**
287
+
179
288
  - [API Reference](https://revenium.readme.io/reference/meter_ai_completion) - Complete metadata field documentation
180
289
 
181
290
  ## Configuration Options
182
291
 
183
292
  ### Environment Variables
184
293
 
185
- | Variable | Required | Default | Description |
186
- | ---------------------------- | -------- | -------------------------- | --------------------------------- |
187
- | `REVENIUM_METERING_API_KEY` | Yes | - | Your Revenium API key |
188
- | `ANTHROPIC_API_KEY` | Yes | - | Anthropic Claude API key |
189
- | `REVENIUM_METERING_BASE_URL` | No | `https://api.revenium.ai` | Revenium metering API base URL |
190
- | `REVENIUM_DEBUG` | No | `false` | Enable debug logging (true/false) |
294
+ | Variable | Required | Default | Description |
295
+ | ---------------------------- | -------- | ------------------------- | ------------------------------------------ |
296
+ | `REVENIUM_METERING_API_KEY` | Yes | - | Your Revenium API key |
297
+ | `ANTHROPIC_API_KEY` | Yes | - | Anthropic Claude API key |
298
+ | `REVENIUM_METERING_BASE_URL` | No | `https://api.revenium.ai` | Revenium metering API base URL |
299
+ | `REVENIUM_DEBUG` | No | `false` | Enable debug logging (true/false) |
300
+ | `REVENIUM_CAPTURE_PROMPTS` | No | `false` | Capture prompts and responses (true/false) |
301
+
302
+ ### Prompt Capture
303
+
304
+ The middleware can capture prompts and responses for analysis and debugging. This feature is **disabled by default** for privacy and performance.
305
+
306
+ #### Configuration
307
+
308
+ Enable via environment variable:
309
+
310
+ ```bash
311
+ REVENIUM_CAPTURE_PROMPTS=true
312
+ ```
313
+
314
+ Or configure programmatically:
315
+
316
+ ```typescript
317
+ import { configure } from "@revenium/anthropic";
318
+
319
+ configure({
320
+ reveniumApiKey: "hak_your_key",
321
+ capturePrompts: true,
322
+ });
323
+ ```
324
+
325
+ #### Per-Request Control
326
+
327
+ Override the global setting for individual requests:
328
+
329
+ ```typescript
330
+ const response = await anthropic.messages.create(
331
+ {
332
+ model: "claude-3-5-sonnet-20241022",
333
+ max_tokens: 1024,
334
+ messages: [{ role: "user", content: "Hello!" }],
335
+ },
336
+ {
337
+ capturePrompts: true, // Enable for this request only
338
+ },
339
+ );
340
+ ```
341
+
342
+ #### Security
343
+
344
+ All captured prompts are automatically sanitized to remove sensitive credentials including:
345
+
346
+ - API keys (sk-\*, sk-proj-\*, sk-ant-\*)
347
+ - Bearer tokens
348
+ - Passwords
349
+ - Generic tokens and api_key fields
191
350
 
192
351
  ### Manual Configuration
193
352
 
@@ -16,27 +16,27 @@ const constants_1 = require("./constants");
16
16
  */
17
17
  class ConsoleLogger {
18
18
  isDebugEnabled() {
19
- return process.env[constants_1.ENV_VARS.DEBUG] === 'true';
19
+ return process.env[constants_1.ENV_VARS.DEBUG] === "true";
20
20
  }
21
21
  formatMessage(level, message, context) {
22
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)}` : '';
23
+ const prefix = `[${constants_1.LOGGING_CONFIG.MIDDLEWARE_NAME}${level === "DEBUG" ? " Debug" : ""}]`;
24
+ const contextStr = context ? ` ${JSON.stringify(context)}` : "";
25
25
  return `${timestamp} ${prefix} ${message}${contextStr}`;
26
26
  }
27
27
  debug(message, context) {
28
28
  if (this.isDebugEnabled()) {
29
- console.debug(this.formatMessage('DEBUG', message, context));
29
+ console.debug(this.formatMessage("DEBUG", message, context));
30
30
  }
31
31
  }
32
32
  info(message, context) {
33
- console.info(this.formatMessage('INFO', message, context));
33
+ console.info(this.formatMessage("INFO", message, context));
34
34
  }
35
35
  warn(message, context) {
36
- console.warn(this.formatMessage('WARN', message, context));
36
+ console.warn(this.formatMessage("WARN", message, context));
37
37
  }
38
38
  error(message, context) {
39
- console.error(this.formatMessage('ERROR', message, context));
39
+ console.error(this.formatMessage("ERROR", message, context));
40
40
  }
41
41
  }
42
42
  /**
@@ -51,14 +51,32 @@ function loadConfigFromEnvironment() {
51
51
  reveniumApiKey: process.env[constants_1.ENV_VARS.REVENIUM_API_KEY],
52
52
  reveniumBaseUrl: process.env[constants_1.ENV_VARS.REVENIUM_BASE_URL],
53
53
  anthropicApiKey: process.env[constants_1.ENV_VARS.ANTHROPIC_API_KEY],
54
- debug: process.env[constants_1.ENV_VARS.DEBUG] === 'true',
54
+ debug: process.env[constants_1.ENV_VARS.DEBUG] === "true",
55
55
  logLevel: process.env[constants_1.ENV_VARS.LOG_LEVEL],
56
56
  apiTimeout: process.env[constants_1.ENV_VARS.API_TIMEOUT],
57
57
  failSilent: process.env[constants_1.ENV_VARS.FAIL_SILENT],
58
- maxRetries: process.env[constants_1.ENV_VARS.MAX_RETRIES]
58
+ maxRetries: process.env[constants_1.ENV_VARS.MAX_RETRIES],
59
+ printSummary: process.env[constants_1.ENV_VARS.PRINT_SUMMARY],
60
+ teamId: process.env[constants_1.ENV_VARS.TEAM_ID],
61
+ capturePrompts: process.env[constants_1.ENV_VARS.CAPTURE_PROMPTS],
59
62
  };
60
63
  return env;
61
64
  }
65
+ /**
66
+ * Parse printSummary environment variable value
67
+ */
68
+ function parsePrintSummary(value) {
69
+ if (!value)
70
+ return undefined;
71
+ const lowerValue = value.toLowerCase();
72
+ if (lowerValue === "true" || lowerValue === "human")
73
+ return "human";
74
+ if (lowerValue === "json")
75
+ return "json";
76
+ if (lowerValue === "false")
77
+ return false;
78
+ return undefined;
79
+ }
62
80
  /**
63
81
  * Convert environment config to Revenium config
64
82
  */
@@ -67,15 +85,20 @@ function createConfigFromEnvironment(env) {
67
85
  return null;
68
86
  }
69
87
  const apiTimeout = env.apiTimeout ? parseInt(env.apiTimeout, 10) : undefined;
70
- const failSilent = env.failSilent !== 'false'; // Default to true
88
+ const failSilent = env.failSilent !== "false"; // Default to true
71
89
  const maxRetries = env.maxRetries ? parseInt(env.maxRetries, 10) : undefined;
90
+ const printSummary = parsePrintSummary(env.printSummary);
91
+ const capturePrompts = env.capturePrompts === "true";
72
92
  return {
73
93
  reveniumApiKey: env.reveniumApiKey,
74
94
  reveniumBaseUrl: env.reveniumBaseUrl || constants_1.DEFAULT_CONFIG.REVENIUM_BASE_URL,
75
95
  anthropicApiKey: env.anthropicApiKey,
76
96
  apiTimeout,
77
97
  failSilent,
78
- maxRetries
98
+ maxRetries,
99
+ printSummary,
100
+ teamId: env.teamId?.trim(),
101
+ capturePrompts,
79
102
  };
80
103
  }
81
104
  /**
@@ -85,18 +108,18 @@ function validateConfig(config) {
85
108
  const validation = (0, validation_1.validateReveniumConfig)(config);
86
109
  if (!validation.isValid) {
87
110
  // Log detailed validation errors
88
- getLogger().error('Configuration validation failed', {
111
+ getLogger().error("Configuration validation failed", {
89
112
  errors: validation.errors,
90
113
  warnings: validation.warnings,
91
- suggestions: validation.suggestions
114
+ suggestions: validation.suggestions,
92
115
  });
93
116
  // Create detailed error message
94
- let errorMessage = 'Configuration validation failed:\n';
117
+ let errorMessage = "Configuration validation failed:\n";
95
118
  validation.errors.forEach((error, index) => {
96
119
  errorMessage += ` ${index + 1}. ${error}\n`;
97
120
  });
98
121
  if (validation.suggestions && validation.suggestions.length > 0) {
99
- errorMessage += '\nSuggestions:\n';
122
+ errorMessage += "\nSuggestions:\n";
100
123
  validation.suggestions.forEach((suggestion) => {
101
124
  errorMessage += ` • ${suggestion}\n`;
102
125
  });
@@ -105,8 +128,8 @@ function validateConfig(config) {
105
128
  }
106
129
  // Log warnings if any
107
130
  if (validation.warnings && validation.warnings.length > 0) {
108
- getLogger().warn('Configuration warnings', {
109
- warnings: validation.warnings
131
+ getLogger().warn("Configuration warnings", {
132
+ warnings: validation.warnings,
110
133
  });
111
134
  }
112
135
  }
@@ -123,14 +146,42 @@ function getConfig() {
123
146
  }
124
147
  /**
125
148
  * Set the global configuration
149
+ * Uses the normalized config from validation (with defaults applied and fields trimmed)
126
150
  */
127
151
  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
152
+ const validation = (0, validation_1.validateReveniumConfig)(config);
153
+ if (!validation.isValid) {
154
+ // Log detailed validation errors
155
+ getLogger().error("Configuration validation failed", {
156
+ errors: validation.errors,
157
+ warnings: validation.warnings,
158
+ suggestions: validation.suggestions,
159
+ });
160
+ // Create detailed error message
161
+ let errorMessage = "Configuration validation failed:\n";
162
+ validation.errors.forEach((error, index) => {
163
+ errorMessage += ` ${index + 1}. ${error}\n`;
164
+ });
165
+ if (validation.suggestions && validation.suggestions.length > 0) {
166
+ errorMessage += "\nSuggestions:\n";
167
+ validation.suggestions.forEach((suggestion) => {
168
+ errorMessage += ` • ${suggestion}\n`;
169
+ });
170
+ }
171
+ throw new Error(errorMessage.trim());
172
+ }
173
+ // Log warnings if any
174
+ if (validation.warnings && validation.warnings.length > 0) {
175
+ getLogger().warn("Configuration warnings", {
176
+ warnings: validation.warnings,
177
+ });
178
+ }
179
+ // Use the normalized config from validation (with defaults applied and fields trimmed)
180
+ globalConfig = validation.config;
181
+ globalLogger.debug("Revenium configuration updated", {
182
+ baseUrl: globalConfig.reveniumBaseUrl,
183
+ hasApiKey: !!globalConfig.reveniumApiKey,
184
+ hasAnthropicKey: !!globalConfig.anthropicApiKey,
134
185
  });
135
186
  }
136
187
  /**
@@ -144,7 +195,7 @@ function getLogger() {
144
195
  */
145
196
  function setLogger(logger) {
146
197
  globalLogger = logger;
147
- globalLogger.debug('Custom logger set for Revenium middleware');
198
+ globalLogger.debug("Custom logger set for Revenium middleware");
148
199
  }
149
200
  /**
150
201
  * Initialize configuration from environment variables
@@ -155,12 +206,12 @@ function initializeConfig() {
155
206
  if (config) {
156
207
  try {
157
208
  setConfig(config);
158
- globalLogger.debug('Revenium middleware initialized from environment variables');
209
+ globalLogger.debug("Revenium middleware initialized from environment variables");
159
210
  return true;
160
211
  }
161
212
  catch (error) {
162
- globalLogger.error('Failed to initialize Revenium configuration', {
163
- error: error instanceof Error ? error.message : String(error)
213
+ globalLogger.error("Failed to initialize Revenium configuration", {
214
+ error: error instanceof Error ? error.message : String(error),
164
215
  });
165
216
  return false;
166
217
  }
@@ -181,14 +232,14 @@ function getConfigStatus() {
181
232
  hasConfig: false,
182
233
  hasApiKey: false,
183
234
  hasAnthropicKey: false,
184
- baseUrl: ''
235
+ baseUrl: "",
185
236
  };
186
237
  }
187
238
  return {
188
239
  hasConfig: true,
189
240
  hasApiKey: !!globalConfig.reveniumApiKey,
190
241
  hasAnthropicKey: !!globalConfig.anthropicApiKey,
191
- baseUrl: globalConfig.reveniumBaseUrl
242
+ baseUrl: globalConfig.reveniumBaseUrl,
192
243
  };
193
244
  }
194
245
  /**