@jambonz/llm 0.4.6 → 0.5.1
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.cjs +145 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +145 -5
- package/dist/index.js.map +1 -1
- package/dist/test-kit/index.cjs +145 -5
- package/dist/test-kit/index.cjs.map +1 -1
- package/dist/test-kit/index.d.cts +1 -1
- package/dist/test-kit/index.d.ts +1 -1
- package/dist/test-kit/index.js +145 -5
- package/dist/test-kit/index.js.map +1 -1
- package/dist/{types-DbqWrdT6.d.cts → types-BEgQaQIb.d.cts} +36 -0
- package/dist/{types-DbqWrdT6.d.ts → types-BEgQaQIb.d.ts} +36 -0
- package/package.json +1 -1
package/dist/test-kit/index.cjs
CHANGED
|
@@ -117,9 +117,22 @@ async function* streamFromOpenAI(client, req, options) {
|
|
|
117
117
|
const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
|
|
118
118
|
body[param] = effectiveMaxTokens;
|
|
119
119
|
}
|
|
120
|
+
const t0 = process.hrtime.bigint();
|
|
121
|
+
let t1;
|
|
122
|
+
let t2;
|
|
120
123
|
let stream;
|
|
124
|
+
let responseHeaders;
|
|
121
125
|
try {
|
|
122
|
-
|
|
126
|
+
const apiPromise = client.chat.completions.create(body, { signal: req.signal });
|
|
127
|
+
const maybeWithResponse = apiPromise.withResponse;
|
|
128
|
+
if (typeof maybeWithResponse === "function") {
|
|
129
|
+
const result = await maybeWithResponse.call(apiPromise);
|
|
130
|
+
stream = result.data;
|
|
131
|
+
responseHeaders = result.response?.headers;
|
|
132
|
+
} else {
|
|
133
|
+
stream = await apiPromise;
|
|
134
|
+
}
|
|
135
|
+
t1 = process.hrtime.bigint();
|
|
123
136
|
} catch (err) {
|
|
124
137
|
if (isAbortError(err)) {
|
|
125
138
|
yield { type: "end", finishReason: "aborted" };
|
|
@@ -151,6 +164,7 @@ async function* streamFromOpenAI(client, req, options) {
|
|
|
151
164
|
const delta = choice.delta;
|
|
152
165
|
const finishReason = choice.finish_reason;
|
|
153
166
|
if (delta?.content) {
|
|
167
|
+
if (t2 === void 0) t2 = process.hrtime.bigint();
|
|
154
168
|
yield { type: "token", text: delta.content };
|
|
155
169
|
}
|
|
156
170
|
if (delta?.tool_calls) {
|
|
@@ -214,6 +228,20 @@ async function* streamFromOpenAI(client, req, options) {
|
|
|
214
228
|
...usage ? { usage } : {},
|
|
215
229
|
...finalRawReason ? { rawReason: finalRawReason } : {}
|
|
216
230
|
};
|
|
231
|
+
if (options.vendorMetadataExtractor && responseHeaders) {
|
|
232
|
+
const metadata = options.vendorMetadataExtractor(responseHeaders);
|
|
233
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
234
|
+
endEvent.vendorMetadata = metadata;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (t1 !== void 0) {
|
|
238
|
+
const t3 = process.hrtime.bigint();
|
|
239
|
+
endEvent.clientTiming = {
|
|
240
|
+
requestToHeadersMs: Number(t1 - t0) / 1e6,
|
|
241
|
+
...t2 !== void 0 ? { headersToFirstTokenMs: Number(t2 - t1) / 1e6 } : {},
|
|
242
|
+
totalMs: Number(t3 - t0) / 1e6
|
|
243
|
+
};
|
|
244
|
+
}
|
|
217
245
|
yield endEvent;
|
|
218
246
|
}
|
|
219
247
|
function appendOpenAIAssistantToolCall(history, toolCalls) {
|
|
@@ -341,6 +369,40 @@ function isAbortError(err) {
|
|
|
341
369
|
return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
|
|
342
370
|
}
|
|
343
371
|
|
|
372
|
+
// src/adapters/_metadata.ts
|
|
373
|
+
function makeMetadataExtractor(fields) {
|
|
374
|
+
return (headers) => {
|
|
375
|
+
const out = {};
|
|
376
|
+
for (const f of fields) {
|
|
377
|
+
const raw = headers.get(f.header);
|
|
378
|
+
if (raw === null || raw === void 0 || raw === "") continue;
|
|
379
|
+
if (f.numeric) {
|
|
380
|
+
const n = Number(raw);
|
|
381
|
+
if (Number.isFinite(n)) out[f.key] = n;
|
|
382
|
+
} else {
|
|
383
|
+
out[f.key] = raw;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return out;
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function extractMetadata(fields, headers) {
|
|
390
|
+
const headersInstance = headers instanceof Headers ? headers : recordToHeaders(headers);
|
|
391
|
+
return makeMetadataExtractor(fields)(headersInstance);
|
|
392
|
+
}
|
|
393
|
+
function recordToHeaders(record) {
|
|
394
|
+
const h = new Headers();
|
|
395
|
+
for (const [name, value] of Object.entries(record)) {
|
|
396
|
+
if (value === void 0) continue;
|
|
397
|
+
if (Array.isArray(value)) {
|
|
398
|
+
for (const v of value) h.append(name, v);
|
|
399
|
+
} else {
|
|
400
|
+
h.set(name, value);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return h;
|
|
404
|
+
}
|
|
405
|
+
|
|
344
406
|
// src/adapters/openai/manifest.ts
|
|
345
407
|
var OPENAI_KNOWN_MODELS = [
|
|
346
408
|
{
|
|
@@ -442,6 +504,12 @@ var openAIManifest = {
|
|
|
442
504
|
};
|
|
443
505
|
|
|
444
506
|
// src/adapters/openai/adapter.ts
|
|
507
|
+
var OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
508
|
+
{ header: "x-request-id", key: "request_id" },
|
|
509
|
+
{ header: "openai-processing-ms", key: "processing_ms", numeric: true },
|
|
510
|
+
{ header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
|
|
511
|
+
{ header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
|
|
512
|
+
]);
|
|
445
513
|
var OpenAIAdapter = class {
|
|
446
514
|
vendor = openAIManifest.vendor;
|
|
447
515
|
acceptedAuth = ["apiKey"];
|
|
@@ -459,7 +527,8 @@ var OpenAIAdapter = class {
|
|
|
459
527
|
}
|
|
460
528
|
stream(req) {
|
|
461
529
|
return streamFromOpenAI(this.ensureClient(), req, {
|
|
462
|
-
knownModels: openAIManifest.knownModels
|
|
530
|
+
knownModels: openAIManifest.knownModels,
|
|
531
|
+
vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
|
|
463
532
|
});
|
|
464
533
|
}
|
|
465
534
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -691,6 +760,12 @@ var anthropicManifest = {
|
|
|
691
760
|
};
|
|
692
761
|
|
|
693
762
|
// src/adapters/anthropic/adapter.ts
|
|
763
|
+
var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
764
|
+
{ header: "request-id", key: "request_id" },
|
|
765
|
+
{ header: "anthropic-ratelimit-requests-remaining", key: "requests_remaining", numeric: true },
|
|
766
|
+
{ header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
|
|
767
|
+
{ header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
|
|
768
|
+
]);
|
|
694
769
|
var AnthropicAdapter = class {
|
|
695
770
|
vendor = anthropicManifest.vendor;
|
|
696
771
|
acceptedAuth = ["apiKey"];
|
|
@@ -725,11 +800,20 @@ var AnthropicAdapter = class {
|
|
|
725
800
|
if (tools) body.tools = tools;
|
|
726
801
|
if (req.temperature !== void 0) body.temperature = req.temperature;
|
|
727
802
|
let stream;
|
|
803
|
+
let responseHeaders;
|
|
728
804
|
try {
|
|
729
|
-
|
|
805
|
+
const apiPromise = client.messages.create(
|
|
730
806
|
body,
|
|
731
807
|
{ signal: req.signal }
|
|
732
808
|
);
|
|
809
|
+
const maybeWithResponse = apiPromise.withResponse;
|
|
810
|
+
if (typeof maybeWithResponse === "function") {
|
|
811
|
+
const result = await maybeWithResponse.call(apiPromise);
|
|
812
|
+
stream = result.data;
|
|
813
|
+
responseHeaders = result.response?.headers;
|
|
814
|
+
} else {
|
|
815
|
+
stream = await apiPromise;
|
|
816
|
+
}
|
|
733
817
|
} catch (err) {
|
|
734
818
|
if (isAbortError2(err)) {
|
|
735
819
|
yield { type: "end", finishReason: "aborted" };
|
|
@@ -840,6 +924,12 @@ var AnthropicAdapter = class {
|
|
|
840
924
|
...usage ? { usage } : {},
|
|
841
925
|
...stopReason ? { rawReason: stopReason } : {}
|
|
842
926
|
};
|
|
927
|
+
if (responseHeaders) {
|
|
928
|
+
const metadata = ANTHROPIC_METADATA_EXTRACTOR(responseHeaders);
|
|
929
|
+
if (Object.keys(metadata).length > 0) {
|
|
930
|
+
endEvent.vendorMetadata = metadata;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
843
933
|
yield endEvent;
|
|
844
934
|
}
|
|
845
935
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -1632,6 +1722,9 @@ var vertexOpenAIManifest = {
|
|
|
1632
1722
|
};
|
|
1633
1723
|
|
|
1634
1724
|
// src/adapters/vertex-openai/adapter.ts
|
|
1725
|
+
var VERTEX_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
1726
|
+
{ header: "x-request-id", key: "request_id" }
|
|
1727
|
+
]);
|
|
1635
1728
|
var VertexOpenAIAdapter = class {
|
|
1636
1729
|
vendor = vertexOpenAIManifest.vendor;
|
|
1637
1730
|
acceptedAuth = ["vertexServiceAccount"];
|
|
@@ -1684,7 +1777,8 @@ var VertexOpenAIAdapter = class {
|
|
|
1684
1777
|
// endpoint predates `max_completion_tokens` and may not recognize it.
|
|
1685
1778
|
// The model-id heuristic wouldn't catch a partner model named in the
|
|
1686
1779
|
// OpenAI style (unlikely today, but defensive).
|
|
1687
|
-
tokensParam: "max_tokens"
|
|
1780
|
+
tokensParam: "max_tokens",
|
|
1781
|
+
vendorMetadataExtractor: VERTEX_OPENAI_METADATA_EXTRACTOR
|
|
1688
1782
|
});
|
|
1689
1783
|
}
|
|
1690
1784
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -2142,6 +2236,21 @@ var BedrockAdapter = class {
|
|
|
2142
2236
|
...usage ? { usage } : {},
|
|
2143
2237
|
...stopReason ? { rawReason: stopReason } : {}
|
|
2144
2238
|
};
|
|
2239
|
+
const httpHeaders = response.$metadata?.httpHeaders;
|
|
2240
|
+
if (httpHeaders) {
|
|
2241
|
+
const metadata = extractMetadata(
|
|
2242
|
+
[
|
|
2243
|
+
{ header: "x-amzn-bedrock-invocation-latency", key: "invocation_latency_ms", numeric: true },
|
|
2244
|
+
{ header: "x-amzn-bedrock-cache-read-input-token-count", key: "cache_read_input_tokens", numeric: true },
|
|
2245
|
+
{ header: "x-amzn-bedrock-cache-write-input-token-count", key: "cache_write_input_tokens", numeric: true },
|
|
2246
|
+
{ header: "x-amzn-bedrock-trace-id", key: "trace_id" }
|
|
2247
|
+
],
|
|
2248
|
+
httpHeaders
|
|
2249
|
+
);
|
|
2250
|
+
if (Object.keys(metadata).length > 0) {
|
|
2251
|
+
endEvent.vendorMetadata = metadata;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2145
2254
|
yield endEvent;
|
|
2146
2255
|
}
|
|
2147
2256
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -2393,6 +2502,14 @@ var azureOpenAIManifest = {
|
|
|
2393
2502
|
};
|
|
2394
2503
|
|
|
2395
2504
|
// src/adapters/azure-openai/adapter.ts
|
|
2505
|
+
var AZURE_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
2506
|
+
{ header: "x-ms-region", key: "region" },
|
|
2507
|
+
{ header: "x-ms-deployment-name", key: "deployment" },
|
|
2508
|
+
{ header: "apim-request-id", key: "request_id" },
|
|
2509
|
+
{ header: "azureml-model-session", key: "model_session" },
|
|
2510
|
+
{ header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
|
|
2511
|
+
{ header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
|
|
2512
|
+
]);
|
|
2396
2513
|
var AzureOpenAIAdapter = class {
|
|
2397
2514
|
vendor = azureOpenAIManifest.vendor;
|
|
2398
2515
|
acceptedAuth = ["azureOpenAIApiKey"];
|
|
@@ -2427,7 +2544,8 @@ var AzureOpenAIAdapter = class {
|
|
|
2427
2544
|
stream(req) {
|
|
2428
2545
|
return streamFromOpenAI(this.ensureClient(), req, {
|
|
2429
2546
|
knownModels: azureOpenAIManifest.knownModels,
|
|
2430
|
-
tokensParam: "max_completion_tokens"
|
|
2547
|
+
tokensParam: "max_completion_tokens",
|
|
2548
|
+
vendorMetadataExtractor: AZURE_OPENAI_METADATA_EXTRACTOR
|
|
2431
2549
|
});
|
|
2432
2550
|
}
|
|
2433
2551
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -2552,6 +2670,12 @@ var groqManifest = {
|
|
|
2552
2670
|
};
|
|
2553
2671
|
|
|
2554
2672
|
// src/adapters/groq/adapter.ts
|
|
2673
|
+
var GROQ_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
2674
|
+
{ header: "x-request-id", key: "request_id" },
|
|
2675
|
+
{ header: "x-groq-region", key: "region" },
|
|
2676
|
+
{ header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
|
|
2677
|
+
{ header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
|
|
2678
|
+
]);
|
|
2555
2679
|
var GroqAdapter = class extends OpenAIAdapter {
|
|
2556
2680
|
vendor = groqManifest.vendor;
|
|
2557
2681
|
init(auth, client) {
|
|
@@ -2563,6 +2687,12 @@ var GroqAdapter = class extends OpenAIAdapter {
|
|
|
2563
2687
|
client
|
|
2564
2688
|
);
|
|
2565
2689
|
}
|
|
2690
|
+
stream(req) {
|
|
2691
|
+
return streamFromOpenAI(this.ensureClient(), req, {
|
|
2692
|
+
knownModels: groqManifest.knownModels,
|
|
2693
|
+
vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2566
2696
|
};
|
|
2567
2697
|
|
|
2568
2698
|
// src/adapters/groq/factory.ts
|
|
@@ -2663,6 +2793,10 @@ var huggingfaceManifest = {
|
|
|
2663
2793
|
};
|
|
2664
2794
|
|
|
2665
2795
|
// src/adapters/huggingface/adapter.ts
|
|
2796
|
+
var HUGGINGFACE_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
2797
|
+
{ header: "x-inference-provider", key: "provider" },
|
|
2798
|
+
{ header: "x-request-id", key: "request_id" }
|
|
2799
|
+
]);
|
|
2666
2800
|
var HuggingfaceAdapter = class extends OpenAIAdapter {
|
|
2667
2801
|
vendor = huggingfaceManifest.vendor;
|
|
2668
2802
|
init(auth, client) {
|
|
@@ -2674,6 +2808,12 @@ var HuggingfaceAdapter = class extends OpenAIAdapter {
|
|
|
2674
2808
|
client
|
|
2675
2809
|
);
|
|
2676
2810
|
}
|
|
2811
|
+
stream(req) {
|
|
2812
|
+
return streamFromOpenAI(this.ensureClient(), req, {
|
|
2813
|
+
knownModels: huggingfaceManifest.knownModels,
|
|
2814
|
+
vendorMetadataExtractor: HUGGINGFACE_METADATA_EXTRACTOR
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2677
2817
|
};
|
|
2678
2818
|
|
|
2679
2819
|
// src/adapters/huggingface/factory.ts
|