@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/cjs/constants.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Centralizes all magic numbers and default values
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ANTHROPIC_PATTERNS = exports.API_ENDPOINTS = exports.ENV_VARS = exports.LOGGING_CONFIG = exports.VALIDATION_CONFIG = exports.RETRY_CONFIG = exports.CIRCUIT_BREAKER_CONFIG = exports.DEFAULT_CONFIG = void 0;
|
|
7
|
+
exports.ANTHROPIC_PATTERNS = exports.API_ENDPOINTS = exports.SUMMARY_PRINTER_CONFIG = exports.ENV_VARS = exports.LOGGING_CONFIG = exports.VALIDATION_CONFIG = exports.RETRY_CONFIG = exports.CIRCUIT_BREAKER_CONFIG = exports.DEFAULT_CONFIG = void 0;
|
|
8
8
|
/**
|
|
9
9
|
* Default configuration values
|
|
10
10
|
*/
|
|
11
11
|
exports.DEFAULT_CONFIG = {
|
|
12
12
|
/** Default Revenium API base URL */
|
|
13
|
-
REVENIUM_BASE_URL:
|
|
13
|
+
REVENIUM_BASE_URL: "https://api.revenium.ai",
|
|
14
14
|
/** Default API timeout in milliseconds */
|
|
15
15
|
API_TIMEOUT: 5000,
|
|
16
16
|
/** Default maximum retries for failed API calls */
|
|
@@ -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
|
|
@@ -63,9 +67,9 @@ exports.VALIDATION_CONFIG = {
|
|
|
63
67
|
/** Minimum API key length */
|
|
64
68
|
MIN_API_KEY_LENGTH: 20,
|
|
65
69
|
/** Required API key prefix for Revenium */
|
|
66
|
-
REVENIUM_API_KEY_PREFIX:
|
|
70
|
+
REVENIUM_API_KEY_PREFIX: "hak_",
|
|
67
71
|
/** Required API key prefix for Anthropic */
|
|
68
|
-
ANTHROPIC_API_KEY_PREFIX:
|
|
72
|
+
ANTHROPIC_API_KEY_PREFIX: "sk-ant-",
|
|
69
73
|
/** Maximum tokens warning threshold */
|
|
70
74
|
HIGH_MAX_TOKENS_THRESHOLD: 4096,
|
|
71
75
|
/** Temperature range */
|
|
@@ -86,39 +90,56 @@ exports.VALIDATION_CONFIG = {
|
|
|
86
90
|
*/
|
|
87
91
|
exports.LOGGING_CONFIG = {
|
|
88
92
|
/** Middleware name for log prefixes */
|
|
89
|
-
MIDDLEWARE_NAME:
|
|
93
|
+
MIDDLEWARE_NAME: "Revenium",
|
|
90
94
|
/** User agent string for API requests */
|
|
91
|
-
USER_AGENT:
|
|
95
|
+
USER_AGENT: "revenium-middleware-anthropic-node/1.0.0",
|
|
92
96
|
/** Debug environment variable name */
|
|
93
|
-
DEBUG_ENV_VAR:
|
|
97
|
+
DEBUG_ENV_VAR: "REVENIUM_DEBUG",
|
|
94
98
|
};
|
|
95
99
|
/**
|
|
96
100
|
* Environment variable names
|
|
97
101
|
*/
|
|
98
102
|
exports.ENV_VARS = {
|
|
99
103
|
/** Revenium API key */
|
|
100
|
-
REVENIUM_API_KEY:
|
|
104
|
+
REVENIUM_API_KEY: "REVENIUM_METERING_API_KEY",
|
|
101
105
|
/** Revenium base URL */
|
|
102
|
-
REVENIUM_BASE_URL:
|
|
106
|
+
REVENIUM_BASE_URL: "REVENIUM_METERING_BASE_URL",
|
|
103
107
|
/** Anthropic API key */
|
|
104
|
-
ANTHROPIC_API_KEY:
|
|
108
|
+
ANTHROPIC_API_KEY: "ANTHROPIC_API_KEY",
|
|
105
109
|
/** Debug mode */
|
|
106
|
-
DEBUG:
|
|
110
|
+
DEBUG: "REVENIUM_DEBUG",
|
|
107
111
|
/** Log level */
|
|
108
|
-
LOG_LEVEL:
|
|
112
|
+
LOG_LEVEL: "REVENIUM_LOG_LEVEL",
|
|
109
113
|
/** API timeout */
|
|
110
|
-
API_TIMEOUT:
|
|
114
|
+
API_TIMEOUT: "REVENIUM_API_TIMEOUT",
|
|
111
115
|
/** Fail silent mode */
|
|
112
|
-
FAIL_SILENT:
|
|
116
|
+
FAIL_SILENT: "REVENIUM_FAIL_SILENT",
|
|
113
117
|
/** Maximum retries */
|
|
114
|
-
MAX_RETRIES:
|
|
118
|
+
MAX_RETRIES: "REVENIUM_MAX_RETRIES",
|
|
119
|
+
/** Print summary mode (true/false/human/json) */
|
|
120
|
+
PRINT_SUMMARY: "REVENIUM_PRINT_SUMMARY",
|
|
121
|
+
/** Team ID for cost metrics retrieval */
|
|
122
|
+
TEAM_ID: "REVENIUM_TEAM_ID",
|
|
123
|
+
/** Prompt capture mode */
|
|
124
|
+
CAPTURE_PROMPTS: "REVENIUM_CAPTURE_PROMPTS",
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Summary printer configuration
|
|
128
|
+
*/
|
|
129
|
+
exports.SUMMARY_PRINTER_CONFIG = {
|
|
130
|
+
/** Maximum number of retries when fetching cost metrics */
|
|
131
|
+
MAX_RETRIES: 3,
|
|
132
|
+
/** Delay between retries in milliseconds */
|
|
133
|
+
RETRY_DELAY: 2000,
|
|
134
|
+
/** Fetch timeout in milliseconds (prevents hung requests from keeping Node process alive) */
|
|
135
|
+
FETCH_TIMEOUT: 10000,
|
|
115
136
|
};
|
|
116
137
|
/**
|
|
117
138
|
* API endpoints
|
|
118
139
|
*/
|
|
119
140
|
exports.API_ENDPOINTS = {
|
|
120
141
|
/** Revenium AI completions endpoint */
|
|
121
|
-
AI_COMPLETIONS:
|
|
142
|
+
AI_COMPLETIONS: "/meter/v2/ai/completions",
|
|
122
143
|
};
|
|
123
144
|
/**
|
|
124
145
|
* Anthropic model patterns
|
|
@@ -128,17 +149,17 @@ exports.ANTHROPIC_PATTERNS = {
|
|
|
128
149
|
CLAUDE_MODEL_PATTERN: /claude/i,
|
|
129
150
|
/** Known Anthropic stop reasons */
|
|
130
151
|
STOP_REASONS: {
|
|
131
|
-
END_TURN:
|
|
132
|
-
MAX_TOKENS:
|
|
133
|
-
STOP_SEQUENCE:
|
|
134
|
-
TOOL_USE:
|
|
152
|
+
END_TURN: "end_turn",
|
|
153
|
+
MAX_TOKENS: "max_tokens",
|
|
154
|
+
STOP_SEQUENCE: "stop_sequence",
|
|
155
|
+
TOOL_USE: "tool_use",
|
|
135
156
|
},
|
|
136
157
|
/** Revenium stop reason mappings */
|
|
137
158
|
REVENIUM_STOP_REASON_MAP: {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
159
|
+
end_turn: "END",
|
|
160
|
+
max_tokens: "TOKEN_LIMIT",
|
|
161
|
+
stop_sequence: "END_SEQUENCE",
|
|
162
|
+
tool_use: "END",
|
|
142
163
|
},
|
|
143
164
|
};
|
|
144
165
|
//# sourceMappingURL=constants.js.map
|
package/dist/cjs/tracking.js
CHANGED
|
@@ -15,8 +15,21 @@ const config_1 = require("./config");
|
|
|
15
15
|
const circuit_breaker_1 = require("./utils/circuit-breaker");
|
|
16
16
|
const error_handling_1 = require("./utils/error-handling");
|
|
17
17
|
const constants_1 = require("./constants");
|
|
18
|
+
const trace_fields_1 = require("./utils/trace-fields");
|
|
19
|
+
const summary_printer_1 = require("./utils/summary-printer");
|
|
18
20
|
// Global logger
|
|
19
21
|
const logger = (0, config_1.getLogger)();
|
|
22
|
+
if (typeof process !== "undefined") {
|
|
23
|
+
process.on("uncaughtException", (error) => {
|
|
24
|
+
if (error.name === "AbortError") {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (error.stack && error.stack.includes("tracking.ts")) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
20
33
|
/**
|
|
21
34
|
* Send tracking data to Revenium API with resilience patterns
|
|
22
35
|
*/
|
|
@@ -34,7 +47,8 @@ async function sendReveniumMetrics(data) {
|
|
|
34
47
|
isStreamed: data.isStreamed,
|
|
35
48
|
});
|
|
36
49
|
// Build payload using exact structure from working implementations
|
|
37
|
-
|
|
50
|
+
// Built early so we can print summary even if Revenium tracking fails
|
|
51
|
+
const payload = await buildReveniumPayload(data);
|
|
38
52
|
// Create request options
|
|
39
53
|
const requestOptions = {
|
|
40
54
|
method: "POST",
|
|
@@ -50,10 +64,6 @@ async function sendReveniumMetrics(data) {
|
|
|
50
64
|
const controller = new AbortController();
|
|
51
65
|
const timeoutId = setTimeout(() => controller.abort(), requestOptions.timeout);
|
|
52
66
|
requestOptions.signal = controller.signal;
|
|
53
|
-
// Handle abort signal errors to prevent unhandled error events
|
|
54
|
-
controller.signal.addEventListener("abort", () => {
|
|
55
|
-
// Silently handle abort - this is expected behavior for timeouts
|
|
56
|
-
});
|
|
57
67
|
try {
|
|
58
68
|
// Execute with circuit breaker and retry logic
|
|
59
69
|
await (0, circuit_breaker_1.executeWithCircuitBreaker)(async () => {
|
|
@@ -66,9 +76,12 @@ async function sendReveniumMetrics(data) {
|
|
|
66
76
|
let response;
|
|
67
77
|
try {
|
|
68
78
|
response = await (0, node_fetch_1.default)(`${config.reveniumBaseUrl}${constants_1.API_ENDPOINTS.AI_COMPLETIONS}`, requestOptions);
|
|
79
|
+
if (response.body) {
|
|
80
|
+
response.body.once("error", () => { });
|
|
81
|
+
response.body.resume();
|
|
82
|
+
}
|
|
69
83
|
}
|
|
70
84
|
catch (fetchError) {
|
|
71
|
-
// Handle AbortError and other fetch errors
|
|
72
85
|
if (fetchError instanceof Error && fetchError.name === "AbortError") {
|
|
73
86
|
throw new Error(`Request timeout after ${requestOptions.timeout}ms`);
|
|
74
87
|
}
|
|
@@ -91,6 +104,17 @@ async function sendReveniumMetrics(data) {
|
|
|
91
104
|
status: response.status,
|
|
92
105
|
duration: data.duration,
|
|
93
106
|
});
|
|
107
|
+
try {
|
|
108
|
+
await response.text();
|
|
109
|
+
}
|
|
110
|
+
catch (bodyError) {
|
|
111
|
+
logger.debug("Error reading response body (non-critical)", {
|
|
112
|
+
requestId,
|
|
113
|
+
error: bodyError instanceof Error
|
|
114
|
+
? bodyError.message
|
|
115
|
+
: String(bodyError),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
94
118
|
return response;
|
|
95
119
|
}, config.maxRetries ?? constants_1.DEFAULT_CONFIG.MAX_RETRIES);
|
|
96
120
|
});
|
|
@@ -111,19 +135,28 @@ async function sendReveniumMetrics(data) {
|
|
|
111
135
|
}
|
|
112
136
|
finally {
|
|
113
137
|
clearTimeout(timeoutId);
|
|
138
|
+
// Print usage summary regardless of whether Revenium tracking succeeded or failed
|
|
139
|
+
// This ensures users see the summary "after each Anthropic API request" as documented
|
|
140
|
+
(0, summary_printer_1.printUsageSummary)(payload);
|
|
114
141
|
}
|
|
115
142
|
}
|
|
116
143
|
/**
|
|
117
144
|
* Build Revenium payload from tracking data
|
|
118
145
|
*/
|
|
119
|
-
function buildReveniumPayload(data) {
|
|
146
|
+
async function buildReveniumPayload(data) {
|
|
120
147
|
const now = new Date().toISOString();
|
|
121
148
|
const requestTime = data.requestTime.toISOString();
|
|
122
149
|
const completionStartTime = data.responseTime.toISOString();
|
|
123
150
|
// Standard known fields
|
|
124
151
|
const knownFields = new Set([
|
|
125
|
-
|
|
126
|
-
|
|
152
|
+
"taskType",
|
|
153
|
+
"agent",
|
|
154
|
+
"organizationId",
|
|
155
|
+
"productId",
|
|
156
|
+
"subscriber",
|
|
157
|
+
"subscriptionId",
|
|
158
|
+
"traceId",
|
|
159
|
+
"responseQualityScore",
|
|
127
160
|
]);
|
|
128
161
|
// Extract custom fields (anything NOT in the standard 8 fields)
|
|
129
162
|
const customFields = {};
|
|
@@ -134,23 +167,26 @@ function buildReveniumPayload(data) {
|
|
|
134
167
|
}
|
|
135
168
|
}
|
|
136
169
|
}
|
|
170
|
+
const environment = (0, trace_fields_1.getEnvironment)();
|
|
171
|
+
const region = await (0, trace_fields_1.getRegion)();
|
|
172
|
+
const credentialAlias = (0, trace_fields_1.getCredentialAlias)();
|
|
173
|
+
const traceType = (0, trace_fields_1.getTraceType)();
|
|
174
|
+
const traceName = (0, trace_fields_1.getTraceName)();
|
|
175
|
+
const parentTransactionId = (0, trace_fields_1.getParentTransactionId)();
|
|
176
|
+
const transactionName = (0, trace_fields_1.getTransactionName)();
|
|
177
|
+
const retryNumber = (0, trace_fields_1.getRetryNumber)();
|
|
178
|
+
const operationSubtype = (0, trace_fields_1.detectOperationSubtype)(data.requestBody);
|
|
137
179
|
return {
|
|
138
180
|
stopReason: getStopReason(data.stopReason),
|
|
139
181
|
costType: "AI",
|
|
140
182
|
isStreamed: data.isStreamed,
|
|
141
|
-
taskType: data.metadata?.taskType,
|
|
142
|
-
agent: data.metadata?.agent,
|
|
143
183
|
operationType: "CHAT",
|
|
144
184
|
inputTokenCount: data.inputTokens,
|
|
145
185
|
outputTokenCount: data.outputTokens,
|
|
146
|
-
reasoningTokenCount: 0,
|
|
186
|
+
reasoningTokenCount: 0,
|
|
147
187
|
cacheCreationTokenCount: data.cacheCreationTokens || 0,
|
|
148
188
|
cacheReadTokenCount: data.cacheReadTokens || 0,
|
|
149
189
|
totalTokenCount: data.inputTokens + data.outputTokens,
|
|
150
|
-
organizationId: data.metadata?.organizationId,
|
|
151
|
-
productId: data.metadata?.productId,
|
|
152
|
-
subscriber: data.metadata?.subscriber, // Pass through nested subscriber object directly
|
|
153
|
-
subscriptionId: data.metadata?.subscriptionId,
|
|
154
190
|
model: data.model,
|
|
155
191
|
transactionId: data.requestId,
|
|
156
192
|
responseTime: now,
|
|
@@ -159,10 +195,31 @@ function buildReveniumPayload(data) {
|
|
|
159
195
|
requestTime: requestTime,
|
|
160
196
|
completionStartTime: completionStartTime,
|
|
161
197
|
timeToFirstToken: data.timeToFirstToken || 0,
|
|
162
|
-
traceId: data.metadata?.traceId,
|
|
163
|
-
responseQualityScore: data.metadata?.responseQualityScore, // Fixed: Now sending to Revenium
|
|
164
198
|
middlewareSource: "nodejs",
|
|
165
|
-
...
|
|
199
|
+
...(data.metadata?.taskType && { taskType: data.metadata.taskType }),
|
|
200
|
+
...(data.metadata?.agent && { agent: data.metadata.agent }),
|
|
201
|
+
...(data.metadata?.organizationId && {
|
|
202
|
+
organizationId: data.metadata.organizationId,
|
|
203
|
+
}),
|
|
204
|
+
...(data.metadata?.productId && { productId: data.metadata.productId }),
|
|
205
|
+
...(data.metadata?.subscriber && { subscriber: data.metadata.subscriber }),
|
|
206
|
+
...(data.metadata?.subscriptionId && {
|
|
207
|
+
subscriptionId: data.metadata.subscriptionId,
|
|
208
|
+
}),
|
|
209
|
+
...(data.metadata?.traceId && { traceId: data.metadata.traceId }),
|
|
210
|
+
...(data.metadata?.responseQualityScore !== undefined && {
|
|
211
|
+
responseQualityScore: data.metadata.responseQualityScore,
|
|
212
|
+
}),
|
|
213
|
+
...(environment && { environment }),
|
|
214
|
+
...(region && { region }),
|
|
215
|
+
...(credentialAlias && { credentialAlias }),
|
|
216
|
+
...(traceType && { traceType }),
|
|
217
|
+
...(traceName && { traceName }),
|
|
218
|
+
...(parentTransactionId && { parentTransactionId }),
|
|
219
|
+
...(transactionName && { transactionName }),
|
|
220
|
+
...(retryNumber !== undefined && { retryNumber }),
|
|
221
|
+
...(operationSubtype && { operationSubtype }),
|
|
222
|
+
...customFields,
|
|
166
223
|
};
|
|
167
224
|
}
|
|
168
225
|
/**
|
|
@@ -184,7 +241,6 @@ function trackUsageAsync(trackingData) {
|
|
|
184
241
|
return logger.warn("Revenium configuration not available - skipping tracking", {
|
|
185
242
|
requestId: trackingData.requestId,
|
|
186
243
|
});
|
|
187
|
-
// Run tracking in background without awaiting
|
|
188
244
|
sendReveniumMetrics(trackingData)
|
|
189
245
|
.then(() => {
|
|
190
246
|
logger.debug("Revenium tracking completed successfully", {
|
|
@@ -194,6 +250,12 @@ function trackUsageAsync(trackingData) {
|
|
|
194
250
|
});
|
|
195
251
|
})
|
|
196
252
|
.catch((error) => {
|
|
253
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
254
|
+
logger.debug("Metrics request aborted (process exiting)", {
|
|
255
|
+
requestId: trackingData.requestId,
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
197
259
|
const errorContext = (0, error_handling_1.createErrorContext)()
|
|
198
260
|
.withRequestId(trackingData.requestId)
|
|
199
261
|
.withModel(trackingData.model)
|
|
@@ -19,68 +19,6 @@
|
|
|
19
19
|
* - **Automatic Validation**: TypeScript validates the structure at compile time
|
|
20
20
|
* - **Better Developer Experience**: Auto-completion and error detection
|
|
21
21
|
*
|
|
22
|
-
* ## Usage Examples:
|
|
23
|
-
*
|
|
24
|
-
* ### Basic Usage:
|
|
25
|
-
* ```typescript
|
|
26
|
-
* import '@revenium/anthropic';
|
|
27
|
-
* import Anthropic from '@anthropic-ai/sdk';
|
|
28
|
-
*
|
|
29
|
-
* const anthropic = new Anthropic();
|
|
30
|
-
*
|
|
31
|
-
* const response = await anthropic.messages.create({
|
|
32
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
33
|
-
* max_tokens: 1024,
|
|
34
|
-
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
35
|
-
* usageMetadata: { // TypeScript recognizes this natively
|
|
36
|
-
* subscriber: { id: 'user-123', email: 'user@example.com' },
|
|
37
|
-
* organizationId: 'my-company',
|
|
38
|
-
* taskType: 'customer-support',
|
|
39
|
-
* traceId: 'session-abc-123'
|
|
40
|
-
* }
|
|
41
|
-
* });
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* ### Streaming Usage:
|
|
45
|
-
* ```typescript
|
|
46
|
-
* const stream = await anthropic.messages.stream({
|
|
47
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
48
|
-
* max_tokens: 1024,
|
|
49
|
-
* messages: [{ role: 'user', content: 'Generate a report' }],
|
|
50
|
-
* usageMetadata: {
|
|
51
|
-
* taskType: 'content-generation',
|
|
52
|
-
* productId: 'report-generator',
|
|
53
|
-
* responseQualityScore: 0.95
|
|
54
|
-
* }
|
|
55
|
-
* });
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* ### Advanced Usage with All Fields:
|
|
59
|
-
* ```typescript
|
|
60
|
-
* const response = await anthropic.messages.create({
|
|
61
|
-
* model: 'claude-3-5-sonnet-latest',
|
|
62
|
-
* max_tokens: 2048,
|
|
63
|
-
* messages: [{ role: 'user', content: 'Complex analysis task' }],
|
|
64
|
-
* usageMetadata: {
|
|
65
|
-
* subscriber: {
|
|
66
|
-
* id: 'user-456',
|
|
67
|
-
* email: 'analyst@company.com',
|
|
68
|
-
* credential: { name: 'api-key', value: 'sk-...' }
|
|
69
|
-
* },
|
|
70
|
-
* traceId: 'analysis-session-789',
|
|
71
|
-
* taskType: 'data-analysis',
|
|
72
|
-
* organizationId: 'enterprise-client',
|
|
73
|
-
* subscriptionId: 'premium-plan',
|
|
74
|
-
* productId: 'analytics-suite',
|
|
75
|
-
* agent: 'data-analyst-bot',
|
|
76
|
-
* responseQualityScore: 0.98,
|
|
77
|
-
* customField: 'custom-value' // Extensible with custom fields
|
|
78
|
-
* }
|
|
79
|
-
* });
|
|
80
|
-
* ```
|
|
81
|
-
*
|
|
82
|
-
* @public
|
|
83
|
-
* @since 1.1.0
|
|
84
22
|
*/
|
|
85
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
86
24
|
//# sourceMappingURL=anthropic-augmentation.js.map
|
|
@@ -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
|