@revenium/perplexity 2.0.8 → 2.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/.env.example +18 -1
- package/CHANGELOG.md +42 -0
- package/README.md +223 -37
- package/dist/cjs/core/config/loader.js +22 -1
- package/dist/cjs/core/config/loader.js.map +1 -1
- package/dist/cjs/core/config/manager.js +9 -0
- package/dist/cjs/core/config/manager.js.map +1 -1
- package/dist/cjs/core/middleware/interfaces.js +38 -1
- package/dist/cjs/core/middleware/interfaces.js.map +1 -1
- package/dist/cjs/core/middleware/streaming-wrapper.js +67 -2
- package/dist/cjs/core/middleware/streaming-wrapper.js.map +1 -1
- package/dist/cjs/core/tracking/api-client.js +2 -0
- package/dist/cjs/core/tracking/api-client.js.map +1 -1
- package/dist/cjs/core/tracking/payload-builder.js +28 -1
- package/dist/cjs/core/tracking/payload-builder.js.map +1 -1
- package/dist/cjs/core/tracking/usage-tracker.js +9 -6
- package/dist/cjs/core/tracking/usage-tracker.js.map +1 -1
- package/dist/cjs/utils/prompt-extraction.js +194 -0
- package/dist/cjs/utils/prompt-extraction.js.map +1 -0
- package/dist/cjs/utils/summary-printer.js +237 -0
- package/dist/cjs/utils/summary-printer.js.map +1 -0
- package/dist/cjs/utils/trace-fields.js +136 -0
- package/dist/cjs/utils/trace-fields.js.map +1 -0
- package/dist/esm/core/config/loader.js +22 -1
- package/dist/esm/core/config/loader.js.map +1 -1
- package/dist/esm/core/config/manager.js +9 -0
- package/dist/esm/core/config/manager.js.map +1 -1
- package/dist/esm/core/middleware/interfaces.js +38 -1
- package/dist/esm/core/middleware/interfaces.js.map +1 -1
- package/dist/esm/core/middleware/streaming-wrapper.js +67 -2
- package/dist/esm/core/middleware/streaming-wrapper.js.map +1 -1
- package/dist/esm/core/tracking/api-client.js +2 -0
- package/dist/esm/core/tracking/api-client.js.map +1 -1
- package/dist/esm/core/tracking/payload-builder.js +28 -1
- package/dist/esm/core/tracking/payload-builder.js.map +1 -1
- package/dist/esm/core/tracking/usage-tracker.js +9 -6
- package/dist/esm/core/tracking/usage-tracker.js.map +1 -1
- package/dist/esm/utils/prompt-extraction.js +188 -0
- package/dist/esm/utils/prompt-extraction.js.map +1 -0
- package/dist/esm/utils/summary-printer.js +233 -0
- package/dist/esm/utils/summary-printer.js.map +1 -0
- package/dist/esm/utils/trace-fields.js +121 -0
- package/dist/esm/utils/trace-fields.js.map +1 -0
- package/dist/types/core/config/loader.d.ts.map +1 -1
- package/dist/types/core/config/manager.d.ts.map +1 -1
- package/dist/types/core/middleware/interfaces.d.ts.map +1 -1
- package/dist/types/core/middleware/streaming-wrapper.d.ts +9 -1
- package/dist/types/core/middleware/streaming-wrapper.d.ts.map +1 -1
- package/dist/types/core/tracking/api-client.d.ts.map +1 -1
- package/dist/types/core/tracking/payload-builder.d.ts +1 -1
- package/dist/types/core/tracking/payload-builder.d.ts.map +1 -1
- package/dist/types/core/tracking/usage-tracker.d.ts +8 -0
- package/dist/types/core/tracking/usage-tracker.d.ts.map +1 -1
- package/dist/types/types/function-parameters.d.ts +7 -0
- package/dist/types/types/function-parameters.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +24 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utils/prompt-extraction.d.ts +29 -0
- package/dist/types/utils/prompt-extraction.d.ts.map +1 -0
- package/dist/types/utils/summary-printer.d.ts +23 -0
- package/dist/types/utils/summary-printer.d.ts.map +1 -0
- package/dist/types/utils/trace-fields.d.ts +11 -0
- package/dist/types/utils/trace-fields.d.ts.map +1 -0
- package/examples/prompt-capture.ts +108 -0
- package/package.json +5 -2
package/.env.example
CHANGED
|
@@ -6,5 +6,22 @@ REVENIUM_METERING_BASE_URL=https://api.revenium.ai
|
|
|
6
6
|
PERPLEXITY_API_KEY=pplx_your_perplexity_api_key_here
|
|
7
7
|
PERPLEXITY_API_BASE_URL=https://api.perplexity.ai
|
|
8
8
|
|
|
9
|
+
# Trace Visualization Fields (Optional)
|
|
10
|
+
REVENIUM_ENVIRONMENT=production
|
|
11
|
+
REVENIUM_REGION=us-east-1
|
|
12
|
+
REVENIUM_CREDENTIAL_ALIAS=Perplexity Production Key
|
|
13
|
+
REVENIUM_TRACE_TYPE=customer_support
|
|
14
|
+
REVENIUM_TRACE_NAME=Support Ticket #12345
|
|
15
|
+
REVENIUM_PARENT_TRANSACTION_ID=parent-txn-123
|
|
16
|
+
REVENIUM_TRANSACTION_NAME=Answer Customer Question
|
|
17
|
+
REVENIUM_RETRY_NUMBER=0
|
|
18
|
+
|
|
9
19
|
# Debug Configuration (Optional)
|
|
10
|
-
REVENIUM_DEBUG=false
|
|
20
|
+
REVENIUM_DEBUG=false
|
|
21
|
+
|
|
22
|
+
# Prompt Capture Configuration (Optional)
|
|
23
|
+
# REVENIUM_CAPTURE_PROMPTS=false
|
|
24
|
+
# REVENIUM_MAX_PROMPT_SIZE=50000
|
|
25
|
+
|
|
26
|
+
# AWS Region Detection (Optional - auto-detected if not set)
|
|
27
|
+
AWS_REGION=us-east-1
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.0] - 2026-01-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Prompt capture functionality with automatic credential sanitization
|
|
13
|
+
- New prompt capture fields in ReveniumPayload: systemPrompt, inputMessages, outputResponse, promptsTruncated
|
|
14
|
+
- Configuration options: capturePrompts (boolean), maxPromptSize (number, default: 50000)
|
|
15
|
+
- Environment variables: REVENIUM_CAPTURE_PROMPTS, REVENIUM_MAX_PROMPT_SIZE
|
|
16
|
+
- Per-call override via usageMetadata.capturePrompts
|
|
17
|
+
- Comprehensive credential sanitization with 13 patterns:
|
|
18
|
+
- Perplexity API keys (pplx-\*)
|
|
19
|
+
- OpenAI keys (sk-_, sk-proj-_, sk-ant-\*)
|
|
20
|
+
- AWS access keys (AKIA\*)
|
|
21
|
+
- GitHub tokens (ghp*\*, ghs*\*)
|
|
22
|
+
- JWT tokens (eyJ*.eyJ*.\*)
|
|
23
|
+
- Bearer tokens
|
|
24
|
+
- Generic API keys, tokens, passwords, secrets
|
|
25
|
+
- Automatic truncation of prompts exceeding maxPromptSize with truncation flag
|
|
26
|
+
|
|
27
|
+
### Security
|
|
28
|
+
|
|
29
|
+
- All captured prompts are automatically sanitized to remove sensitive credentials
|
|
30
|
+
- Credential patterns are redacted before transmission to Revenium API
|
|
31
|
+
- Prompt capture is opt-in (disabled by default) for privacy
|
|
32
|
+
|
|
33
|
+
## [2.0.9] - 2026-01-06
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Trace visualization fields support for distributed tracing and analytics
|
|
38
|
+
- New trace fields: environment, region, credentialAlias, traceType, traceName, parentTransactionId, transactionName, retryNumber, operationSubtype
|
|
39
|
+
- Automatic region detection from AWS/Azure/GCP environment variables with fallback to AWS EC2 metadata service
|
|
40
|
+
- Comprehensive unit tests for all trace field functions
|
|
41
|
+
- Jest testing infrastructure with full test coverage
|
|
42
|
+
- Updated .env.example with trace visualization field examples
|
|
43
|
+
- Documentation for trace visualization fields in README.md
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- buildPayload function is now async to support region detection
|
|
48
|
+
- Updated ReveniumPayload interface with trace visualization fields
|
|
49
|
+
|
|
8
50
|
## [2.0.8] - 2025-11-14
|
|
9
51
|
|
|
10
52
|
### Changed
|
package/README.md
CHANGED
|
@@ -84,6 +84,10 @@ REVENIUM_METERING_API_KEY=hak_your_revenium_api_key
|
|
|
84
84
|
|
|
85
85
|
# Optional: Enable debug logging
|
|
86
86
|
# REVENIUM_DEBUG=false
|
|
87
|
+
|
|
88
|
+
# Optional: Terminal cost/metrics summary
|
|
89
|
+
# REVENIUM_PRINT_SUMMARY=true # or 'human' or 'json'
|
|
90
|
+
# REVENIUM_TEAM_ID=your_team_id # Required for cost retrieval
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
**Replace the placeholder values with your actual keys!**
|
|
@@ -200,53 +204,235 @@ The middleware automatically captures comprehensive usage data:
|
|
|
200
204
|
|
|
201
205
|
The following table shows all fields this middleware sends to the Revenium API:
|
|
202
206
|
|
|
203
|
-
| Field
|
|
204
|
-
|
|
205
|
-
| **Core Fields**
|
|
206
|
-
| `model`
|
|
207
|
-
| `provider`
|
|
208
|
-
| `inputTokenCount`
|
|
209
|
-
| `outputTokenCount`
|
|
210
|
-
| `totalTokenCount`
|
|
211
|
-
| `requestDuration`
|
|
212
|
-
| **Timing**
|
|
213
|
-
| `requestTime`
|
|
214
|
-
| `responseTime`
|
|
215
|
-
| `completionStartTime`
|
|
216
|
-
| `timeToFirstToken`
|
|
217
|
-
| **Request Details**
|
|
218
|
-
| `transactionId`
|
|
219
|
-
| `operationType`
|
|
220
|
-
| `stopReason`
|
|
221
|
-
| `isStreamed`
|
|
222
|
-
| `costType`
|
|
223
|
-
| `modelSource`
|
|
224
|
-
| `middlewareSource`
|
|
225
|
-
| **Cost Information**
|
|
226
|
-
| `inputTokenCost`
|
|
227
|
-
| `outputTokenCost`
|
|
228
|
-
| `totalCost`
|
|
229
|
-
| **Business Context**
|
|
230
|
-
| `organizationId`
|
|
231
|
-
| `productId`
|
|
232
|
-
| `subscriptionId`
|
|
233
|
-
| `taskType`
|
|
234
|
-
| `traceId`
|
|
235
|
-
| `agent`
|
|
236
|
-
| `responseQualityScore`
|
|
237
|
-
| `subscriber.id`
|
|
238
|
-
| `subscriber.email`
|
|
239
|
-
| `subscriber.credential` | object
|
|
207
|
+
| Field | Type | Required | Description |
|
|
208
|
+
| ----------------------- | ------- | --------- | -------------------------------------------------- |
|
|
209
|
+
| **Core Fields** | | | |
|
|
210
|
+
| `model` | string | Yes | Perplexity model name (e.g., "sonar-pro") |
|
|
211
|
+
| `provider` | string | Yes | Always "Perplexity" |
|
|
212
|
+
| `inputTokenCount` | integer | Yes | Number of input tokens consumed |
|
|
213
|
+
| `outputTokenCount` | integer | Yes | Number of output tokens generated |
|
|
214
|
+
| `totalTokenCount` | integer | Yes | Total tokens (input + output) |
|
|
215
|
+
| `requestDuration` | integer | Yes | Request duration in milliseconds |
|
|
216
|
+
| **Timing** | | | |
|
|
217
|
+
| `requestTime` | string | Auto | ISO 8601 timestamp when request started |
|
|
218
|
+
| `responseTime` | string | Auto | ISO 8601 timestamp when response completed |
|
|
219
|
+
| `completionStartTime` | string | Auto | ISO 8601 timestamp when completion started |
|
|
220
|
+
| `timeToFirstToken` | integer | Streaming | Time to first token in ms (streaming only) |
|
|
221
|
+
| **Request Details** | | | |
|
|
222
|
+
| `transactionId` | string | Auto | Unique transaction identifier |
|
|
223
|
+
| `operationType` | string | Auto | Always "CHAT" for chat completions |
|
|
224
|
+
| `stopReason` | string | Auto | Completion finish reason ("END", "STOP", etc.) |
|
|
225
|
+
| `isStreamed` | boolean | Auto | Whether response was streamed |
|
|
226
|
+
| `costType` | string | Auto | Always "AI" |
|
|
227
|
+
| `modelSource` | string | Auto | Always "PERPLEXITY" |
|
|
228
|
+
| `middlewareSource` | string | Auto | Always "revenium-perplexity-node" |
|
|
229
|
+
| **Cost Information** | | | |
|
|
230
|
+
| `inputTokenCost` | number | Optional | Cost for input tokens (if provided by Perplexity) |
|
|
231
|
+
| `outputTokenCost` | number | Optional | Cost for output tokens (if provided by Perplexity) |
|
|
232
|
+
| `totalCost` | number | Optional | Total cost (if provided by Perplexity) |
|
|
233
|
+
| **Business Context** | | | |
|
|
234
|
+
| `organizationId` | string | Optional | Your organization identifier |
|
|
235
|
+
| `productId` | string | Optional | Your product identifier |
|
|
236
|
+
| `subscriptionId` | string | Optional | Your subscription identifier |
|
|
237
|
+
| `taskType` | string | Optional | Type of AI task (e.g., "chat", "research") |
|
|
238
|
+
| `traceId` | string | Optional | Session or conversation tracking ID |
|
|
239
|
+
| `agent` | string | Optional | AI agent or bot identifier |
|
|
240
|
+
| `responseQualityScore` | number | Optional | Custom quality rating (0.0-1.0) |
|
|
241
|
+
| `subscriber.id` | string | Optional | User identifier |
|
|
242
|
+
| `subscriber.email` | string | Optional | User email address |
|
|
243
|
+
| `subscriber.credential` | object | Optional | Authentication credential (name, value) |
|
|
240
244
|
|
|
241
245
|
**Notes:**
|
|
246
|
+
|
|
242
247
|
- **Required** fields are always sent with every request
|
|
243
248
|
- **Auto** fields are automatically populated by the middleware
|
|
244
249
|
- **Optional** fields are only sent if you provide them via `usageMetadata`
|
|
245
250
|
- **Streaming** fields are only sent for streaming requests
|
|
246
251
|
|
|
247
252
|
**Reference:**
|
|
253
|
+
|
|
248
254
|
- [API Reference](https://revenium.readme.io/reference/meter_ai_completion) - Complete metadata field documentation
|
|
249
255
|
|
|
256
|
+
## Trace Visualization Fields
|
|
257
|
+
|
|
258
|
+
The middleware automatically captures trace visualization fields for distributed tracing and analytics:
|
|
259
|
+
|
|
260
|
+
| Field | Type | Description | Environment Variable |
|
|
261
|
+
| --------------------- | ------ | ------------------------------------------------------------------------------- | ---------------------------------- |
|
|
262
|
+
| `environment` | string | Deployment environment (production, staging, development) | `REVENIUM_ENVIRONMENT`, `NODE_ENV` |
|
|
263
|
+
| `operationType` | string | Operation classification (CHAT, EMBED, etc.) - automatically detected | N/A (auto-detected) |
|
|
264
|
+
| `operationSubtype` | string | Additional detail (function_call, etc.) - automatically detected | N/A (auto-detected) |
|
|
265
|
+
| `retryNumber` | number | Retry attempt number (0 for first attempt, 1+ for retries) | `REVENIUM_RETRY_NUMBER` |
|
|
266
|
+
| `parentTransactionId` | string | Parent transaction reference for distributed tracing | `REVENIUM_PARENT_TRANSACTION_ID` |
|
|
267
|
+
| `transactionName` | string | Human-friendly operation label | `REVENIUM_TRANSACTION_NAME` |
|
|
268
|
+
| `region` | string | Cloud region (us-east-1, etc.) - auto-detected from AWS/Azure/GCP | `AWS_REGION`, `REVENIUM_REGION` |
|
|
269
|
+
| `credentialAlias` | string | Human-readable credential name | `REVENIUM_CREDENTIAL_ALIAS` |
|
|
270
|
+
| `traceType` | string | Categorical identifier (alphanumeric, hyphens, underscores only, max 128 chars) | `REVENIUM_TRACE_TYPE` |
|
|
271
|
+
| `traceName` | string | Human-readable label for trace instances (max 256 chars) | `REVENIUM_TRACE_NAME` |
|
|
272
|
+
|
|
273
|
+
**All trace visualization fields are optional.** The middleware will automatically detect and populate these fields when possible.
|
|
274
|
+
|
|
275
|
+
### Example Configuration
|
|
276
|
+
|
|
277
|
+
```env
|
|
278
|
+
REVENIUM_ENVIRONMENT=production
|
|
279
|
+
REVENIUM_REGION=us-east-1
|
|
280
|
+
REVENIUM_CREDENTIAL_ALIAS=Perplexity Production Key
|
|
281
|
+
REVENIUM_TRACE_TYPE=customer_support
|
|
282
|
+
REVENIUM_TRACE_NAME=Support Ticket #12345
|
|
283
|
+
REVENIUM_PARENT_TRANSACTION_ID=parent-txn-123
|
|
284
|
+
REVENIUM_TRANSACTION_NAME=Answer Customer Question
|
|
285
|
+
REVENIUM_RETRY_NUMBER=0
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
For a complete example, see [`.env.example`](https://github.com/revenium/revenium-middleware-perplexity-node/blob/HEAD/.env.example).
|
|
289
|
+
|
|
290
|
+
## Prompt Capture
|
|
291
|
+
|
|
292
|
+
The middleware can capture prompts and responses for analysis. This feature is **disabled by default** for privacy.
|
|
293
|
+
|
|
294
|
+
### Configuration
|
|
295
|
+
|
|
296
|
+
Enable prompt capture using environment variables, programmatic configuration, or per-call metadata:
|
|
297
|
+
|
|
298
|
+
**Environment Variables:**
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
export REVENIUM_CAPTURE_PROMPTS=true
|
|
302
|
+
export REVENIUM_MAX_PROMPT_SIZE=50000
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Programmatic Configuration:**
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
import { Initialize } from "@revenium/perplexity";
|
|
309
|
+
|
|
310
|
+
Initialize({
|
|
311
|
+
reveniumApiKey: "hak_your_key",
|
|
312
|
+
reveniumBaseUrl: "https://api.revenium.ai",
|
|
313
|
+
perplexityApiKey: "pplx_your_key",
|
|
314
|
+
capturePrompts: true,
|
|
315
|
+
maxPromptSize: 50000,
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Per-Call Override:**
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
const response = await client.chat.completions.create(
|
|
323
|
+
{
|
|
324
|
+
model: "llama-3.1-sonar-small-128k-online",
|
|
325
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
usageMetadata: { capturePrompts: true },
|
|
329
|
+
},
|
|
330
|
+
);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Configuration Priority
|
|
334
|
+
|
|
335
|
+
The middleware uses the following priority order (highest to lowest):
|
|
336
|
+
|
|
337
|
+
1. Per-call `usageMetadata.capturePrompts`
|
|
338
|
+
2. Programmatic `config.capturePrompts`
|
|
339
|
+
3. Environment variable `REVENIUM_CAPTURE_PROMPTS`
|
|
340
|
+
4. Default: `false`
|
|
341
|
+
|
|
342
|
+
### Security
|
|
343
|
+
|
|
344
|
+
All captured prompts are automatically sanitized to remove sensitive credentials:
|
|
345
|
+
|
|
346
|
+
- Perplexity API keys (pplx-\*)
|
|
347
|
+
- OpenAI keys (sk-\*, sk-proj-\*, sk-ant-\*)
|
|
348
|
+
- AWS access keys (AKIA\*)
|
|
349
|
+
- GitHub tokens (ghp*\*, ghs*\*)
|
|
350
|
+
- JWT tokens
|
|
351
|
+
- Bearer tokens
|
|
352
|
+
- Generic API keys, tokens, passwords, secrets
|
|
353
|
+
|
|
354
|
+
Prompts exceeding `maxPromptSize` (default: 50000 characters) are automatically truncated with a flag indicating truncation.
|
|
355
|
+
|
|
356
|
+
## Terminal Cost/Metrics Summary
|
|
357
|
+
|
|
358
|
+
The middleware can print a cost and metrics summary to your terminal after each API request. This is useful for development and debugging.
|
|
359
|
+
|
|
360
|
+
### Configuration
|
|
361
|
+
|
|
362
|
+
Enable terminal summary output using environment variables or programmatic configuration:
|
|
363
|
+
|
|
364
|
+
**Environment Variables:**
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# Enable human-readable summary (default format)
|
|
368
|
+
export REVENIUM_PRINT_SUMMARY=true
|
|
369
|
+
|
|
370
|
+
# Or specify format explicitly
|
|
371
|
+
export REVENIUM_PRINT_SUMMARY=human # Human-readable format
|
|
372
|
+
export REVENIUM_PRINT_SUMMARY=json # JSON format for log parsing
|
|
373
|
+
|
|
374
|
+
# Optional: Set team ID to fetch cost data
|
|
375
|
+
export REVENIUM_TEAM_ID=your_team_id
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Programmatic Configuration:**
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { Initialize } from "@revenium/perplexity";
|
|
382
|
+
|
|
383
|
+
Initialize({
|
|
384
|
+
reveniumApiKey: "hak_your_api_key",
|
|
385
|
+
reveniumBaseUrl: "https://api.revenium.ai",
|
|
386
|
+
perplexityApiKey: "pplx_your_api_key",
|
|
387
|
+
printSummary: true, // or 'human' or 'json'
|
|
388
|
+
teamId: "your_team_id", // Optional: for cost retrieval
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Output Formats
|
|
393
|
+
|
|
394
|
+
**Human-readable format** (`printSummary: true` or `printSummary: 'human'`):
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
============================================================
|
|
398
|
+
📊 REVENIUM USAGE SUMMARY
|
|
399
|
+
============================================================
|
|
400
|
+
🤖 Model: sonar-pro
|
|
401
|
+
🏢 Provider: Perplexity
|
|
402
|
+
⏱️ Duration: 1.23s
|
|
403
|
+
|
|
404
|
+
💬 Token Usage:
|
|
405
|
+
📥 Input Tokens: 150
|
|
406
|
+
📤 Output Tokens: 75
|
|
407
|
+
📊 Total Tokens: 225
|
|
408
|
+
|
|
409
|
+
💰 Cost: $0.004500
|
|
410
|
+
🔖 Trace ID: trace-abc-123
|
|
411
|
+
============================================================
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**JSON format** (`printSummary: 'json'`):
|
|
415
|
+
|
|
416
|
+
```json
|
|
417
|
+
{
|
|
418
|
+
"model": "sonar-pro",
|
|
419
|
+
"provider": "Perplexity",
|
|
420
|
+
"durationSeconds": 1.23,
|
|
421
|
+
"inputTokenCount": 150,
|
|
422
|
+
"outputTokenCount": 75,
|
|
423
|
+
"totalTokenCount": 225,
|
|
424
|
+
"cost": 0.0045,
|
|
425
|
+
"traceId": "trace-abc-123"
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Cost Retrieval
|
|
430
|
+
|
|
431
|
+
- **Without `teamId`**: Shows token counts and duration, displays hint to set `REVENIUM_TEAM_ID`
|
|
432
|
+
- **With `teamId`**: Fetches actual cost from Revenium API with automatic retry logic
|
|
433
|
+
- **Cost pending**: Shows "(pending aggregation)" if cost data isn't available yet
|
|
434
|
+
- **Fire-and-forget**: Never blocks your application, even if cost fetch fails
|
|
435
|
+
|
|
250
436
|
## API Overview
|
|
251
437
|
|
|
252
438
|
- **`Initialize(config?)`** - Initialize the middleware (from environment or explicit config)
|
|
@@ -33,16 +33,37 @@ function loadConfigFromEnv() {
|
|
|
33
33
|
const perplexityApiKey = process.env.PERPLEXITY_API_KEY;
|
|
34
34
|
const perplexityBaseUrl = process.env.PERPLEXITY_API_BASE_URL || DEFAULT_PERPLEXITY_BASE_URL;
|
|
35
35
|
const debug = process.env.REVENIUM_DEBUG === "true";
|
|
36
|
+
let printSummary = undefined;
|
|
37
|
+
const printSummaryEnv = process.env.REVENIUM_PRINT_SUMMARY;
|
|
38
|
+
if (printSummaryEnv) {
|
|
39
|
+
if (printSummaryEnv === "true") {
|
|
40
|
+
printSummary = true;
|
|
41
|
+
}
|
|
42
|
+
else if (printSummaryEnv === "false") {
|
|
43
|
+
printSummary = false;
|
|
44
|
+
}
|
|
45
|
+
else if (printSummaryEnv === "human" || printSummaryEnv === "json") {
|
|
46
|
+
printSummary = printSummaryEnv;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const teamId = process.env.REVENIUM_TEAM_ID;
|
|
50
|
+
const capturePromptsEnv = process.env.REVENIUM_CAPTURE_PROMPTS;
|
|
36
51
|
if (!reveniumApiKey)
|
|
37
52
|
return null;
|
|
38
53
|
if (!perplexityApiKey)
|
|
39
54
|
return null;
|
|
40
|
-
|
|
55
|
+
const config = {
|
|
41
56
|
reveniumApiKey,
|
|
42
57
|
reveniumBaseUrl,
|
|
43
58
|
perplexityApiKey,
|
|
44
59
|
perplexityBaseUrl,
|
|
45
60
|
debug,
|
|
61
|
+
printSummary,
|
|
62
|
+
teamId,
|
|
46
63
|
};
|
|
64
|
+
if (capturePromptsEnv !== undefined) {
|
|
65
|
+
config.capturePrompts = capturePromptsEnv.toLowerCase() === "true";
|
|
66
|
+
}
|
|
67
|
+
return config;
|
|
47
68
|
}
|
|
48
69
|
//# sourceMappingURL=loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/core/config/loader.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAoBH,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/core/config/loader.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAoBH,8CAkDC;AAnED,mCAA8C;AAE9C;;GAEG;AACH,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAC5D,MAAM,2BAA2B,GAAG,2BAA2B,CAAC;AAEhE;;GAEG;AACH,IAAI,aAAa,GAAG,KAAK,CAAC;AAE1B;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAA,eAAU,GAAE,CAAC;QACb,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,MAAM,cAAc,GAClB,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACxE,MAAM,eAAe,GACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACtC,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC7B,yBAAyB,CAAC;IAC5B,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACxD,MAAM,iBAAiB,GACrB,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,2BAA2B,CAAC;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,CAAC;IAEpD,IAAI,YAAY,GAA2C,SAAS,CAAC;IACrE,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAC3D,IAAI,eAAe,EAAE,CAAC;QACpB,IAAI,eAAe,KAAK,MAAM,EAAE,CAAC;YAC/B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;aAAM,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;YACvC,YAAY,GAAG,KAAK,CAAC;QACvB,CAAC;aAAM,IAAI,eAAe,KAAK,OAAO,IAAI,eAAe,KAAK,MAAM,EAAE,CAAC;YACrE,YAAY,GAAG,eAAe,CAAC;QACjC,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAE/D,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,MAAM,GAAQ;QAClB,cAAc;QACd,eAAe;QACf,gBAAgB;QAChB,iBAAiB;QACjB,KAAK;QACL,YAAY;QACZ,MAAM;KACP,CAAC;IAEF,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,cAAc,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;IACrE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -12,6 +12,7 @@ exports.getLogger = getLogger;
|
|
|
12
12
|
exports.initializeConfig = initializeConfig;
|
|
13
13
|
const loader_js_1 = require("./loader.js");
|
|
14
14
|
const validator_js_1 = require("./validator.js");
|
|
15
|
+
const summary_printer_js_1 = require("../../utils/summary-printer.js");
|
|
15
16
|
/**
|
|
16
17
|
* Global configuration instance
|
|
17
18
|
*/
|
|
@@ -52,6 +53,14 @@ function setConfig(config) {
|
|
|
52
53
|
baseUrl: config.reveniumBaseUrl,
|
|
53
54
|
hasReveniumKey: !!config.reveniumApiKey,
|
|
54
55
|
hasPerplexityKey: !!config.perplexityApiKey,
|
|
56
|
+
printSummary: config.printSummary,
|
|
57
|
+
teamId: config.teamId,
|
|
58
|
+
});
|
|
59
|
+
(0, summary_printer_js_1.setConfig)({
|
|
60
|
+
reveniumApiKey: config.reveniumApiKey,
|
|
61
|
+
reveniumBaseUrl: config.reveniumBaseUrl,
|
|
62
|
+
teamId: config.teamId,
|
|
63
|
+
printSummary: config.printSummary,
|
|
55
64
|
});
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../src/core/config/manager.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../src/core/config/manager.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAqCH,8BAEC;AAKD,8BAiBC;AAKD,8BAEC;AAKD,4CAkBC;AAxFD,2CAAgD;AAChD,iDAAgD;AAChD,uEAAsF;AAEtF;;GAEG;AACH,IAAI,YAAY,GAA0B,IAAI,CAAC;AAE/C;;GAEG;AACU,QAAA,aAAa,GAAW;IACnC,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;QAC7C,IAAI,YAAY,EAAE,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,EAAE,CAAC;YACjE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IACD,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;QAC5C,OAAO,CAAC,IAAI,CAAC,cAAc,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;QAC5C,OAAO,CAAC,IAAI,CAAC,sBAAsB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IACzD,CAAC;IACD,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAe,EAAE,EAAE;QAC7C,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;CACF,CAAC;AAEF,IAAI,YAAY,GAAW,qBAAa,CAAC;AAEzC;;GAEG;AACH,SAAgB,SAAS;IACvB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAgB,SAAS,CAAC,MAAsB;IAC9C,IAAA,6BAAc,EAAC,MAAM,CAAC,CAAC;IACvB,YAAY,GAAG,MAAM,CAAC;IACtB,YAAY,CAAC,KAAK,CAAC,gCAAgC,EAAE;QACnD,OAAO,EAAE,MAAM,CAAC,eAAe;QAC/B,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc;QACvC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,gBAAgB;QAC3C,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAC;IAEH,IAAA,8BAAuB,EAAC;QACtB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,SAAS;IACvB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB;IAC9B,MAAM,SAAS,GAAG,IAAA,6BAAiB,GAAE,CAAC;IAEtC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,YAAY,CAAC,KAAK,CAChB,iHAAiH,CAClH,CAAC;QACF,MAAM,IAAI,KAAK,CACb,iHAAiH,CAClH,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,YAAY,CAAC,KAAK,CAChB,4DAA4D,CAC7D,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -8,6 +8,7 @@ const config_1 = require("../config");
|
|
|
8
8
|
const transaction_id_js_1 = require("../../utils/transaction-id.js");
|
|
9
9
|
const index_js_1 = require("../tracking/index.js");
|
|
10
10
|
const streaming_wrapper_js_1 = require("./streaming-wrapper.js");
|
|
11
|
+
const prompt_extraction_js_1 = require("../../utils/prompt-extraction.js");
|
|
11
12
|
const logger = (0, config_1.getLogger)();
|
|
12
13
|
/**
|
|
13
14
|
* Chat interface - provides access to chat completions
|
|
@@ -48,6 +49,9 @@ class CompletionsInterface {
|
|
|
48
49
|
if ("usage" in response && response.usage) {
|
|
49
50
|
// Extract cost if available (Perplexity-specific)
|
|
50
51
|
const usage = response.usage;
|
|
52
|
+
const responseContent = "choices" in response
|
|
53
|
+
? response.choices[0]?.message?.content || undefined
|
|
54
|
+
: undefined;
|
|
51
55
|
(0, index_js_1.trackUsageAsync)({
|
|
52
56
|
requestId: ("id" in response ? response.id : null) || transactionId,
|
|
53
57
|
model: params.model,
|
|
@@ -61,12 +65,31 @@ class CompletionsInterface {
|
|
|
61
65
|
usageMetadata: metadata,
|
|
62
66
|
isStreamed: false,
|
|
63
67
|
cost: usage.cost,
|
|
68
|
+
responseFormat: params.response_format,
|
|
69
|
+
messages: params.messages,
|
|
70
|
+
responseContent: responseContent
|
|
71
|
+
? (0, prompt_extraction_js_1.sanitizeCredentials)(responseContent)
|
|
72
|
+
: undefined,
|
|
64
73
|
});
|
|
65
74
|
}
|
|
66
75
|
return response;
|
|
67
76
|
}
|
|
68
77
|
catch (error) {
|
|
69
78
|
logger.error(`[Revenium] Error in chat completion: ${error.message}`);
|
|
79
|
+
const endTime = Date.now();
|
|
80
|
+
const duration = endTime - startTime.getTime();
|
|
81
|
+
(0, index_js_1.trackUsageAsync)({
|
|
82
|
+
requestId: transactionId,
|
|
83
|
+
model: params.model,
|
|
84
|
+
promptTokens: 0,
|
|
85
|
+
completionTokens: 0,
|
|
86
|
+
totalTokens: 0,
|
|
87
|
+
duration,
|
|
88
|
+
finishReason: "error",
|
|
89
|
+
usageMetadata: metadata,
|
|
90
|
+
isStreamed: false,
|
|
91
|
+
messages: params.messages,
|
|
92
|
+
});
|
|
70
93
|
throw error;
|
|
71
94
|
}
|
|
72
95
|
}
|
|
@@ -82,10 +105,24 @@ class CompletionsInterface {
|
|
|
82
105
|
...params,
|
|
83
106
|
stream: true,
|
|
84
107
|
});
|
|
85
|
-
return new streaming_wrapper_js_1.StreamingWrapper(stream, params.model, startTime, transactionId, metadata, this.config);
|
|
108
|
+
return new streaming_wrapper_js_1.StreamingWrapper(stream, params.model, startTime, transactionId, metadata, this.config, params.response_format, params.messages);
|
|
86
109
|
}
|
|
87
110
|
catch (error) {
|
|
88
111
|
logger.error(`[Revenium] Error in streaming chat completion: ${error.message}`);
|
|
112
|
+
const endTime = Date.now();
|
|
113
|
+
const duration = endTime - startTime.getTime();
|
|
114
|
+
(0, index_js_1.trackUsageAsync)({
|
|
115
|
+
requestId: transactionId,
|
|
116
|
+
model: params.model,
|
|
117
|
+
promptTokens: 0,
|
|
118
|
+
completionTokens: 0,
|
|
119
|
+
totalTokens: 0,
|
|
120
|
+
duration,
|
|
121
|
+
finishReason: "error",
|
|
122
|
+
usageMetadata: metadata,
|
|
123
|
+
isStreamed: true,
|
|
124
|
+
messages: params.messages,
|
|
125
|
+
});
|
|
89
126
|
throw error;
|
|
90
127
|
}
|
|
91
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../../src/core/middleware/interfaces.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAIH,sCAAsC;AACtC,qEAAsE;AACtE,mDAAuD;AACvD,iEAA0D;
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../../src/core/middleware/interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,18 +6,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.StreamingWrapper = void 0;
|
|
7
7
|
const config_1 = require("../config");
|
|
8
8
|
const tracking_1 = require("../tracking");
|
|
9
|
+
const prompt_extraction_js_1 = require("../../utils/prompt-extraction.js");
|
|
9
10
|
const logger = (0, config_1.getLogger)();
|
|
10
11
|
/**
|
|
11
12
|
* Wrapper for streaming responses that tracks usage
|
|
12
13
|
*/
|
|
13
14
|
class StreamingWrapper {
|
|
14
|
-
constructor(stream, model, startTime, transactionId, metadata, config) {
|
|
15
|
+
constructor(stream, model, startTime, transactionId, metadata, config, responseFormat, messages) {
|
|
16
|
+
this.accumulatedContent = "";
|
|
15
17
|
this.stream = stream;
|
|
16
18
|
this.model = model;
|
|
17
19
|
this.startTime = startTime;
|
|
18
20
|
this.transactionId = transactionId;
|
|
19
21
|
this.metadata = metadata;
|
|
20
22
|
this.config = config || {};
|
|
23
|
+
this.responseFormat = responseFormat;
|
|
24
|
+
this.messages = messages || [];
|
|
21
25
|
}
|
|
22
26
|
/**
|
|
23
27
|
* Iterate over stream chunks
|
|
@@ -30,6 +34,7 @@ class StreamingWrapper {
|
|
|
30
34
|
let costData = undefined;
|
|
31
35
|
let firstChunkTime = null;
|
|
32
36
|
let timeToFirstToken = 0;
|
|
37
|
+
let completed = false;
|
|
33
38
|
try {
|
|
34
39
|
for await (const chunk of this.stream) {
|
|
35
40
|
// Capture time of first chunk
|
|
@@ -39,6 +44,14 @@ class StreamingWrapper {
|
|
|
39
44
|
firstChunkTime.getTime() - this.startTime.getTime();
|
|
40
45
|
}
|
|
41
46
|
lastChunk = chunk;
|
|
47
|
+
if (chunk.choices?.[0]?.delta?.content &&
|
|
48
|
+
(0, prompt_extraction_js_1.shouldCapturePrompts)(this.metadata)) {
|
|
49
|
+
const maxSize = (0, prompt_extraction_js_1.getMaxPromptSize)();
|
|
50
|
+
const remaining = maxSize - this.accumulatedContent.length;
|
|
51
|
+
if (remaining > 0) {
|
|
52
|
+
this.accumulatedContent += chunk.choices[0].delta.content.slice(0, remaining);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
42
55
|
// Track usage if available in chunk
|
|
43
56
|
if (chunk.usage) {
|
|
44
57
|
inputTokens = chunk.usage.prompt_tokens || 0;
|
|
@@ -51,6 +64,7 @@ class StreamingWrapper {
|
|
|
51
64
|
}
|
|
52
65
|
yield chunk;
|
|
53
66
|
}
|
|
67
|
+
completed = true;
|
|
54
68
|
// Send metering data when stream completes (fire-and-forget)
|
|
55
69
|
const endTime = Date.now();
|
|
56
70
|
const duration = endTime - this.startTime.getTime();
|
|
@@ -67,13 +81,64 @@ class StreamingWrapper {
|
|
|
67
81
|
isStreamed: true,
|
|
68
82
|
timeToFirstToken,
|
|
69
83
|
cost: costData,
|
|
84
|
+
responseFormat: this.responseFormat,
|
|
85
|
+
messages: this.messages,
|
|
86
|
+
responseContent: this.accumulatedContent
|
|
87
|
+
? (0, prompt_extraction_js_1.sanitizeCredentials)(this.accumulatedContent)
|
|
88
|
+
: undefined,
|
|
70
89
|
});
|
|
71
90
|
}
|
|
72
91
|
catch (error) {
|
|
73
|
-
|
|
92
|
+
completed = true;
|
|
74
93
|
logger.error("[Revenium] Error in stream processing:", error.message);
|
|
94
|
+
const endTime = Date.now();
|
|
95
|
+
const duration = endTime - this.startTime.getTime();
|
|
96
|
+
(0, tracking_1.trackUsageAsync)({
|
|
97
|
+
requestId: this.transactionId,
|
|
98
|
+
model: this.model,
|
|
99
|
+
promptTokens: inputTokens,
|
|
100
|
+
completionTokens: outputTokens,
|
|
101
|
+
totalTokens,
|
|
102
|
+
duration,
|
|
103
|
+
finishReason: "error",
|
|
104
|
+
usageMetadata: this.metadata,
|
|
105
|
+
isStreamed: true,
|
|
106
|
+
messages: this.messages,
|
|
107
|
+
responseContent: this.accumulatedContent
|
|
108
|
+
? (0, prompt_extraction_js_1.sanitizeCredentials)(this.accumulatedContent)
|
|
109
|
+
: undefined,
|
|
110
|
+
});
|
|
75
111
|
throw error;
|
|
76
112
|
}
|
|
113
|
+
finally {
|
|
114
|
+
if (!completed) {
|
|
115
|
+
const endTime = Date.now();
|
|
116
|
+
const duration = endTime - this.startTime.getTime();
|
|
117
|
+
(0, tracking_1.trackUsageAsync)({
|
|
118
|
+
requestId: this.transactionId,
|
|
119
|
+
model: this.model,
|
|
120
|
+
promptTokens: inputTokens,
|
|
121
|
+
completionTokens: outputTokens,
|
|
122
|
+
totalTokens,
|
|
123
|
+
duration,
|
|
124
|
+
finishReason: "cancelled",
|
|
125
|
+
usageMetadata: this.metadata,
|
|
126
|
+
isStreamed: true,
|
|
127
|
+
timeToFirstToken,
|
|
128
|
+
cost: costData,
|
|
129
|
+
responseFormat: this.responseFormat,
|
|
130
|
+
messages: this.messages,
|
|
131
|
+
responseContent: this.accumulatedContent
|
|
132
|
+
? (0, prompt_extraction_js_1.sanitizeCredentials)(this.accumulatedContent)
|
|
133
|
+
: undefined,
|
|
134
|
+
});
|
|
135
|
+
logger.debug("[Revenium] Streaming cancelled", {
|
|
136
|
+
requestId: this.transactionId,
|
|
137
|
+
model: this.model,
|
|
138
|
+
duration,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
77
142
|
}
|
|
78
143
|
}
|
|
79
144
|
exports.StreamingWrapper = StreamingWrapper;
|