@revenium/anthropic 1.0.9 → 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 +12 -0
- package/README.md +58 -6
- package/dist/cjs/config.js +39 -36
- package/dist/cjs/constants.js +6 -0
- package/dist/cjs/utils/prompt-extraction.js +158 -0
- package/dist/esm/config.js +41 -38
- package/dist/esm/constants.js +6 -0
- package/dist/esm/utils/prompt-extraction.js +154 -0
- package/dist/types/config.d.ts +1 -1
- package/dist/types/constants.d.ts +6 -0
- package/dist/types/types.d.ts +13 -2
- package/dist/types/utils/prompt-extraction.d.ts +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
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
|
+
|
|
5
17
|
## [1.0.9] - 2026-01-06
|
|
6
18
|
|
|
7
19
|
### Added
|
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
|
|
@@ -157,6 +158,7 @@ configure({
|
|
|
157
158
|
> **Note**: Cost data requires `teamId` to be configured. Without it, the summary will show token usage but not cost.
|
|
158
159
|
>
|
|
159
160
|
> **Optional fields**: The JSON output may include additional fields depending on the context:
|
|
161
|
+
>
|
|
160
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`.
|
|
161
163
|
> - `traceId`: The trace ID for request correlation (only present if `traceId` was provided in `usageMetadata`).
|
|
162
164
|
|
|
@@ -289,12 +291,62 @@ The middleware automatically sends the following fields to Revenium's `/meter/v2
|
|
|
289
291
|
|
|
290
292
|
### Environment Variables
|
|
291
293
|
|
|
292
|
-
| Variable | Required | Default | Description
|
|
293
|
-
| ---------------------------- | -------- | ------------------------- |
|
|
294
|
-
| `REVENIUM_METERING_API_KEY` | Yes | - | Your Revenium API key
|
|
295
|
-
| `ANTHROPIC_API_KEY` | Yes | - | Anthropic Claude API key
|
|
296
|
-
| `REVENIUM_METERING_BASE_URL` | No | `https://api.revenium.ai` | Revenium metering API base URL
|
|
297
|
-
| `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
|
|
298
350
|
|
|
299
351
|
### Manual Configuration
|
|
300
352
|
|
package/dist/cjs/config.js
CHANGED
|
@@ -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] ===
|
|
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 ===
|
|
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(
|
|
29
|
+
console.debug(this.formatMessage("DEBUG", message, context));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
info(message, context) {
|
|
33
|
-
console.info(this.formatMessage(
|
|
33
|
+
console.info(this.formatMessage("INFO", message, context));
|
|
34
34
|
}
|
|
35
35
|
warn(message, context) {
|
|
36
|
-
console.warn(this.formatMessage(
|
|
36
|
+
console.warn(this.formatMessage("WARN", message, context));
|
|
37
37
|
}
|
|
38
38
|
error(message, context) {
|
|
39
|
-
console.error(this.formatMessage(
|
|
39
|
+
console.error(this.formatMessage("ERROR", message, context));
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
@@ -51,13 +51,14 @@ 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] ===
|
|
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
58
|
maxRetries: process.env[constants_1.ENV_VARS.MAX_RETRIES],
|
|
59
59
|
printSummary: process.env[constants_1.ENV_VARS.PRINT_SUMMARY],
|
|
60
|
-
teamId: process.env[constants_1.ENV_VARS.TEAM_ID]
|
|
60
|
+
teamId: process.env[constants_1.ENV_VARS.TEAM_ID],
|
|
61
|
+
capturePrompts: process.env[constants_1.ENV_VARS.CAPTURE_PROMPTS],
|
|
61
62
|
};
|
|
62
63
|
return env;
|
|
63
64
|
}
|
|
@@ -68,11 +69,11 @@ function parsePrintSummary(value) {
|
|
|
68
69
|
if (!value)
|
|
69
70
|
return undefined;
|
|
70
71
|
const lowerValue = value.toLowerCase();
|
|
71
|
-
if (lowerValue ===
|
|
72
|
-
return
|
|
73
|
-
if (lowerValue ===
|
|
74
|
-
return
|
|
75
|
-
if (lowerValue ===
|
|
72
|
+
if (lowerValue === "true" || lowerValue === "human")
|
|
73
|
+
return "human";
|
|
74
|
+
if (lowerValue === "json")
|
|
75
|
+
return "json";
|
|
76
|
+
if (lowerValue === "false")
|
|
76
77
|
return false;
|
|
77
78
|
return undefined;
|
|
78
79
|
}
|
|
@@ -84,9 +85,10 @@ function createConfigFromEnvironment(env) {
|
|
|
84
85
|
return null;
|
|
85
86
|
}
|
|
86
87
|
const apiTimeout = env.apiTimeout ? parseInt(env.apiTimeout, 10) : undefined;
|
|
87
|
-
const failSilent = env.failSilent !==
|
|
88
|
+
const failSilent = env.failSilent !== "false"; // Default to true
|
|
88
89
|
const maxRetries = env.maxRetries ? parseInt(env.maxRetries, 10) : undefined;
|
|
89
90
|
const printSummary = parsePrintSummary(env.printSummary);
|
|
91
|
+
const capturePrompts = env.capturePrompts === "true";
|
|
90
92
|
return {
|
|
91
93
|
reveniumApiKey: env.reveniumApiKey,
|
|
92
94
|
reveniumBaseUrl: env.reveniumBaseUrl || constants_1.DEFAULT_CONFIG.REVENIUM_BASE_URL,
|
|
@@ -95,7 +97,8 @@ function createConfigFromEnvironment(env) {
|
|
|
95
97
|
failSilent,
|
|
96
98
|
maxRetries,
|
|
97
99
|
printSummary,
|
|
98
|
-
teamId: env.teamId?.trim()
|
|
100
|
+
teamId: env.teamId?.trim(),
|
|
101
|
+
capturePrompts,
|
|
99
102
|
};
|
|
100
103
|
}
|
|
101
104
|
/**
|
|
@@ -105,18 +108,18 @@ function validateConfig(config) {
|
|
|
105
108
|
const validation = (0, validation_1.validateReveniumConfig)(config);
|
|
106
109
|
if (!validation.isValid) {
|
|
107
110
|
// Log detailed validation errors
|
|
108
|
-
getLogger().error(
|
|
111
|
+
getLogger().error("Configuration validation failed", {
|
|
109
112
|
errors: validation.errors,
|
|
110
113
|
warnings: validation.warnings,
|
|
111
|
-
suggestions: validation.suggestions
|
|
114
|
+
suggestions: validation.suggestions,
|
|
112
115
|
});
|
|
113
116
|
// Create detailed error message
|
|
114
|
-
let errorMessage =
|
|
117
|
+
let errorMessage = "Configuration validation failed:\n";
|
|
115
118
|
validation.errors.forEach((error, index) => {
|
|
116
119
|
errorMessage += ` ${index + 1}. ${error}\n`;
|
|
117
120
|
});
|
|
118
121
|
if (validation.suggestions && validation.suggestions.length > 0) {
|
|
119
|
-
errorMessage +=
|
|
122
|
+
errorMessage += "\nSuggestions:\n";
|
|
120
123
|
validation.suggestions.forEach((suggestion) => {
|
|
121
124
|
errorMessage += ` • ${suggestion}\n`;
|
|
122
125
|
});
|
|
@@ -125,8 +128,8 @@ function validateConfig(config) {
|
|
|
125
128
|
}
|
|
126
129
|
// Log warnings if any
|
|
127
130
|
if (validation.warnings && validation.warnings.length > 0) {
|
|
128
|
-
getLogger().warn(
|
|
129
|
-
warnings: validation.warnings
|
|
131
|
+
getLogger().warn("Configuration warnings", {
|
|
132
|
+
warnings: validation.warnings,
|
|
130
133
|
});
|
|
131
134
|
}
|
|
132
135
|
}
|
|
@@ -149,18 +152,18 @@ function setConfig(config) {
|
|
|
149
152
|
const validation = (0, validation_1.validateReveniumConfig)(config);
|
|
150
153
|
if (!validation.isValid) {
|
|
151
154
|
// Log detailed validation errors
|
|
152
|
-
getLogger().error(
|
|
155
|
+
getLogger().error("Configuration validation failed", {
|
|
153
156
|
errors: validation.errors,
|
|
154
157
|
warnings: validation.warnings,
|
|
155
|
-
suggestions: validation.suggestions
|
|
158
|
+
suggestions: validation.suggestions,
|
|
156
159
|
});
|
|
157
160
|
// Create detailed error message
|
|
158
|
-
let errorMessage =
|
|
161
|
+
let errorMessage = "Configuration validation failed:\n";
|
|
159
162
|
validation.errors.forEach((error, index) => {
|
|
160
163
|
errorMessage += ` ${index + 1}. ${error}\n`;
|
|
161
164
|
});
|
|
162
165
|
if (validation.suggestions && validation.suggestions.length > 0) {
|
|
163
|
-
errorMessage +=
|
|
166
|
+
errorMessage += "\nSuggestions:\n";
|
|
164
167
|
validation.suggestions.forEach((suggestion) => {
|
|
165
168
|
errorMessage += ` • ${suggestion}\n`;
|
|
166
169
|
});
|
|
@@ -169,16 +172,16 @@ function setConfig(config) {
|
|
|
169
172
|
}
|
|
170
173
|
// Log warnings if any
|
|
171
174
|
if (validation.warnings && validation.warnings.length > 0) {
|
|
172
|
-
getLogger().warn(
|
|
173
|
-
warnings: validation.warnings
|
|
175
|
+
getLogger().warn("Configuration warnings", {
|
|
176
|
+
warnings: validation.warnings,
|
|
174
177
|
});
|
|
175
178
|
}
|
|
176
179
|
// Use the normalized config from validation (with defaults applied and fields trimmed)
|
|
177
180
|
globalConfig = validation.config;
|
|
178
|
-
globalLogger.debug(
|
|
181
|
+
globalLogger.debug("Revenium configuration updated", {
|
|
179
182
|
baseUrl: globalConfig.reveniumBaseUrl,
|
|
180
183
|
hasApiKey: !!globalConfig.reveniumApiKey,
|
|
181
|
-
hasAnthropicKey: !!globalConfig.anthropicApiKey
|
|
184
|
+
hasAnthropicKey: !!globalConfig.anthropicApiKey,
|
|
182
185
|
});
|
|
183
186
|
}
|
|
184
187
|
/**
|
|
@@ -192,7 +195,7 @@ function getLogger() {
|
|
|
192
195
|
*/
|
|
193
196
|
function setLogger(logger) {
|
|
194
197
|
globalLogger = logger;
|
|
195
|
-
globalLogger.debug(
|
|
198
|
+
globalLogger.debug("Custom logger set for Revenium middleware");
|
|
196
199
|
}
|
|
197
200
|
/**
|
|
198
201
|
* Initialize configuration from environment variables
|
|
@@ -203,12 +206,12 @@ function initializeConfig() {
|
|
|
203
206
|
if (config) {
|
|
204
207
|
try {
|
|
205
208
|
setConfig(config);
|
|
206
|
-
globalLogger.debug(
|
|
209
|
+
globalLogger.debug("Revenium middleware initialized from environment variables");
|
|
207
210
|
return true;
|
|
208
211
|
}
|
|
209
212
|
catch (error) {
|
|
210
|
-
globalLogger.error(
|
|
211
|
-
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),
|
|
212
215
|
});
|
|
213
216
|
return false;
|
|
214
217
|
}
|
|
@@ -229,14 +232,14 @@ function getConfigStatus() {
|
|
|
229
232
|
hasConfig: false,
|
|
230
233
|
hasApiKey: false,
|
|
231
234
|
hasAnthropicKey: false,
|
|
232
|
-
baseUrl:
|
|
235
|
+
baseUrl: "",
|
|
233
236
|
};
|
|
234
237
|
}
|
|
235
238
|
return {
|
|
236
239
|
hasConfig: true,
|
|
237
240
|
hasApiKey: !!globalConfig.reveniumApiKey,
|
|
238
241
|
hasAnthropicKey: !!globalConfig.anthropicApiKey,
|
|
239
|
-
baseUrl: globalConfig.reveniumBaseUrl
|
|
242
|
+
baseUrl: globalConfig.reveniumBaseUrl,
|
|
240
243
|
};
|
|
241
244
|
}
|
|
242
245
|
/**
|
package/dist/cjs/constants.js
CHANGED
|
@@ -25,6 +25,10 @@ exports.DEFAULT_CONFIG = {
|
|
|
25
25
|
MAX_RETRY_ATTEMPTS: 10,
|
|
26
26
|
/** Warning threshold for low API timeout */
|
|
27
27
|
LOW_TIMEOUT_WARNING_THRESHOLD: 3000,
|
|
28
|
+
/** Default prompt capture behavior */
|
|
29
|
+
CAPTURE_PROMPTS: false,
|
|
30
|
+
/** Maximum size for each prompt field in characters (50KB) */
|
|
31
|
+
MAX_PROMPT_SIZE: 50000,
|
|
28
32
|
};
|
|
29
33
|
/**
|
|
30
34
|
* Circuit breaker configuration constants
|
|
@@ -116,6 +120,8 @@ exports.ENV_VARS = {
|
|
|
116
120
|
PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY",
|
|
117
121
|
/** Team ID for cost metrics retrieval */
|
|
118
122
|
TEAM_ID: "REVENIUM_TEAM_ID",
|
|
123
|
+
/** Prompt capture mode */
|
|
124
|
+
CAPTURE_PROMPTS: "REVENIUM_CAPTURE_PROMPTS",
|
|
119
125
|
};
|
|
120
126
|
/**
|
|
121
127
|
* Summary printer configuration
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shouldCapturePrompts = shouldCapturePrompts;
|
|
4
|
+
exports.extractPrompts = extractPrompts;
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
const config_1 = require("../config");
|
|
7
|
+
function sanitizeCredentials(text) {
|
|
8
|
+
const patterns = [
|
|
9
|
+
{
|
|
10
|
+
regex: /sk-proj-[a-zA-Z0-9_-]{48,}/g,
|
|
11
|
+
replacement: "sk-proj-***REDACTED***",
|
|
12
|
+
},
|
|
13
|
+
{ regex: /sk-[a-zA-Z0-9_-]{20,}/g, replacement: "sk-***REDACTED***" },
|
|
14
|
+
{
|
|
15
|
+
regex: /Bearer\s+[a-zA-Z0-9_\-\.]+/gi,
|
|
16
|
+
replacement: "Bearer ***REDACTED***",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
regex: /api[_-]?key["\s:=]+[a-zA-Z0-9_\-\.\+\/=]{20,}/gi,
|
|
20
|
+
replacement: "api_key: ***REDACTED***",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
regex: /token["\s:=]+[a-zA-Z0-9_\-\.]{20,}/gi,
|
|
24
|
+
replacement: "token: ***REDACTED***",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
regex: /password["\s:=]+[^\s"']{8,}/gi,
|
|
28
|
+
replacement: "password: ***REDACTED***",
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
let sanitized = text;
|
|
32
|
+
for (const pattern of patterns) {
|
|
33
|
+
sanitized = sanitized.replace(pattern.regex, pattern.replacement);
|
|
34
|
+
}
|
|
35
|
+
return sanitized;
|
|
36
|
+
}
|
|
37
|
+
function truncateString(str, maxLength) {
|
|
38
|
+
const sanitized = sanitizeCredentials(str);
|
|
39
|
+
if (sanitized.length <= maxLength) {
|
|
40
|
+
return { value: sanitized, truncated: false };
|
|
41
|
+
}
|
|
42
|
+
return { value: sanitized.substring(0, maxLength), truncated: true };
|
|
43
|
+
}
|
|
44
|
+
function extractSystemPrompt(params) {
|
|
45
|
+
if (!params.system) {
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
if (typeof params.system === "string") {
|
|
49
|
+
return params.system;
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(params.system)) {
|
|
52
|
+
return params.system
|
|
53
|
+
.map((block) => {
|
|
54
|
+
if (block.type === "text") {
|
|
55
|
+
return block.text;
|
|
56
|
+
}
|
|
57
|
+
if (block.type === "image") {
|
|
58
|
+
return "[IMAGE]";
|
|
59
|
+
}
|
|
60
|
+
return "";
|
|
61
|
+
})
|
|
62
|
+
.filter(Boolean)
|
|
63
|
+
.join("\n");
|
|
64
|
+
}
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
function extractInputMessages(params) {
|
|
68
|
+
if (!params.messages || params.messages.length === 0) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
return params.messages
|
|
72
|
+
.map((message) => {
|
|
73
|
+
const role = message.role;
|
|
74
|
+
let content = "";
|
|
75
|
+
if (typeof message.content === "string") {
|
|
76
|
+
content = message.content;
|
|
77
|
+
}
|
|
78
|
+
else if (Array.isArray(message.content)) {
|
|
79
|
+
content = message.content
|
|
80
|
+
.map((block) => {
|
|
81
|
+
if (block.type === "text") {
|
|
82
|
+
return block.text;
|
|
83
|
+
}
|
|
84
|
+
if (block.type === "image") {
|
|
85
|
+
return "[IMAGE]";
|
|
86
|
+
}
|
|
87
|
+
if (block.type === "tool_use") {
|
|
88
|
+
const toolName = block.name || "unknown";
|
|
89
|
+
return `[TOOL_USE: ${toolName}]`;
|
|
90
|
+
}
|
|
91
|
+
if (block.type === "tool_result") {
|
|
92
|
+
return "[TOOL_RESULT]";
|
|
93
|
+
}
|
|
94
|
+
return "";
|
|
95
|
+
})
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.join("\n");
|
|
98
|
+
}
|
|
99
|
+
return `[${role}]\n${content}`;
|
|
100
|
+
})
|
|
101
|
+
.join("\n\n");
|
|
102
|
+
}
|
|
103
|
+
function extractOutputResponse(response) {
|
|
104
|
+
if (!response.content || response.content.length === 0) {
|
|
105
|
+
return "";
|
|
106
|
+
}
|
|
107
|
+
return response.content
|
|
108
|
+
.map((block) => {
|
|
109
|
+
if (block.type === "text") {
|
|
110
|
+
return block.text;
|
|
111
|
+
}
|
|
112
|
+
if (block.type === "tool_use") {
|
|
113
|
+
return `[TOOL_USE: ${block.name}]`;
|
|
114
|
+
}
|
|
115
|
+
return "";
|
|
116
|
+
})
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.join("\n");
|
|
119
|
+
}
|
|
120
|
+
function shouldCapturePrompts(metadata) {
|
|
121
|
+
if (metadata?.capturePrompts !== undefined) {
|
|
122
|
+
return metadata.capturePrompts;
|
|
123
|
+
}
|
|
124
|
+
const config = (0, config_1.getConfig)();
|
|
125
|
+
if (config?.capturePrompts !== undefined) {
|
|
126
|
+
return config.capturePrompts;
|
|
127
|
+
}
|
|
128
|
+
return constants_1.DEFAULT_CONFIG.CAPTURE_PROMPTS;
|
|
129
|
+
}
|
|
130
|
+
function extractPrompts(params, response, metadata) {
|
|
131
|
+
if (!shouldCapturePrompts(metadata)) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const maxSize = constants_1.DEFAULT_CONFIG.MAX_PROMPT_SIZE;
|
|
135
|
+
let anyTruncated = false;
|
|
136
|
+
const systemPromptRaw = extractSystemPrompt(params);
|
|
137
|
+
const systemPromptResult = truncateString(systemPromptRaw, maxSize);
|
|
138
|
+
anyTruncated = anyTruncated || systemPromptResult.truncated;
|
|
139
|
+
const inputMessagesRaw = extractInputMessages(params);
|
|
140
|
+
const inputMessagesResult = truncateString(inputMessagesRaw, maxSize);
|
|
141
|
+
anyTruncated = anyTruncated || inputMessagesResult.truncated;
|
|
142
|
+
const outputResponseRaw = extractOutputResponse(response);
|
|
143
|
+
const outputResponseResult = truncateString(outputResponseRaw, maxSize);
|
|
144
|
+
anyTruncated = anyTruncated || outputResponseResult.truncated;
|
|
145
|
+
const hasAnyContent = systemPromptResult.value ||
|
|
146
|
+
inputMessagesResult.value ||
|
|
147
|
+
outputResponseResult.value;
|
|
148
|
+
if (!hasAnyContent) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
systemPrompt: systemPromptResult.value || undefined,
|
|
153
|
+
inputMessages: inputMessagesResult.value || undefined,
|
|
154
|
+
outputResponse: outputResponseResult.value || undefined,
|
|
155
|
+
promptsTruncated: anyTruncated,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=prompt-extraction.js.map
|
package/dist/esm/config.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { validateReveniumConfig } from
|
|
2
|
-
import { DEFAULT_CONFIG, ENV_VARS, LOGGING_CONFIG } from
|
|
1
|
+
import { validateReveniumConfig } from "./utils/validation.js";
|
|
2
|
+
import { DEFAULT_CONFIG, ENV_VARS, LOGGING_CONFIG } from "./constants.js";
|
|
3
3
|
/**
|
|
4
4
|
* Simple console logger implementation for Anthropic middleware
|
|
5
5
|
*/
|
|
6
6
|
class ConsoleLogger {
|
|
7
7
|
isDebugEnabled() {
|
|
8
|
-
return process.env[ENV_VARS.DEBUG] ===
|
|
8
|
+
return process.env[ENV_VARS.DEBUG] === "true";
|
|
9
9
|
}
|
|
10
10
|
formatMessage(level, message, context) {
|
|
11
11
|
const timestamp = new Date().toISOString();
|
|
12
|
-
const prefix = `[${LOGGING_CONFIG.MIDDLEWARE_NAME}${level ===
|
|
13
|
-
const contextStr = context ? ` ${JSON.stringify(context)}` :
|
|
12
|
+
const prefix = `[${LOGGING_CONFIG.MIDDLEWARE_NAME}${level === "DEBUG" ? " Debug" : ""}]`;
|
|
13
|
+
const contextStr = context ? ` ${JSON.stringify(context)}` : "";
|
|
14
14
|
return `${timestamp} ${prefix} ${message}${contextStr}`;
|
|
15
15
|
}
|
|
16
16
|
debug(message, context) {
|
|
17
17
|
if (this.isDebugEnabled()) {
|
|
18
|
-
console.debug(this.formatMessage(
|
|
18
|
+
console.debug(this.formatMessage("DEBUG", message, context));
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
info(message, context) {
|
|
22
|
-
console.info(this.formatMessage(
|
|
22
|
+
console.info(this.formatMessage("INFO", message, context));
|
|
23
23
|
}
|
|
24
24
|
warn(message, context) {
|
|
25
|
-
console.warn(this.formatMessage(
|
|
25
|
+
console.warn(this.formatMessage("WARN", message, context));
|
|
26
26
|
}
|
|
27
27
|
error(message, context) {
|
|
28
|
-
console.error(this.formatMessage(
|
|
28
|
+
console.error(this.formatMessage("ERROR", message, context));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
@@ -40,13 +40,14 @@ function loadConfigFromEnvironment() {
|
|
|
40
40
|
reveniumApiKey: process.env[ENV_VARS.REVENIUM_API_KEY],
|
|
41
41
|
reveniumBaseUrl: process.env[ENV_VARS.REVENIUM_BASE_URL],
|
|
42
42
|
anthropicApiKey: process.env[ENV_VARS.ANTHROPIC_API_KEY],
|
|
43
|
-
debug: process.env[ENV_VARS.DEBUG] ===
|
|
43
|
+
debug: process.env[ENV_VARS.DEBUG] === "true",
|
|
44
44
|
logLevel: process.env[ENV_VARS.LOG_LEVEL],
|
|
45
45
|
apiTimeout: process.env[ENV_VARS.API_TIMEOUT],
|
|
46
46
|
failSilent: process.env[ENV_VARS.FAIL_SILENT],
|
|
47
47
|
maxRetries: process.env[ENV_VARS.MAX_RETRIES],
|
|
48
48
|
printSummary: process.env[ENV_VARS.PRINT_SUMMARY],
|
|
49
|
-
teamId: process.env[ENV_VARS.TEAM_ID]
|
|
49
|
+
teamId: process.env[ENV_VARS.TEAM_ID],
|
|
50
|
+
capturePrompts: process.env[ENV_VARS.CAPTURE_PROMPTS],
|
|
50
51
|
};
|
|
51
52
|
return env;
|
|
52
53
|
}
|
|
@@ -57,11 +58,11 @@ function parsePrintSummary(value) {
|
|
|
57
58
|
if (!value)
|
|
58
59
|
return undefined;
|
|
59
60
|
const lowerValue = value.toLowerCase();
|
|
60
|
-
if (lowerValue ===
|
|
61
|
-
return
|
|
62
|
-
if (lowerValue ===
|
|
63
|
-
return
|
|
64
|
-
if (lowerValue ===
|
|
61
|
+
if (lowerValue === "true" || lowerValue === "human")
|
|
62
|
+
return "human";
|
|
63
|
+
if (lowerValue === "json")
|
|
64
|
+
return "json";
|
|
65
|
+
if (lowerValue === "false")
|
|
65
66
|
return false;
|
|
66
67
|
return undefined;
|
|
67
68
|
}
|
|
@@ -73,9 +74,10 @@ function createConfigFromEnvironment(env) {
|
|
|
73
74
|
return null;
|
|
74
75
|
}
|
|
75
76
|
const apiTimeout = env.apiTimeout ? parseInt(env.apiTimeout, 10) : undefined;
|
|
76
|
-
const failSilent = env.failSilent !==
|
|
77
|
+
const failSilent = env.failSilent !== "false"; // Default to true
|
|
77
78
|
const maxRetries = env.maxRetries ? parseInt(env.maxRetries, 10) : undefined;
|
|
78
79
|
const printSummary = parsePrintSummary(env.printSummary);
|
|
80
|
+
const capturePrompts = env.capturePrompts === "true";
|
|
79
81
|
return {
|
|
80
82
|
reveniumApiKey: env.reveniumApiKey,
|
|
81
83
|
reveniumBaseUrl: env.reveniumBaseUrl || DEFAULT_CONFIG.REVENIUM_BASE_URL,
|
|
@@ -84,7 +86,8 @@ function createConfigFromEnvironment(env) {
|
|
|
84
86
|
failSilent,
|
|
85
87
|
maxRetries,
|
|
86
88
|
printSummary,
|
|
87
|
-
teamId: env.teamId?.trim()
|
|
89
|
+
teamId: env.teamId?.trim(),
|
|
90
|
+
capturePrompts,
|
|
88
91
|
};
|
|
89
92
|
}
|
|
90
93
|
/**
|
|
@@ -94,18 +97,18 @@ export function validateConfig(config) {
|
|
|
94
97
|
const validation = validateReveniumConfig(config);
|
|
95
98
|
if (!validation.isValid) {
|
|
96
99
|
// Log detailed validation errors
|
|
97
|
-
getLogger().error(
|
|
100
|
+
getLogger().error("Configuration validation failed", {
|
|
98
101
|
errors: validation.errors,
|
|
99
102
|
warnings: validation.warnings,
|
|
100
|
-
suggestions: validation.suggestions
|
|
103
|
+
suggestions: validation.suggestions,
|
|
101
104
|
});
|
|
102
105
|
// Create detailed error message
|
|
103
|
-
let errorMessage =
|
|
106
|
+
let errorMessage = "Configuration validation failed:\n";
|
|
104
107
|
validation.errors.forEach((error, index) => {
|
|
105
108
|
errorMessage += ` ${index + 1}. ${error}\n`;
|
|
106
109
|
});
|
|
107
110
|
if (validation.suggestions && validation.suggestions.length > 0) {
|
|
108
|
-
errorMessage +=
|
|
111
|
+
errorMessage += "\nSuggestions:\n";
|
|
109
112
|
validation.suggestions.forEach((suggestion) => {
|
|
110
113
|
errorMessage += ` • ${suggestion}\n`;
|
|
111
114
|
});
|
|
@@ -114,8 +117,8 @@ export function validateConfig(config) {
|
|
|
114
117
|
}
|
|
115
118
|
// Log warnings if any
|
|
116
119
|
if (validation.warnings && validation.warnings.length > 0) {
|
|
117
|
-
getLogger().warn(
|
|
118
|
-
warnings: validation.warnings
|
|
120
|
+
getLogger().warn("Configuration warnings", {
|
|
121
|
+
warnings: validation.warnings,
|
|
119
122
|
});
|
|
120
123
|
}
|
|
121
124
|
}
|
|
@@ -138,18 +141,18 @@ export function setConfig(config) {
|
|
|
138
141
|
const validation = validateReveniumConfig(config);
|
|
139
142
|
if (!validation.isValid) {
|
|
140
143
|
// Log detailed validation errors
|
|
141
|
-
getLogger().error(
|
|
144
|
+
getLogger().error("Configuration validation failed", {
|
|
142
145
|
errors: validation.errors,
|
|
143
146
|
warnings: validation.warnings,
|
|
144
|
-
suggestions: validation.suggestions
|
|
147
|
+
suggestions: validation.suggestions,
|
|
145
148
|
});
|
|
146
149
|
// Create detailed error message
|
|
147
|
-
let errorMessage =
|
|
150
|
+
let errorMessage = "Configuration validation failed:\n";
|
|
148
151
|
validation.errors.forEach((error, index) => {
|
|
149
152
|
errorMessage += ` ${index + 1}. ${error}\n`;
|
|
150
153
|
});
|
|
151
154
|
if (validation.suggestions && validation.suggestions.length > 0) {
|
|
152
|
-
errorMessage +=
|
|
155
|
+
errorMessage += "\nSuggestions:\n";
|
|
153
156
|
validation.suggestions.forEach((suggestion) => {
|
|
154
157
|
errorMessage += ` • ${suggestion}\n`;
|
|
155
158
|
});
|
|
@@ -158,16 +161,16 @@ export function setConfig(config) {
|
|
|
158
161
|
}
|
|
159
162
|
// Log warnings if any
|
|
160
163
|
if (validation.warnings && validation.warnings.length > 0) {
|
|
161
|
-
getLogger().warn(
|
|
162
|
-
warnings: validation.warnings
|
|
164
|
+
getLogger().warn("Configuration warnings", {
|
|
165
|
+
warnings: validation.warnings,
|
|
163
166
|
});
|
|
164
167
|
}
|
|
165
168
|
// Use the normalized config from validation (with defaults applied and fields trimmed)
|
|
166
169
|
globalConfig = validation.config;
|
|
167
|
-
globalLogger.debug(
|
|
170
|
+
globalLogger.debug("Revenium configuration updated", {
|
|
168
171
|
baseUrl: globalConfig.reveniumBaseUrl,
|
|
169
172
|
hasApiKey: !!globalConfig.reveniumApiKey,
|
|
170
|
-
hasAnthropicKey: !!globalConfig.anthropicApiKey
|
|
173
|
+
hasAnthropicKey: !!globalConfig.anthropicApiKey,
|
|
171
174
|
});
|
|
172
175
|
}
|
|
173
176
|
/**
|
|
@@ -181,7 +184,7 @@ export function getLogger() {
|
|
|
181
184
|
*/
|
|
182
185
|
export function setLogger(logger) {
|
|
183
186
|
globalLogger = logger;
|
|
184
|
-
globalLogger.debug(
|
|
187
|
+
globalLogger.debug("Custom logger set for Revenium middleware");
|
|
185
188
|
}
|
|
186
189
|
/**
|
|
187
190
|
* Initialize configuration from environment variables
|
|
@@ -192,12 +195,12 @@ export function initializeConfig() {
|
|
|
192
195
|
if (config) {
|
|
193
196
|
try {
|
|
194
197
|
setConfig(config);
|
|
195
|
-
globalLogger.debug(
|
|
198
|
+
globalLogger.debug("Revenium middleware initialized from environment variables");
|
|
196
199
|
return true;
|
|
197
200
|
}
|
|
198
201
|
catch (error) {
|
|
199
|
-
globalLogger.error(
|
|
200
|
-
error: error instanceof Error ? error.message : String(error)
|
|
202
|
+
globalLogger.error("Failed to initialize Revenium configuration", {
|
|
203
|
+
error: error instanceof Error ? error.message : String(error),
|
|
201
204
|
});
|
|
202
205
|
return false;
|
|
203
206
|
}
|
|
@@ -218,14 +221,14 @@ export function getConfigStatus() {
|
|
|
218
221
|
hasConfig: false,
|
|
219
222
|
hasApiKey: false,
|
|
220
223
|
hasAnthropicKey: false,
|
|
221
|
-
baseUrl:
|
|
224
|
+
baseUrl: "",
|
|
222
225
|
};
|
|
223
226
|
}
|
|
224
227
|
return {
|
|
225
228
|
hasConfig: true,
|
|
226
229
|
hasApiKey: !!globalConfig.reveniumApiKey,
|
|
227
230
|
hasAnthropicKey: !!globalConfig.anthropicApiKey,
|
|
228
|
-
baseUrl: globalConfig.reveniumBaseUrl
|
|
231
|
+
baseUrl: globalConfig.reveniumBaseUrl,
|
|
229
232
|
};
|
|
230
233
|
}
|
|
231
234
|
/**
|
package/dist/esm/constants.js
CHANGED
|
@@ -22,6 +22,10 @@ export const DEFAULT_CONFIG = {
|
|
|
22
22
|
MAX_RETRY_ATTEMPTS: 10,
|
|
23
23
|
/** Warning threshold for low API timeout */
|
|
24
24
|
LOW_TIMEOUT_WARNING_THRESHOLD: 3000,
|
|
25
|
+
/** Default prompt capture behavior */
|
|
26
|
+
CAPTURE_PROMPTS: false,
|
|
27
|
+
/** Maximum size for each prompt field in characters (50KB) */
|
|
28
|
+
MAX_PROMPT_SIZE: 50000,
|
|
25
29
|
};
|
|
26
30
|
/**
|
|
27
31
|
* Circuit breaker configuration constants
|
|
@@ -113,6 +117,8 @@ export const ENV_VARS = {
|
|
|
113
117
|
PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY",
|
|
114
118
|
/** Team ID for cost metrics retrieval */
|
|
115
119
|
TEAM_ID: "REVENIUM_TEAM_ID",
|
|
120
|
+
/** Prompt capture mode */
|
|
121
|
+
CAPTURE_PROMPTS: "REVENIUM_CAPTURE_PROMPTS",
|
|
116
122
|
};
|
|
117
123
|
/**
|
|
118
124
|
* Summary printer configuration
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { DEFAULT_CONFIG } from "../constants.js";
|
|
2
|
+
import { getConfig } from "../config.js";
|
|
3
|
+
function sanitizeCredentials(text) {
|
|
4
|
+
const patterns = [
|
|
5
|
+
{
|
|
6
|
+
regex: /sk-proj-[a-zA-Z0-9_-]{48,}/g,
|
|
7
|
+
replacement: "sk-proj-***REDACTED***",
|
|
8
|
+
},
|
|
9
|
+
{ regex: /sk-[a-zA-Z0-9_-]{20,}/g, replacement: "sk-***REDACTED***" },
|
|
10
|
+
{
|
|
11
|
+
regex: /Bearer\s+[a-zA-Z0-9_\-\.]+/gi,
|
|
12
|
+
replacement: "Bearer ***REDACTED***",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
regex: /api[_-]?key["\s:=]+[a-zA-Z0-9_\-\.\+\/=]{20,}/gi,
|
|
16
|
+
replacement: "api_key: ***REDACTED***",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
regex: /token["\s:=]+[a-zA-Z0-9_\-\.]{20,}/gi,
|
|
20
|
+
replacement: "token: ***REDACTED***",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
regex: /password["\s:=]+[^\s"']{8,}/gi,
|
|
24
|
+
replacement: "password: ***REDACTED***",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
let sanitized = text;
|
|
28
|
+
for (const pattern of patterns) {
|
|
29
|
+
sanitized = sanitized.replace(pattern.regex, pattern.replacement);
|
|
30
|
+
}
|
|
31
|
+
return sanitized;
|
|
32
|
+
}
|
|
33
|
+
function truncateString(str, maxLength) {
|
|
34
|
+
const sanitized = sanitizeCredentials(str);
|
|
35
|
+
if (sanitized.length <= maxLength) {
|
|
36
|
+
return { value: sanitized, truncated: false };
|
|
37
|
+
}
|
|
38
|
+
return { value: sanitized.substring(0, maxLength), truncated: true };
|
|
39
|
+
}
|
|
40
|
+
function extractSystemPrompt(params) {
|
|
41
|
+
if (!params.system) {
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
if (typeof params.system === "string") {
|
|
45
|
+
return params.system;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(params.system)) {
|
|
48
|
+
return params.system
|
|
49
|
+
.map((block) => {
|
|
50
|
+
if (block.type === "text") {
|
|
51
|
+
return block.text;
|
|
52
|
+
}
|
|
53
|
+
if (block.type === "image") {
|
|
54
|
+
return "[IMAGE]";
|
|
55
|
+
}
|
|
56
|
+
return "";
|
|
57
|
+
})
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.join("\n");
|
|
60
|
+
}
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
function extractInputMessages(params) {
|
|
64
|
+
if (!params.messages || params.messages.length === 0) {
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
return params.messages
|
|
68
|
+
.map((message) => {
|
|
69
|
+
const role = message.role;
|
|
70
|
+
let content = "";
|
|
71
|
+
if (typeof message.content === "string") {
|
|
72
|
+
content = message.content;
|
|
73
|
+
}
|
|
74
|
+
else if (Array.isArray(message.content)) {
|
|
75
|
+
content = message.content
|
|
76
|
+
.map((block) => {
|
|
77
|
+
if (block.type === "text") {
|
|
78
|
+
return block.text;
|
|
79
|
+
}
|
|
80
|
+
if (block.type === "image") {
|
|
81
|
+
return "[IMAGE]";
|
|
82
|
+
}
|
|
83
|
+
if (block.type === "tool_use") {
|
|
84
|
+
const toolName = block.name || "unknown";
|
|
85
|
+
return `[TOOL_USE: ${toolName}]`;
|
|
86
|
+
}
|
|
87
|
+
if (block.type === "tool_result") {
|
|
88
|
+
return "[TOOL_RESULT]";
|
|
89
|
+
}
|
|
90
|
+
return "";
|
|
91
|
+
})
|
|
92
|
+
.filter(Boolean)
|
|
93
|
+
.join("\n");
|
|
94
|
+
}
|
|
95
|
+
return `[${role}]\n${content}`;
|
|
96
|
+
})
|
|
97
|
+
.join("\n\n");
|
|
98
|
+
}
|
|
99
|
+
function extractOutputResponse(response) {
|
|
100
|
+
if (!response.content || response.content.length === 0) {
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
return response.content
|
|
104
|
+
.map((block) => {
|
|
105
|
+
if (block.type === "text") {
|
|
106
|
+
return block.text;
|
|
107
|
+
}
|
|
108
|
+
if (block.type === "tool_use") {
|
|
109
|
+
return `[TOOL_USE: ${block.name}]`;
|
|
110
|
+
}
|
|
111
|
+
return "";
|
|
112
|
+
})
|
|
113
|
+
.filter(Boolean)
|
|
114
|
+
.join("\n");
|
|
115
|
+
}
|
|
116
|
+
export function shouldCapturePrompts(metadata) {
|
|
117
|
+
if (metadata?.capturePrompts !== undefined) {
|
|
118
|
+
return metadata.capturePrompts;
|
|
119
|
+
}
|
|
120
|
+
const config = getConfig();
|
|
121
|
+
if (config?.capturePrompts !== undefined) {
|
|
122
|
+
return config.capturePrompts;
|
|
123
|
+
}
|
|
124
|
+
return DEFAULT_CONFIG.CAPTURE_PROMPTS;
|
|
125
|
+
}
|
|
126
|
+
export function extractPrompts(params, response, metadata) {
|
|
127
|
+
if (!shouldCapturePrompts(metadata)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const maxSize = DEFAULT_CONFIG.MAX_PROMPT_SIZE;
|
|
131
|
+
let anyTruncated = false;
|
|
132
|
+
const systemPromptRaw = extractSystemPrompt(params);
|
|
133
|
+
const systemPromptResult = truncateString(systemPromptRaw, maxSize);
|
|
134
|
+
anyTruncated = anyTruncated || systemPromptResult.truncated;
|
|
135
|
+
const inputMessagesRaw = extractInputMessages(params);
|
|
136
|
+
const inputMessagesResult = truncateString(inputMessagesRaw, maxSize);
|
|
137
|
+
anyTruncated = anyTruncated || inputMessagesResult.truncated;
|
|
138
|
+
const outputResponseRaw = extractOutputResponse(response);
|
|
139
|
+
const outputResponseResult = truncateString(outputResponseRaw, maxSize);
|
|
140
|
+
anyTruncated = anyTruncated || outputResponseResult.truncated;
|
|
141
|
+
const hasAnyContent = systemPromptResult.value ||
|
|
142
|
+
inputMessagesResult.value ||
|
|
143
|
+
outputResponseResult.value;
|
|
144
|
+
if (!hasAnyContent) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
systemPrompt: systemPromptResult.value || undefined,
|
|
149
|
+
inputMessages: inputMessagesResult.value || undefined,
|
|
150
|
+
outputResponse: outputResponseResult.value || undefined,
|
|
151
|
+
promptsTruncated: anyTruncated,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=prompt-extraction.js.map
|
package/dist/types/config.d.ts
CHANGED
|
@@ -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
|
|
@@ -113,6 +117,8 @@ export declare const ENV_VARS: {
|
|
|
113
117
|
readonly PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY";
|
|
114
118
|
/** Team ID for cost metrics retrieval */
|
|
115
119
|
readonly TEAM_ID: "REVENIUM_TEAM_ID";
|
|
120
|
+
/** Prompt capture mode */
|
|
121
|
+
readonly CAPTURE_PROMPTS: "REVENIUM_CAPTURE_PROMPTS";
|
|
116
122
|
};
|
|
117
123
|
/**
|
|
118
124
|
* Summary printer configuration
|
package/dist/types/types.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface ReveniumConfig {
|
|
|
47
47
|
printSummary?: boolean | SummaryFormat;
|
|
48
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
49
|
teamId?: string;
|
|
50
|
+
/** Whether to capture prompts and responses for analysis (default: false) */
|
|
51
|
+
capturePrompts?: boolean;
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Usage metadata for enhanced tracking and analytics
|
|
@@ -68,6 +70,8 @@ export interface UsageMetadata {
|
|
|
68
70
|
agent?: string;
|
|
69
71
|
/** Quality score of AI response (0.0-1.0) for performance tracking */
|
|
70
72
|
responseQualityScore?: number;
|
|
73
|
+
/** Whether to capture prompts and responses for this request (overrides global config) */
|
|
74
|
+
capturePrompts?: boolean;
|
|
71
75
|
/** Allow additional custom fields for extensibility */
|
|
72
76
|
[key: string]: unknown;
|
|
73
77
|
}
|
|
@@ -328,8 +332,14 @@ export interface AnthropicMessageParams {
|
|
|
328
332
|
stream?: boolean;
|
|
329
333
|
/** Sequences that will stop generation */
|
|
330
334
|
stop_sequences?: string[];
|
|
331
|
-
/** System message to set context */
|
|
332
|
-
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
|
+
}>;
|
|
333
343
|
/** Available tools for function calling */
|
|
334
344
|
tools?: AnthropicTool[];
|
|
335
345
|
/** Tool usage configuration */
|
|
@@ -469,6 +479,7 @@ export interface EnvironmentConfig {
|
|
|
469
479
|
maxRetries?: string;
|
|
470
480
|
printSummary?: string;
|
|
471
481
|
teamId?: string;
|
|
482
|
+
capturePrompts?: string;
|
|
472
483
|
}
|
|
473
484
|
/**
|
|
474
485
|
* Summary output format options
|
|
@@ -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
|
package/package.json
CHANGED