@signalvaultio/node 0.5.1 → 0.5.2
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/dist/index.d.ts +1 -1
- package/dist/index.js +57 -18
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type OpenAI from 'openai';
|
|
|
2
2
|
import { ToolsAPI } from './tools';
|
|
3
3
|
export type { ToolRecordOptions, ToolsAPI } from './tools';
|
|
4
4
|
/** Kept in sync with package.json by a unit test. */
|
|
5
|
-
export declare const SDK_VERSION = "0.5.
|
|
5
|
+
export declare const SDK_VERSION = "0.5.2";
|
|
6
6
|
/**
|
|
7
7
|
* Normalizes the base URL and refuses plaintext HTTP to anything but the local
|
|
8
8
|
* machine. The API key and full prompts travel in every request, so an
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.normalizeBaseUrl = normalizeBaseUrl;
|
|
|
5
5
|
const crypto_1 = require("crypto");
|
|
6
6
|
const tools_1 = require("./tools");
|
|
7
7
|
/** Kept in sync with package.json by a unit test. */
|
|
8
|
-
exports.SDK_VERSION = '0.5.
|
|
8
|
+
exports.SDK_VERSION = '0.5.2';
|
|
9
9
|
const DEFAULT_BASE_URL = 'https://api.signalvault.io';
|
|
10
10
|
const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
|
|
11
11
|
/** Longest Retry-After the SDK will wait out before retrying a background event once. */
|
|
@@ -164,6 +164,39 @@ function anthropicOutputText(response) {
|
|
|
164
164
|
.map((b) => b.text)
|
|
165
165
|
.join('');
|
|
166
166
|
}
|
|
167
|
+
const ANTHROPIC_USAGE_KEYS = [
|
|
168
|
+
'input_tokens',
|
|
169
|
+
'cache_creation_input_tokens',
|
|
170
|
+
'cache_read_input_tokens',
|
|
171
|
+
'output_tokens',
|
|
172
|
+
];
|
|
173
|
+
/** `usage.cache_creation`: the cache writes by cache lifetime, priced differently. */
|
|
174
|
+
const CACHE_CREATION_KEYS = ['ephemeral_5m_input_tokens', 'ephemeral_1h_input_tokens'];
|
|
175
|
+
function copyCounts(target, source, keys) {
|
|
176
|
+
for (const key of keys) {
|
|
177
|
+
const n = source?.[key];
|
|
178
|
+
if (typeof n === 'number' && Number.isFinite(n) && n >= 0)
|
|
179
|
+
target[key] = n;
|
|
180
|
+
}
|
|
181
|
+
return target;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Anthropic usage under Anthropic's own names, as the proxy records it. The
|
|
185
|
+
* server adds the cache counts to `input_tokens`; renamed to `prompt_tokens`,
|
|
186
|
+
* which for OpenAI already includes cached tokens, they would be lost. Later
|
|
187
|
+
* sources override earlier ones, but only with a count.
|
|
188
|
+
*/
|
|
189
|
+
function anthropicUsage(...sources) {
|
|
190
|
+
const usage = { input_tokens: 0, output_tokens: 0 };
|
|
191
|
+
let cacheCreation = {};
|
|
192
|
+
for (const source of sources) {
|
|
193
|
+
copyCounts(usage, source, ANTHROPIC_USAGE_KEYS);
|
|
194
|
+
cacheCreation = copyCounts(cacheCreation, source?.cache_creation, CACHE_CREATION_KEYS);
|
|
195
|
+
}
|
|
196
|
+
if (Object.keys(cacheCreation).length)
|
|
197
|
+
usage.cache_creation = cacheCreation;
|
|
198
|
+
return usage;
|
|
199
|
+
}
|
|
167
200
|
function parseRetryAfterMs(response) {
|
|
168
201
|
const raw = response?.headers?.get?.('retry-after');
|
|
169
202
|
if (!raw)
|
|
@@ -505,10 +538,13 @@ class SignalVaultClient {
|
|
|
505
538
|
const model = params.model;
|
|
506
539
|
const messages = params.messages;
|
|
507
540
|
if (params.stream) {
|
|
508
|
-
return this.wrapStream(response, usage.injected, (output, promptTokens, completionTokens) => this.sendAuditEvents(requestId, model, messages, output, promptTokens, completionTokens, metadata, 'openai'));
|
|
541
|
+
return this.wrapStream(response, usage.injected, (output, promptTokens, completionTokens) => this.sendAuditEvents(requestId, model, messages, output, { prompt_tokens: promptTokens, completion_tokens: completionTokens }, metadata, 'openai'));
|
|
509
542
|
}
|
|
510
543
|
const completion = response;
|
|
511
|
-
this.track(this.sendAuditEvents(requestId, model, messages, completion.choices[0]?.message?.content || '',
|
|
544
|
+
this.track(this.sendAuditEvents(requestId, model, messages, completion.choices[0]?.message?.content || '', {
|
|
545
|
+
prompt_tokens: completion.usage?.prompt_tokens || 0,
|
|
546
|
+
completion_tokens: completion.usage?.completion_tokens || 0,
|
|
547
|
+
}, metadata, 'openai'));
|
|
512
548
|
return completion;
|
|
513
549
|
}
|
|
514
550
|
// ---------------------------------------------------------------------------
|
|
@@ -522,11 +558,14 @@ class SignalVaultClient {
|
|
|
522
558
|
const usage = withStreamUsage(params);
|
|
523
559
|
const response = await this.openai.chat.completions.create(usage.params);
|
|
524
560
|
if (params.stream) {
|
|
525
|
-
return this.wrapStream(response, usage.injected, (output, promptTokens, completionTokens) => this.sendResponseEvent(requestId, model, output, promptTokens, completionTokens, metadata, 'openai', fallback));
|
|
561
|
+
return this.wrapStream(response, usage.injected, (output, promptTokens, completionTokens) => this.sendResponseEvent(requestId, model, output, { prompt_tokens: promptTokens, completion_tokens: completionTokens }, metadata, 'openai', fallback));
|
|
526
562
|
}
|
|
527
563
|
const completion = response;
|
|
528
564
|
// Background: the audit of the response must not delay returning it.
|
|
529
|
-
this.track(this.sendResponseEvent(requestId, model, completion.choices[0]?.message?.content || '',
|
|
565
|
+
this.track(this.sendResponseEvent(requestId, model, completion.choices[0]?.message?.content || '', {
|
|
566
|
+
prompt_tokens: completion.usage?.prompt_tokens || 0,
|
|
567
|
+
completion_tokens: completion.usage?.completion_tokens || 0,
|
|
568
|
+
}, metadata, 'openai', fallback));
|
|
530
569
|
return completion;
|
|
531
570
|
}
|
|
532
571
|
// ---------------------------------------------------------------------------
|
|
@@ -536,9 +575,9 @@ class SignalVaultClient {
|
|
|
536
575
|
const response = await this.anthropic.messages.create(params);
|
|
537
576
|
const messages = anthropicMessagesForAudit(params);
|
|
538
577
|
if (params.stream) {
|
|
539
|
-
return this.wrapAnthropicStream(response, (output,
|
|
578
|
+
return this.wrapAnthropicStream(response, (output, usage) => this.sendAuditEvents(requestId, params.model, messages, output, usage, metadata, 'anthropic'));
|
|
540
579
|
}
|
|
541
|
-
this.track(this.sendAuditEvents(requestId, params.model, messages, anthropicOutputText(response), response.usage
|
|
580
|
+
this.track(this.sendAuditEvents(requestId, params.model, messages, anthropicOutputText(response), anthropicUsage(response.usage), metadata, 'anthropic'));
|
|
542
581
|
return response;
|
|
543
582
|
}
|
|
544
583
|
// ---------------------------------------------------------------------------
|
|
@@ -550,9 +589,9 @@ class SignalVaultClient {
|
|
|
550
589
|
const fallback = this.fallbackRequest(decision, requestId, params.model, messages, metadata, 'anthropic');
|
|
551
590
|
const response = await this.anthropic.messages.create(params);
|
|
552
591
|
if (params.stream) {
|
|
553
|
-
return this.wrapAnthropicStream(response, (output,
|
|
592
|
+
return this.wrapAnthropicStream(response, (output, usage) => this.sendResponseEvent(requestId, params.model, output, usage, metadata, 'anthropic', fallback));
|
|
554
593
|
}
|
|
555
|
-
this.track(this.sendResponseEvent(requestId, params.model, anthropicOutputText(response), response.usage
|
|
594
|
+
this.track(this.sendResponseEvent(requestId, params.model, anthropicOutputText(response), anthropicUsage(response.usage), metadata, 'anthropic', fallback));
|
|
556
595
|
return response;
|
|
557
596
|
}
|
|
558
597
|
// ---------------------------------------------------------------------------
|
|
@@ -590,24 +629,24 @@ class SignalVaultClient {
|
|
|
590
629
|
}
|
|
591
630
|
async *wrapAnthropicStream(stream, onComplete) {
|
|
592
631
|
const chunks = [];
|
|
593
|
-
let
|
|
594
|
-
let outputTokens = 0;
|
|
632
|
+
let usage = anthropicUsage();
|
|
595
633
|
try {
|
|
596
634
|
for await (const event of stream) {
|
|
597
635
|
if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
|
|
598
636
|
chunks.push(event.delta.text || '');
|
|
599
637
|
}
|
|
638
|
+
// message_delta may repeat the input and cache counts; its values win.
|
|
600
639
|
if (event.type === 'message_start' && event.message?.usage) {
|
|
601
|
-
|
|
640
|
+
usage = anthropicUsage(usage, event.message.usage);
|
|
602
641
|
}
|
|
603
642
|
if (event.type === 'message_delta' && event.usage) {
|
|
604
|
-
|
|
643
|
+
usage = anthropicUsage(usage, event.usage);
|
|
605
644
|
}
|
|
606
645
|
yield event;
|
|
607
646
|
}
|
|
608
647
|
}
|
|
609
648
|
finally {
|
|
610
|
-
this.track(onComplete(chunks.join(''),
|
|
649
|
+
this.track(onComplete(chunks.join(''), usage));
|
|
611
650
|
}
|
|
612
651
|
}
|
|
613
652
|
// ---------------------------------------------------------------------------
|
|
@@ -812,7 +851,7 @@ class SignalVaultClient {
|
|
|
812
851
|
dashboard_url: typeof data.dashboard_url === 'string' ? data.dashboard_url : undefined,
|
|
813
852
|
};
|
|
814
853
|
}
|
|
815
|
-
async sendResponseEvent(requestId, model, output,
|
|
854
|
+
async sendResponseEvent(requestId, model, output, usage, metadata, provider, fallbackRequest) {
|
|
816
855
|
if (fallbackRequest === null)
|
|
817
856
|
return;
|
|
818
857
|
if (fallbackRequest) {
|
|
@@ -829,7 +868,7 @@ class SignalVaultClient {
|
|
|
829
868
|
metadata,
|
|
830
869
|
payload: {
|
|
831
870
|
output,
|
|
832
|
-
usage
|
|
871
|
+
usage,
|
|
833
872
|
},
|
|
834
873
|
});
|
|
835
874
|
}
|
|
@@ -838,7 +877,7 @@ class SignalVaultClient {
|
|
|
838
877
|
* purpose — the server rejects an ai.response whose ai.request it has not
|
|
839
878
|
* stored yet, so sending both at once can lose the response.
|
|
840
879
|
*/
|
|
841
|
-
async sendAuditEvents(requestId, model, messages, output,
|
|
880
|
+
async sendAuditEvents(requestId, model, messages, output, usage, metadata, provider) {
|
|
842
881
|
const base = {
|
|
843
882
|
request_id: requestId,
|
|
844
883
|
environment: this.svEnvironment,
|
|
@@ -856,7 +895,7 @@ class SignalVaultClient {
|
|
|
856
895
|
type: 'ai.response',
|
|
857
896
|
payload: {
|
|
858
897
|
output,
|
|
859
|
-
usage
|
|
898
|
+
usage,
|
|
860
899
|
monitor_mode: true,
|
|
861
900
|
},
|
|
862
901
|
});
|