@revenium/perplexity 2.0.4 → 2.0.5
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 +32 -33
- package/README.md +120 -101
- package/SECURITY.md +34 -0
- package/dist/cjs/constants/models.js +38 -0
- package/dist/cjs/constants/models.js.map +1 -0
- package/dist/cjs/core/client/index.js +13 -0
- package/dist/cjs/core/client/index.js.map +1 -0
- package/dist/cjs/core/client/manager.js +85 -0
- package/dist/cjs/core/client/manager.js.map +1 -0
- package/dist/cjs/core/config/index.js +21 -0
- package/dist/cjs/core/config/index.js.map +1 -0
- package/dist/cjs/core/config/loader.js +48 -0
- package/dist/cjs/core/config/loader.js.map +1 -0
- package/dist/cjs/core/config/manager.js +77 -0
- package/dist/cjs/core/config/manager.js.map +1 -0
- package/dist/cjs/core/config/validator.js +45 -0
- package/dist/cjs/core/config/validator.js.map +1 -0
- package/dist/cjs/core/middleware/index.js +14 -0
- package/dist/cjs/core/middleware/index.js.map +1 -0
- package/dist/cjs/core/middleware/interfaces.js +94 -0
- package/dist/cjs/core/middleware/interfaces.js.map +1 -0
- package/dist/cjs/core/middleware/revenium-client.js +44 -0
- package/dist/cjs/core/middleware/revenium-client.js.map +1 -0
- package/dist/cjs/core/middleware/streaming-wrapper.js +80 -0
- package/dist/cjs/core/middleware/streaming-wrapper.js.map +1 -0
- package/dist/cjs/core/providers/detector.js +38 -0
- package/dist/cjs/core/providers/detector.js.map +1 -0
- package/dist/cjs/core/providers/index.js +14 -0
- package/dist/cjs/core/providers/index.js.map +1 -0
- package/dist/cjs/core/tracking/api-client.js +67 -0
- package/dist/cjs/core/tracking/api-client.js.map +1 -0
- package/dist/cjs/core/tracking/index.js +21 -0
- package/dist/cjs/core/tracking/index.js.map +1 -0
- package/dist/cjs/core/tracking/payload-builder.js +95 -0
- package/dist/cjs/core/tracking/payload-builder.js.map +1 -0
- package/dist/cjs/core/tracking/usage-tracker.js +83 -0
- package/dist/cjs/core/tracking/usage-tracker.js.map +1 -0
- package/dist/cjs/index.js +60 -59
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/function-parameters.js +14 -0
- package/dist/cjs/types/function-parameters.js.map +1 -0
- package/dist/cjs/types/index.js +20 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/utils/constants.js +20 -0
- package/dist/cjs/utils/constants.js.map +1 -0
- package/dist/cjs/utils/error-handler.js +194 -0
- package/dist/cjs/utils/error-handler.js.map +1 -0
- package/dist/cjs/utils/metadata-builder.js +191 -0
- package/dist/cjs/utils/metadata-builder.js.map +1 -0
- package/dist/cjs/utils/stop-reason-mapper.js +74 -0
- package/dist/cjs/utils/stop-reason-mapper.js.map +1 -0
- package/dist/cjs/utils/transaction-id.js +19 -0
- package/dist/cjs/utils/transaction-id.js.map +1 -0
- package/dist/cjs/utils/url-builder.js +57 -0
- package/dist/cjs/utils/url-builder.js.map +1 -0
- package/dist/esm/constants/models.js +35 -0
- package/dist/esm/constants/models.js.map +1 -0
- package/dist/esm/core/client/index.js +5 -0
- package/dist/esm/core/client/index.js.map +1 -0
- package/dist/esm/core/client/manager.js +78 -0
- package/dist/esm/core/client/manager.js.map +1 -0
- package/dist/esm/core/config/index.js +11 -0
- package/dist/esm/core/config/index.js.map +1 -0
- package/dist/esm/core/config/loader.js +45 -0
- package/dist/esm/core/config/loader.js.map +1 -0
- package/dist/esm/core/config/manager.js +70 -0
- package/dist/esm/core/config/manager.js.map +1 -0
- package/dist/esm/core/config/validator.js +42 -0
- package/dist/esm/core/config/validator.js.map +1 -0
- package/dist/esm/core/middleware/index.js +7 -0
- package/dist/esm/core/middleware/index.js.map +1 -0
- package/dist/esm/core/middleware/interfaces.js +89 -0
- package/dist/esm/core/middleware/interfaces.js.map +1 -0
- package/dist/esm/core/middleware/revenium-client.js +37 -0
- package/dist/esm/core/middleware/revenium-client.js.map +1 -0
- package/dist/esm/core/middleware/streaming-wrapper.js +76 -0
- package/dist/esm/core/middleware/streaming-wrapper.js.map +1 -0
- package/dist/esm/core/providers/detector.js +34 -0
- package/dist/esm/core/providers/detector.js.map +1 -0
- package/dist/esm/core/providers/index.js +9 -0
- package/dist/esm/core/providers/index.js.map +1 -0
- package/dist/esm/core/tracking/api-client.js +64 -0
- package/dist/esm/core/tracking/api-client.js.map +1 -0
- package/dist/esm/core/tracking/index.js +13 -0
- package/dist/esm/core/tracking/index.js.map +1 -0
- package/dist/esm/core/tracking/payload-builder.js +92 -0
- package/dist/esm/core/tracking/payload-builder.js.map +1 -0
- package/dist/esm/core/tracking/usage-tracker.js +79 -0
- package/dist/esm/core/tracking/usage-tracker.js.map +1 -0
- package/dist/esm/index.js +46 -39
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/function-parameters.js +13 -0
- package/dist/esm/types/function-parameters.js.map +1 -0
- package/dist/esm/types/index.js +6 -2
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/utils/constants.js +17 -0
- package/dist/esm/utils/constants.js.map +1 -0
- package/dist/esm/utils/error-handler.js +182 -0
- package/dist/esm/utils/error-handler.js.map +1 -0
- package/dist/esm/utils/metadata-builder.js +183 -0
- package/dist/esm/utils/metadata-builder.js.map +1 -0
- package/dist/esm/utils/stop-reason-mapper.js +69 -0
- package/dist/esm/utils/stop-reason-mapper.js.map +1 -0
- package/dist/esm/utils/transaction-id.js +16 -0
- package/dist/esm/utils/transaction-id.js.map +1 -0
- package/dist/esm/utils/url-builder.js +53 -0
- package/dist/esm/utils/url-builder.js.map +1 -0
- package/dist/types/constants/models.d.ts +39 -0
- package/dist/types/constants/models.d.ts.map +1 -0
- package/dist/types/core/client/index.d.ts +5 -0
- package/dist/types/core/client/index.d.ts.map +1 -0
- package/dist/types/core/client/manager.d.ts +44 -0
- package/dist/types/core/client/manager.d.ts.map +1 -0
- package/dist/types/core/config/index.d.ts +10 -0
- package/dist/types/core/config/index.d.ts.map +1 -0
- package/dist/types/core/config/loader.d.ts +13 -0
- package/dist/types/core/config/loader.d.ts.map +1 -0
- package/dist/types/core/config/manager.d.ts +28 -0
- package/dist/types/core/config/manager.d.ts.map +1 -0
- package/dist/types/core/config/validator.d.ts +12 -0
- package/dist/types/core/config/validator.d.ts.map +1 -0
- package/dist/types/core/middleware/index.d.ts +7 -0
- package/dist/types/core/middleware/index.d.ts.map +1 -0
- package/dist/types/core/middleware/interfaces.d.ts +35 -0
- package/dist/types/core/middleware/interfaces.d.ts.map +1 -0
- package/dist/types/core/middleware/revenium-client.d.ts +25 -0
- package/dist/types/core/middleware/revenium-client.d.ts.map +1 -0
- package/dist/types/core/middleware/streaming-wrapper.d.ts +21 -0
- package/dist/types/core/middleware/streaming-wrapper.d.ts.map +1 -0
- package/dist/types/core/providers/detector.d.ts +24 -0
- package/dist/types/core/providers/detector.d.ts.map +1 -0
- package/dist/types/core/providers/index.d.ts +8 -0
- package/dist/types/core/providers/index.d.ts.map +1 -0
- package/dist/types/core/tracking/api-client.d.ts +17 -0
- package/dist/types/core/tracking/api-client.d.ts.map +1 -0
- package/dist/types/core/tracking/index.d.ts +11 -0
- package/dist/types/core/tracking/index.d.ts.map +1 -0
- package/dist/types/core/tracking/payload-builder.d.ts +24 -0
- package/dist/types/core/tracking/payload-builder.d.ts.map +1 -0
- package/dist/types/core/tracking/usage-tracker.d.ts +30 -0
- package/dist/types/core/tracking/usage-tracker.d.ts.map +1 -0
- package/dist/types/index.d.ts +56 -27
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types/function-parameters.d.ts +185 -0
- package/dist/types/types/function-parameters.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +108 -129
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utils/constants.d.ts +9 -0
- package/dist/types/utils/constants.d.ts.map +1 -0
- package/dist/types/utils/error-handler.d.ts +95 -0
- package/dist/types/utils/error-handler.d.ts.map +1 -0
- package/dist/types/utils/metadata-builder.d.ts +65 -0
- package/dist/types/utils/metadata-builder.d.ts.map +1 -0
- package/dist/types/utils/stop-reason-mapper.d.ts +29 -0
- package/dist/types/utils/stop-reason-mapper.d.ts.map +1 -0
- package/dist/types/utils/transaction-id.d.ts +14 -0
- package/dist/types/utils/transaction-id.d.ts.map +1 -0
- package/dist/types/utils/url-builder.d.ts +22 -0
- package/dist/types/utils/url-builder.d.ts.map +1 -0
- package/examples/README.md +124 -220
- package/examples/advanced.ts +123 -0
- package/examples/basic.ts +32 -37
- package/examples/getting_started.ts +26 -49
- package/examples/metadata.ts +51 -48
- package/examples/stream.ts +53 -0
- package/package.json +9 -10
- package/dist/cjs/constants.js +0 -70
- package/dist/cjs/constants.js.map +0 -1
- package/dist/cjs/core/config/perplexity-config.js +0 -45
- package/dist/cjs/core/config/perplexity-config.js.map +0 -1
- package/dist/cjs/core/config/revenium-config.js +0 -80
- package/dist/cjs/core/config/revenium-config.js.map +0 -1
- package/dist/cjs/core/tracking/metering.js +0 -211
- package/dist/cjs/core/tracking/metering.js.map +0 -1
- package/dist/cjs/core/wrapper/perplexity-client.js +0 -187
- package/dist/cjs/core/wrapper/perplexity-client.js.map +0 -1
- package/dist/cjs/utils/logger.js +0 -23
- package/dist/cjs/utils/logger.js.map +0 -1
- package/dist/esm/constants.js +0 -67
- package/dist/esm/constants.js.map +0 -1
- package/dist/esm/core/config/perplexity-config.js +0 -40
- package/dist/esm/core/config/perplexity-config.js.map +0 -1
- package/dist/esm/core/config/revenium-config.js +0 -72
- package/dist/esm/core/config/revenium-config.js.map +0 -1
- package/dist/esm/core/tracking/metering.js +0 -206
- package/dist/esm/core/tracking/metering.js.map +0 -1
- package/dist/esm/core/wrapper/perplexity-client.js +0 -180
- package/dist/esm/core/wrapper/perplexity-client.js.map +0 -1
- package/dist/esm/utils/logger.js +0 -20
- package/dist/esm/utils/logger.js.map +0 -1
- package/dist/types/constants.d.ts +0 -67
- package/dist/types/constants.d.ts.map +0 -1
- package/dist/types/core/config/perplexity-config.d.ts +0 -24
- package/dist/types/core/config/perplexity-config.d.ts.map +0 -1
- package/dist/types/core/config/revenium-config.d.ts +0 -37
- package/dist/types/core/config/revenium-config.d.ts.map +0 -1
- package/dist/types/core/tracking/metering.d.ts +0 -31
- package/dist/types/core/tracking/metering.d.ts.map +0 -1
- package/dist/types/core/wrapper/perplexity-client.d.ts +0 -32
- package/dist/types/core/wrapper/perplexity-client.d.ts.map +0 -1
- package/dist/types/utils/logger.d.ts +0 -10
- package/dist/types/utils/logger.d.ts.map +0 -1
- package/examples/advanced-features.ts +0 -148
- package/examples/chat.ts +0 -73
- package/examples/streaming.ts +0 -50
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Validator Module
|
|
3
|
+
*
|
|
4
|
+
* Handles validation of configuration objects.
|
|
5
|
+
* Separated from loading and management for single responsibility.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate Revenium configuration
|
|
9
|
+
*/
|
|
10
|
+
export function validateConfig(config) {
|
|
11
|
+
if (!config.reveniumApiKey) {
|
|
12
|
+
throw new Error("Revenium API key is required. Set REVENIUM_METERING_API_KEY environment variable or provide reveniumApiKey in config.");
|
|
13
|
+
}
|
|
14
|
+
if (!config.reveniumApiKey.startsWith("hak_")) {
|
|
15
|
+
throw new Error('Invalid Revenium API key format. Revenium API keys should start with "hak_"');
|
|
16
|
+
}
|
|
17
|
+
// Validate Revenium URL format (base URL should always be provided by loader with default)
|
|
18
|
+
if (config.reveniumBaseUrl) {
|
|
19
|
+
try {
|
|
20
|
+
new URL(config.reveniumBaseUrl);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new Error(`Invalid Revenium base URL format: ${config.reveniumBaseUrl}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!config.perplexityApiKey) {
|
|
27
|
+
throw new Error("Perplexity API key is required. Set PERPLEXITY_API_KEY environment variable or provide perplexityApiKey in config.");
|
|
28
|
+
}
|
|
29
|
+
if (!config.perplexityApiKey.startsWith("pplx-")) {
|
|
30
|
+
throw new Error('Invalid Perplexity API key format. Perplexity API keys should start with "pplx-"');
|
|
31
|
+
}
|
|
32
|
+
// Validate Perplexity URL format (base URL should always be provided by loader with default)
|
|
33
|
+
if (config.perplexityBaseUrl) {
|
|
34
|
+
try {
|
|
35
|
+
new URL(config.perplexityBaseUrl);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new Error(`Invalid Perplexity base URL format: ${config.perplexityBaseUrl}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../../src/core/config/validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,uHAAuH,CACxH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IAED,2FAA2F;IAC3F,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,qCAAqC,MAAM,CAAC,eAAe,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,oHAAoH,CACrH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAC;IACJ,CAAC;IAED,6FAA6F;IAC7F,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,uCAAuC,MAAM,CAAC,iBAAiB,EAAE,CAClE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware module exports
|
|
3
|
+
*/
|
|
4
|
+
export { ReveniumPerplexity } from "./revenium-client.js";
|
|
5
|
+
export { ChatInterface, CompletionsInterface } from "./interfaces.js";
|
|
6
|
+
export { StreamingWrapper } from "./streaming-wrapper.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/middleware/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware interfaces for Perplexity API
|
|
3
|
+
*/
|
|
4
|
+
import { getLogger } from "../config/index.js";
|
|
5
|
+
import { generateTransactionId } from "../../utils/transaction-id.js";
|
|
6
|
+
import { trackUsageAsync } from "../tracking/index.js";
|
|
7
|
+
import { StreamingWrapper } from "./streaming-wrapper.js";
|
|
8
|
+
const logger = getLogger();
|
|
9
|
+
/**
|
|
10
|
+
* Chat interface - provides access to chat completions
|
|
11
|
+
*/
|
|
12
|
+
export class ChatInterface {
|
|
13
|
+
constructor(client, config) {
|
|
14
|
+
this.client = client;
|
|
15
|
+
this.config = config;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get completions interface
|
|
19
|
+
*/
|
|
20
|
+
completions() {
|
|
21
|
+
return new CompletionsInterface(this.client, this.config);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Completions interface - handles chat completion requests
|
|
26
|
+
*/
|
|
27
|
+
export class CompletionsInterface {
|
|
28
|
+
constructor(client, config) {
|
|
29
|
+
this.client = client;
|
|
30
|
+
this.config = config;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create a chat completion
|
|
34
|
+
*/
|
|
35
|
+
async create(params, metadata) {
|
|
36
|
+
const startTime = new Date();
|
|
37
|
+
const transactionId = generateTransactionId();
|
|
38
|
+
try {
|
|
39
|
+
logger.debug(`[Revenium] Creating chat completion with model: ${params.model}`);
|
|
40
|
+
const response = await this.client.chat.completions.create(params);
|
|
41
|
+
const endTime = Date.now();
|
|
42
|
+
const duration = endTime - startTime.getTime();
|
|
43
|
+
// Track usage asynchronously (fire-and-forget - errors handled internally)
|
|
44
|
+
if ("usage" in response && response.usage) {
|
|
45
|
+
// Extract cost if available (Perplexity-specific)
|
|
46
|
+
const usage = response.usage;
|
|
47
|
+
trackUsageAsync({
|
|
48
|
+
requestId: ("id" in response ? response.id : null) || transactionId,
|
|
49
|
+
model: params.model,
|
|
50
|
+
promptTokens: response.usage.prompt_tokens,
|
|
51
|
+
completionTokens: response.usage.completion_tokens,
|
|
52
|
+
totalTokens: response.usage.total_tokens,
|
|
53
|
+
duration,
|
|
54
|
+
finishReason: "choices" in response
|
|
55
|
+
? response.choices[0]?.finish_reason || null
|
|
56
|
+
: null,
|
|
57
|
+
usageMetadata: metadata,
|
|
58
|
+
isStreamed: false,
|
|
59
|
+
cost: usage.cost,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return response;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
logger.error(`[Revenium] Error in chat completion: ${error.message}`);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a streaming chat completion
|
|
71
|
+
*/
|
|
72
|
+
async createStreaming(params, metadata) {
|
|
73
|
+
const startTime = new Date();
|
|
74
|
+
const transactionId = generateTransactionId();
|
|
75
|
+
try {
|
|
76
|
+
logger.debug(`[Revenium] Creating streaming chat completion with model: ${params.model}`);
|
|
77
|
+
const stream = await this.client.chat.completions.create({
|
|
78
|
+
...params,
|
|
79
|
+
stream: true,
|
|
80
|
+
});
|
|
81
|
+
return new StreamingWrapper(stream, params.model, startTime, transactionId, metadata, this.config);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error(`[Revenium] Error in streaming chat completion: ${error.message}`);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=interfaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../../src/core/middleware/interfaces.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B;;GAEG;AACH,MAAM,OAAO,aAAa;IACxB,YAAoB,MAAc,EAAU,MAAW;QAAnC,WAAM,GAAN,MAAM,CAAQ;QAAU,WAAM,GAAN,MAAM,CAAK;IAAG,CAAC;IAE3D;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,oBAAoB;IAC/B,YAAoB,MAAc,EAAU,MAAW;QAAnC,WAAM,GAAN,MAAM,CAAQ;QAAU,WAAM,GAAN,MAAM,CAAK;IAAG,CAAC;IAE3D;;OAEG;IACH,KAAK,CAAC,MAAM,CACV,MAA8C,EAC9C,QAAwB;QAExB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,qBAAqB,EAAE,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,CACV,mDAAmD,MAAM,CAAC,KAAK,EAAE,CAClE,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAEnE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;YAE/C,2EAA2E;YAC3E,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAC1C,kDAAkD;gBAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAY,CAAC;gBAEpC,eAAe,CAAC;oBACd,SAAS,EAAE,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,aAAa;oBACnE,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;oBAC1C,gBAAgB,EAAE,QAAQ,CAAC,KAAK,CAAC,iBAAiB;oBAClD,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY;oBACxC,QAAQ;oBACR,YAAY,EACV,SAAS,IAAI,QAAQ;wBACnB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,IAAI;wBAC5C,CAAC,CAAC,IAAI;oBACV,aAAa,EAAE,QAAQ;oBACvB,UAAU,EAAE,KAAK;oBACjB,IAAI,EAAE,KAAK,CAAC,IAAI;iBACjB,CAAC,CAAC;YACL,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,wCAAwC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACtE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CACnB,MAA8C,EAC9C,QAAwB;QAExB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,qBAAqB,EAAE,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,CACV,6DAA6D,MAAM,CAAC,KAAK,EAAE,CAC5E,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACvD,GAAG,MAAM;gBACT,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YAEH,OAAO,IAAI,gBAAgB,CACzB,MAAa,EACb,MAAM,CAAC,KAAK,EACZ,SAAS,EACT,aAAa,EACb,QAAQ,EACR,IAAI,CAAC,MAAM,CACZ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,KAAK,CACV,kDAAkD,KAAK,CAAC,OAAO,EAAE,CAClE,CAAC;YACF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Revenium Perplexity Client
|
|
3
|
+
*
|
|
4
|
+
* Main client class that wraps Perplexity API with Revenium tracking
|
|
5
|
+
*/
|
|
6
|
+
import OpenAI from "openai";
|
|
7
|
+
import { ChatInterface } from "./interfaces.js";
|
|
8
|
+
/**
|
|
9
|
+
* Revenium Perplexity client with usage tracking
|
|
10
|
+
*/
|
|
11
|
+
export class ReveniumPerplexity {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.client = new OpenAI({
|
|
15
|
+
apiKey: config.perplexityApiKey,
|
|
16
|
+
baseURL: config.perplexityBaseUrl,
|
|
17
|
+
});
|
|
18
|
+
if (config.debug) {
|
|
19
|
+
console.log("[Revenium] Perplexity client created", {
|
|
20
|
+
baseURL: config.perplexityBaseUrl,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get chat interface
|
|
26
|
+
*/
|
|
27
|
+
chat() {
|
|
28
|
+
return new ChatInterface(this.client, this.config);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get underlying OpenAI client (for advanced use cases)
|
|
32
|
+
*/
|
|
33
|
+
getUnderlyingClient() {
|
|
34
|
+
return this.client;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=revenium-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revenium-client.js","sourceRoot":"","sources":["../../../../src/core/middleware/revenium-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAI7B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC,gBAAgB;YAC/B,OAAO,EAAE,MAAM,CAAC,iBAAiB;SAClC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,sCAAsC,EAAE;gBAClD,OAAO,EAAE,MAAM,CAAC,iBAAiB;aAClC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming wrapper for Perplexity API
|
|
3
|
+
*/
|
|
4
|
+
import { getLogger } from "../config/index.js";
|
|
5
|
+
import { trackUsageAsync } from "../tracking/index.js";
|
|
6
|
+
const logger = getLogger();
|
|
7
|
+
/**
|
|
8
|
+
* Wrapper for streaming responses that tracks usage
|
|
9
|
+
*/
|
|
10
|
+
export class StreamingWrapper {
|
|
11
|
+
constructor(stream, model, startTime, transactionId, metadata, config) {
|
|
12
|
+
this.stream = stream;
|
|
13
|
+
this.model = model;
|
|
14
|
+
this.startTime = startTime;
|
|
15
|
+
this.transactionId = transactionId;
|
|
16
|
+
this.metadata = metadata;
|
|
17
|
+
this.config = config || {};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Iterate over stream chunks
|
|
21
|
+
*/
|
|
22
|
+
async *[Symbol.asyncIterator]() {
|
|
23
|
+
let lastChunk = null;
|
|
24
|
+
let inputTokens = 0;
|
|
25
|
+
let outputTokens = 0;
|
|
26
|
+
let totalTokens = 0;
|
|
27
|
+
let costData = undefined;
|
|
28
|
+
let firstChunkTime = null;
|
|
29
|
+
let timeToFirstToken = 0;
|
|
30
|
+
try {
|
|
31
|
+
for await (const chunk of this.stream) {
|
|
32
|
+
// Capture time of first chunk
|
|
33
|
+
if (!firstChunkTime) {
|
|
34
|
+
firstChunkTime = new Date();
|
|
35
|
+
timeToFirstToken =
|
|
36
|
+
firstChunkTime.getTime() - this.startTime.getTime();
|
|
37
|
+
}
|
|
38
|
+
lastChunk = chunk;
|
|
39
|
+
// Track usage if available in chunk
|
|
40
|
+
if (chunk.usage) {
|
|
41
|
+
inputTokens = chunk.usage.prompt_tokens || 0;
|
|
42
|
+
outputTokens = chunk.usage.completion_tokens || 0;
|
|
43
|
+
totalTokens = chunk.usage.total_tokens || 0;
|
|
44
|
+
// Extract cost data if available (Perplexity-specific)
|
|
45
|
+
if (chunk.usage.cost) {
|
|
46
|
+
costData = chunk.usage.cost;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
yield chunk;
|
|
50
|
+
}
|
|
51
|
+
// Send metering data when stream completes (fire-and-forget)
|
|
52
|
+
const endTime = Date.now();
|
|
53
|
+
const duration = endTime - this.startTime.getTime();
|
|
54
|
+
// fire-and-forget
|
|
55
|
+
trackUsageAsync({
|
|
56
|
+
requestId: this.transactionId,
|
|
57
|
+
model: this.model,
|
|
58
|
+
promptTokens: inputTokens,
|
|
59
|
+
completionTokens: outputTokens,
|
|
60
|
+
totalTokens,
|
|
61
|
+
duration,
|
|
62
|
+
finishReason: lastChunk?.choices?.[0]?.finish_reason || null,
|
|
63
|
+
usageMetadata: this.metadata,
|
|
64
|
+
isStreamed: true,
|
|
65
|
+
timeToFirstToken,
|
|
66
|
+
cost: costData,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// Log error
|
|
71
|
+
logger.error("[Revenium] Error in stream processing:", error.message);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=streaming-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-wrapper.js","sourceRoot":"","sources":["../../../../src/core/middleware/streaming-wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAQ3B,YACE,MAA0B,EAC1B,KAAa,EACb,SAAe,EACf,aAAqB,EACrB,QAAwB,EACxB,MAAY;QAEZ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,IAAI,SAAS,GAAQ,IAAI,CAAC;QAC1B,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,QAAQ,GAAQ,SAAS,CAAC;QAC9B,IAAI,cAAc,GAAgB,IAAI,CAAC;QACvC,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACtC,8BAA8B;gBAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;oBACpB,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC;oBAC5B,gBAAgB;wBACd,cAAc,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACxD,CAAC;gBAED,SAAS,GAAG,KAAK,CAAC;gBAElB,oCAAoC;gBACpC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAChB,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;oBAC7C,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC;oBAClD,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;oBAC5C,uDAAuD;oBACvD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;wBACrB,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBAED,MAAM,KAAK,CAAC;YACd,CAAC;YAED,6DAA6D;YAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YAEpD,kBAAkB;YAClB,eAAe,CAAC;gBACd,SAAS,EAAE,IAAI,CAAC,aAAa;gBAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,YAAY,EAAE,WAAW;gBACzB,gBAAgB,EAAE,YAAY;gBAC9B,WAAW;gBACX,QAAQ;gBACR,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,IAAI;gBAC5D,aAAa,EAAE,IAAI,CAAC,QAAQ;gBAC5B,UAAU,EAAE,IAAI;gBAChB,gBAAgB;gBAChB,IAAI,EAAE,QAAQ;aACf,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,YAAY;YACZ,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACtE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Detection Module
|
|
3
|
+
*
|
|
4
|
+
* Handles provider metadata for Perplexity AI.
|
|
5
|
+
* Simplified compared to OpenAI modular since Perplexity doesn't have Azure variant.
|
|
6
|
+
*/
|
|
7
|
+
import { getLogger } from "../config/index.js";
|
|
8
|
+
// Global logger
|
|
9
|
+
const logger = getLogger();
|
|
10
|
+
/**
|
|
11
|
+
* Get provider info for Perplexity
|
|
12
|
+
* Always returns Perplexity since there's no Azure variant
|
|
13
|
+
*
|
|
14
|
+
* @returns ProviderInfo with Perplexity provider
|
|
15
|
+
*/
|
|
16
|
+
export function detectProvider() {
|
|
17
|
+
logger.debug("Using Perplexity AI provider");
|
|
18
|
+
return {
|
|
19
|
+
provider: "PERPLEXITY",
|
|
20
|
+
modelSource: "PERPLEXITY",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get provider metadata for Revenium payload
|
|
25
|
+
*
|
|
26
|
+
* @returns metadata object for Revenium
|
|
27
|
+
*/
|
|
28
|
+
export function getProviderMetadata() {
|
|
29
|
+
return {
|
|
30
|
+
provider: "Perplexity",
|
|
31
|
+
modelSource: "PERPLEXITY",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../../../src/core/providers/detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,gBAAgB;AAChB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC7C,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,WAAW,EAAE,YAAY;KAC1B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IAIjC,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,WAAW,EAAE,YAAY;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Providers module - Main exports
|
|
3
|
+
*
|
|
4
|
+
* This module provides a clean interface for provider detection and management.
|
|
5
|
+
* Simplified for Perplexity (no Azure variant).
|
|
6
|
+
*/
|
|
7
|
+
// Re-export all provider functionality
|
|
8
|
+
export { detectProvider, getProviderMetadata } from "./detector.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/providers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uCAAuC;AACvC,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Revenium API Client Module
|
|
3
|
+
*
|
|
4
|
+
* Handles HTTP communication with the Revenium API.
|
|
5
|
+
* Extracted from tracking.ts for single responsibility.
|
|
6
|
+
*/
|
|
7
|
+
import { getConfig, getLogger } from "../config/index.js";
|
|
8
|
+
import { buildReveniumUrl } from "../../utils/url-builder.js";
|
|
9
|
+
// Global logger
|
|
10
|
+
const logger = getLogger();
|
|
11
|
+
/**
|
|
12
|
+
* Send payload to Revenium API
|
|
13
|
+
*
|
|
14
|
+
* This is the shared HTTP function that eliminates all duplication
|
|
15
|
+
* between chat completions and embeddings tracking.
|
|
16
|
+
*
|
|
17
|
+
* @param payload - The payload to send to Revenium
|
|
18
|
+
*/
|
|
19
|
+
export async function sendToRevenium(payload) {
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
if (!config)
|
|
22
|
+
return logger.warn("Revenium configuration not found, skipping tracking");
|
|
23
|
+
const url = buildReveniumUrl(config.reveniumBaseUrl || "https://api.revenium.ai", "/ai/completions");
|
|
24
|
+
logger.debug("Sending Revenium API request", {
|
|
25
|
+
url,
|
|
26
|
+
operationType: payload.operationType,
|
|
27
|
+
transactionId: payload.transactionId,
|
|
28
|
+
model: payload.model,
|
|
29
|
+
totalTokens: payload.totalTokenCount,
|
|
30
|
+
});
|
|
31
|
+
const response = await fetch(url, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
Accept: "application/json",
|
|
36
|
+
"x-api-key": config.reveniumApiKey,
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(payload),
|
|
39
|
+
});
|
|
40
|
+
logger.debug("Revenium API response", {
|
|
41
|
+
status: response.status,
|
|
42
|
+
statusText: response.statusText,
|
|
43
|
+
transactionId: payload.transactionId,
|
|
44
|
+
operationType: payload.operationType,
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const responseText = await response.text();
|
|
48
|
+
logger.error("Revenium API error response", {
|
|
49
|
+
status: response.status,
|
|
50
|
+
statusText: response.statusText,
|
|
51
|
+
body: responseText,
|
|
52
|
+
transactionId: payload.transactionId,
|
|
53
|
+
operationType: payload.operationType,
|
|
54
|
+
});
|
|
55
|
+
throw new Error(`Revenium API error: ${response.status} ${response.statusText} - ${responseText}`);
|
|
56
|
+
}
|
|
57
|
+
const responseBody = await response.text();
|
|
58
|
+
logger.debug("Revenium tracking successful", {
|
|
59
|
+
transactionId: payload.transactionId,
|
|
60
|
+
operationType: payload.operationType,
|
|
61
|
+
response: responseBody,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../../src/core/tracking/api-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,gBAAgB;AAChB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAwB;IAC3D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM;QACT,OAAO,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IAE5E,MAAM,GAAG,GAAG,gBAAgB,CAC1B,MAAM,CAAC,eAAe,IAAI,yBAAyB,EACnD,iBAAiB,CAClB,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE;QAC3C,GAAG;QACH,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,eAAe;KACrC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,kBAAkB;YAC1B,WAAW,EAAE,MAAM,CAAC,cAAc;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IAEH,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;QACpC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;YAC1C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,IAAI,EAAE,YAAY;YAClB,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,aAAa,EAAE,OAAO,CAAC,aAAa;SACrC,CAAC,CAAC;QACH,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,YAAY,EAAE,CAClF,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3C,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE;QAC3C,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,QAAQ,EAAE,YAAY;KACvB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracking module - Main exports
|
|
3
|
+
*
|
|
4
|
+
* This module provides a clean interface for usage tracking,
|
|
5
|
+
* separating concerns into focused sub-modules.
|
|
6
|
+
*/
|
|
7
|
+
// Re-export all tracking functionality
|
|
8
|
+
export { sendToRevenium } from './api-client.js';
|
|
9
|
+
export { buildPayload } from './payload-builder.js';
|
|
10
|
+
export { sendReveniumMetrics, trackUsageAsync } from './usage-tracker.js';
|
|
11
|
+
// Export utility functions
|
|
12
|
+
export { mapStopReason } from '../../utils/stop-reason-mapper.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/tracking/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uCAAuC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1E,2BAA2B;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payload Builder Module
|
|
3
|
+
*
|
|
4
|
+
* Handles construction of Revenium API payloads.
|
|
5
|
+
* Extracted from tracking.ts for single responsibility.
|
|
6
|
+
*/
|
|
7
|
+
import { randomUUID } from "crypto";
|
|
8
|
+
import { getLogger } from "../config/index.js";
|
|
9
|
+
import { mapStopReason } from "../../utils/stop-reason-mapper.js";
|
|
10
|
+
import { buildMetadataFields } from "../../utils/metadata-builder.js";
|
|
11
|
+
import { getProviderMetadata } from "../providers/index.js";
|
|
12
|
+
// Global logger
|
|
13
|
+
const logger = getLogger();
|
|
14
|
+
/**
|
|
15
|
+
* Build payload for Revenium API
|
|
16
|
+
*
|
|
17
|
+
* This shared payload builder eliminates payload duplication.
|
|
18
|
+
* Handles CHAT operation type for Perplexity.
|
|
19
|
+
*
|
|
20
|
+
* @param operationType - Type of operation (CHAT)
|
|
21
|
+
* @param response - API response from Perplexity
|
|
22
|
+
* @param request - Original request parameters
|
|
23
|
+
* @param startTime - Request start timestamp
|
|
24
|
+
* @param duration - Request duration in milliseconds
|
|
25
|
+
* @param providerInfo - Provider information (always Perplexity)
|
|
26
|
+
* @param timeToFirstToken - Time to first token in milliseconds (for streaming)
|
|
27
|
+
* @returns Constructed payload for Revenium API
|
|
28
|
+
*/
|
|
29
|
+
export function buildPayload(operationType, response, request, startTime, duration, providerInfo, timeToFirstToken) {
|
|
30
|
+
const now = new Date().toISOString();
|
|
31
|
+
const requestTime = new Date(startTime).toISOString();
|
|
32
|
+
const usage = response.usage;
|
|
33
|
+
if (!usage) {
|
|
34
|
+
throw new Error("Response usage data is missing");
|
|
35
|
+
}
|
|
36
|
+
const modelName = response.model;
|
|
37
|
+
// Get provider metadata (always Perplexity)
|
|
38
|
+
const providerMetadata = providerInfo
|
|
39
|
+
? getProviderMetadata()
|
|
40
|
+
: { provider: "Perplexity", modelSource: "PERPLEXITY" };
|
|
41
|
+
// Build metadata fields using utility (eliminates repetitive spreading)
|
|
42
|
+
const metadataFields = buildMetadataFields(request.usageMetadata);
|
|
43
|
+
// Map Perplexity cost object to Revenium cost fields
|
|
44
|
+
const costFields = usage.cost
|
|
45
|
+
? {
|
|
46
|
+
inputTokenCost: usage.cost.input_tokens_cost,
|
|
47
|
+
outputTokenCost: usage.cost.output_tokens_cost,
|
|
48
|
+
totalCost: usage.cost.total_cost,
|
|
49
|
+
}
|
|
50
|
+
: {
|
|
51
|
+
// Let Revenium calculate costs if not provided
|
|
52
|
+
inputTokenCost: undefined,
|
|
53
|
+
outputTokenCost: undefined,
|
|
54
|
+
totalCost: undefined,
|
|
55
|
+
};
|
|
56
|
+
// Common fields for all operations
|
|
57
|
+
const commonPayload = {
|
|
58
|
+
costType: "AI",
|
|
59
|
+
model: modelName,
|
|
60
|
+
responseTime: now,
|
|
61
|
+
requestDuration: duration,
|
|
62
|
+
provider: providerMetadata.provider,
|
|
63
|
+
modelSource: providerMetadata.modelSource,
|
|
64
|
+
requestTime,
|
|
65
|
+
completionStartTime: now,
|
|
66
|
+
// Common token counts
|
|
67
|
+
inputTokenCount: usage.prompt_tokens,
|
|
68
|
+
totalTokenCount: usage.total_tokens,
|
|
69
|
+
// Metadata fields (processed by utility)
|
|
70
|
+
...metadataFields,
|
|
71
|
+
// Fixed middleware source identifier (spec format: revenium-{provider}-{language})
|
|
72
|
+
middlewareSource: "revenium-perplexity-node",
|
|
73
|
+
// Cost fields from Perplexity
|
|
74
|
+
...costFields,
|
|
75
|
+
};
|
|
76
|
+
// Chat-specific fields
|
|
77
|
+
return {
|
|
78
|
+
...commonPayload,
|
|
79
|
+
operationType: "CHAT",
|
|
80
|
+
transactionId: response.id || `chat-${randomUUID()}`,
|
|
81
|
+
outputTokenCount: usage.completion_tokens || 0,
|
|
82
|
+
// Perplexity doesn't support reasoning or caching
|
|
83
|
+
reasoningTokenCount: undefined,
|
|
84
|
+
cacheCreationTokenCount: undefined,
|
|
85
|
+
cacheReadTokenCount: undefined,
|
|
86
|
+
stopReason: mapStopReason(response.choices?.[0]?.finish_reason, logger),
|
|
87
|
+
isStreamed: Boolean(request.stream),
|
|
88
|
+
// Time to first token (for streaming requests)
|
|
89
|
+
timeToFirstToken: timeToFirstToken,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=payload-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-builder.js","sourceRoot":"","sources":["../../../../src/core/tracking/payload-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage Tracker Module
|
|
3
|
+
*
|
|
4
|
+
* High-level tracking functions that combine payload building and API communication.
|
|
5
|
+
* Extracted from tracking.ts for better organization.
|
|
6
|
+
*/
|
|
7
|
+
import { getLogger } from "../config/index.js";
|
|
8
|
+
import { sendToRevenium } from "./api-client.js";
|
|
9
|
+
import { buildPayload } from "./payload-builder.js";
|
|
10
|
+
import { safeAsyncOperation } from "../../utils/error-handler.js";
|
|
11
|
+
// Global logger
|
|
12
|
+
const logger = getLogger();
|
|
13
|
+
/**
|
|
14
|
+
* Chat completions tracking - thin wrapper
|
|
15
|
+
*/
|
|
16
|
+
export async function sendReveniumMetrics(response, request, startTime, duration, providerInfo, timeToFirstToken) {
|
|
17
|
+
await safeAsyncOperation(async () => {
|
|
18
|
+
const payload = buildPayload("CHAT", response, request, startTime, duration, providerInfo, timeToFirstToken);
|
|
19
|
+
await sendToRevenium(payload);
|
|
20
|
+
}, "Chat completion tracking", {
|
|
21
|
+
logError: true,
|
|
22
|
+
rethrow: false, // Don't rethrow to maintain fire-and-forget behavior
|
|
23
|
+
messagePrefix: "Chat completion tracking failed: ",
|
|
24
|
+
}, logger);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fire-and-forget wrapper for chat completions
|
|
28
|
+
* Constructs DTO objects from simple tracking data to call sendReveniumMetrics
|
|
29
|
+
*/
|
|
30
|
+
export function trackUsageAsync(trackingData) {
|
|
31
|
+
// Build DTO response object from tracking data
|
|
32
|
+
const dtoResponse = {
|
|
33
|
+
id: trackingData.requestId,
|
|
34
|
+
model: trackingData.model,
|
|
35
|
+
object: "chat.completion",
|
|
36
|
+
created: Math.floor(Date.now() / 1000),
|
|
37
|
+
usage: {
|
|
38
|
+
prompt_tokens: trackingData.promptTokens,
|
|
39
|
+
completion_tokens: trackingData.completionTokens,
|
|
40
|
+
total_tokens: trackingData.totalTokens,
|
|
41
|
+
cost: trackingData.cost,
|
|
42
|
+
},
|
|
43
|
+
choices: [
|
|
44
|
+
{
|
|
45
|
+
index: 0,
|
|
46
|
+
finish_reason: trackingData.finishReason,
|
|
47
|
+
message: {
|
|
48
|
+
role: "assistant",
|
|
49
|
+
content: "",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
// Build DTO request object from tracking data
|
|
55
|
+
const dtoRequest = {
|
|
56
|
+
model: trackingData.model,
|
|
57
|
+
messages: [],
|
|
58
|
+
usageMetadata: trackingData.usageMetadata,
|
|
59
|
+
stream: trackingData.isStreamed,
|
|
60
|
+
};
|
|
61
|
+
const startTime = Date.now() - trackingData.duration;
|
|
62
|
+
sendReveniumMetrics(dtoResponse, dtoRequest, startTime, trackingData.duration, trackingData.providerInfo, trackingData.timeToFirstToken)
|
|
63
|
+
.then(() => {
|
|
64
|
+
logger.debug("Usage tracking completed successfully", {
|
|
65
|
+
requestId: trackingData.requestId,
|
|
66
|
+
model: trackingData.model,
|
|
67
|
+
totalTokens: trackingData.totalTokens,
|
|
68
|
+
isStreamed: trackingData.isStreamed,
|
|
69
|
+
});
|
|
70
|
+
})
|
|
71
|
+
.catch((error) => {
|
|
72
|
+
logger.warn("Usage tracking failed", {
|
|
73
|
+
error: error instanceof Error ? error.message : String(error),
|
|
74
|
+
requestId: trackingData.requestId,
|
|
75
|
+
model: trackingData.model,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=usage-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-tracker.js","sourceRoot":"","sources":["../../../../src/core/tracking/usage-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,gBAAgB;AAChB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAA4B,EAC5B,OAA8B,EAC9B,SAAiB,EACjB,QAAgB,EAChB,YAA2B,EAC3B,gBAAyB;IAEzB,MAAM,kBAAkB,CACtB,KAAK,IAAI,EAAE;QACT,MAAM,OAAO,GAAG,YAAY,CAC1B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,gBAAgB,CACjB,CAAC;QACF,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC,EACD,0BAA0B,EAC1B;QACE,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,KAAK,EAAE,qDAAqD;QACrE,aAAa,EAAE,mCAAmC;KACnD,EACD,MAAM,CACP,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,YAa/B;IACC,+CAA+C;IAC/C,MAAM,WAAW,GAAuB;QACtC,EAAE,EAAE,YAAY,CAAC,SAAS;QAC1B,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,MAAM,EAAE,iBAAiB;QACzB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QACtC,KAAK,EAAE;YACL,aAAa,EAAE,YAAY,CAAC,YAAY;YACxC,iBAAiB,EAAE,YAAY,CAAC,gBAAgB;YAChD,YAAY,EAAE,YAAY,CAAC,WAAW;YACtC,IAAI,EAAE,YAAY,CAAC,IAAI;SACxB;QACD,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,CAAC;gBACR,aAAa,EAAE,YAAY,CAAC,YAAY;gBACxC,OAAO,EAAE;oBACP,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,EAAE;iBACZ;aACF;SACF;KACF,CAAC;IAEF,8CAA8C;IAC9C,MAAM,UAAU,GAA0B;QACxC,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,QAAQ,EAAE,EAAE;QACZ,aAAa,EAAE,YAAY,CAAC,aAAa;QACzC,MAAM,EAAE,YAAY,CAAC,UAAU;KAChC,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC;IAErD,mBAAmB,CACjB,WAAW,EACX,UAAU,EACV,SAAS,EACT,YAAY,CAAC,QAAQ,EACrB,YAAY,CAAC,YAAY,EACzB,YAAY,CAAC,gBAAgB,CAC9B;SACE,IAAI,CAAC,GAAG,EAAE;QACT,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE;YACpD,SAAS,EAAE,YAAY,CAAC,SAAS;YACjC,KAAK,EAAE,YAAY,CAAC,KAAK;YACzB,WAAW,EAAE,YAAY,CAAC,WAAW;YACrC,UAAU,EAAE,YAAY,CAAC,UAAU;SACpC,CAAC,CAAC;IACL,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE;YACnC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC7D,SAAS,EAAE,YAAY,CAAC,SAAS;YACjC,KAAK,EAAE,YAAY,CAAC,KAAK;SAC1B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
|