@jambonz/llm 0.3.4 → 0.4.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 +289 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +288 -2
- package/dist/index.js.map +1 -1
- package/dist/test-kit/index.cjs +219 -2
- 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 +219 -2
- package/dist/test-kit/index.js.map +1 -1
- package/dist/{types-4d2QrlAe.d.cts → types-DxknK0Rc.d.cts} +25 -2
- package/dist/{types-4d2QrlAe.d.ts → types-DxknK0Rc.d.ts} +25 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(src_exports, {
|
|
|
36
36
|
getManifest: () => getManifest,
|
|
37
37
|
listVendors: () => listVendors,
|
|
38
38
|
normalizeAuth: () => normalizeAuth,
|
|
39
|
+
pickAuthKind: () => pickAuthKind,
|
|
39
40
|
registerAdapter: () => registerAdapter,
|
|
40
41
|
replaceAdapter: () => replaceAdapter,
|
|
41
42
|
unregisterAdapter: () => unregisterAdapter
|
|
@@ -125,7 +126,10 @@ async function* streamFromOpenAI(client, req, options) {
|
|
|
125
126
|
}
|
|
126
127
|
if (req.temperature !== void 0) body.temperature = req.temperature;
|
|
127
128
|
const effectiveMaxTokens = req.maxTokens ?? options.defaultMaxTokens;
|
|
128
|
-
if (effectiveMaxTokens !== void 0)
|
|
129
|
+
if (effectiveMaxTokens !== void 0) {
|
|
130
|
+
const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
|
|
131
|
+
body[param] = effectiveMaxTokens;
|
|
132
|
+
}
|
|
129
133
|
let stream;
|
|
130
134
|
try {
|
|
131
135
|
stream = await client.chat.completions.create(body, { signal: req.signal });
|
|
@@ -308,6 +312,9 @@ function capabilitiesFor(modelId, knownModels) {
|
|
|
308
312
|
if (known) return known.capabilities;
|
|
309
313
|
return defaultCapabilitiesForUnknown(modelId);
|
|
310
314
|
}
|
|
315
|
+
function needsMaxCompletionTokens(modelId) {
|
|
316
|
+
return /^(o\d|gpt-5)/i.test(modelId);
|
|
317
|
+
}
|
|
311
318
|
function defaultCapabilitiesForUnknown(modelId) {
|
|
312
319
|
const isReasoning = /^o[13]([-/]|$)/i.test(modelId);
|
|
313
320
|
if (isReasoning) {
|
|
@@ -1685,7 +1692,12 @@ var VertexOpenAIAdapter = class {
|
|
|
1685
1692
|
stream(req) {
|
|
1686
1693
|
return streamFromOpenAI(this.ensureClient(), req, {
|
|
1687
1694
|
knownModels: vertexOpenAIManifest.knownModels,
|
|
1688
|
-
defaultMaxTokens: 4096
|
|
1695
|
+
defaultMaxTokens: 4096,
|
|
1696
|
+
// Pin legacy `max_tokens`: Vertex's OpenAI-compat partner-model
|
|
1697
|
+
// endpoint predates `max_completion_tokens` and may not recognize it.
|
|
1698
|
+
// The model-id heuristic wouldn't catch a partner model named in the
|
|
1699
|
+
// OpenAI style (unlikely today, but defensive).
|
|
1700
|
+
tokensParam: "max_tokens"
|
|
1689
1701
|
});
|
|
1690
1702
|
}
|
|
1691
1703
|
appendAssistantToolCall(history, toolCalls) {
|
|
@@ -2270,6 +2282,211 @@ var bedrockFactory = {
|
|
|
2270
2282
|
create: () => new BedrockAdapter()
|
|
2271
2283
|
};
|
|
2272
2284
|
|
|
2285
|
+
// src/adapters/azure-openai/adapter.ts
|
|
2286
|
+
var import_openai3 = require("openai");
|
|
2287
|
+
|
|
2288
|
+
// src/adapters/azure-openai/manifest.ts
|
|
2289
|
+
var AZURE_OPENAI_KNOWN_MODELS = [
|
|
2290
|
+
{
|
|
2291
|
+
id: "gpt-4o",
|
|
2292
|
+
displayName: "GPT-4o (on Azure)",
|
|
2293
|
+
capabilities: {
|
|
2294
|
+
streaming: true,
|
|
2295
|
+
tools: true,
|
|
2296
|
+
vision: true,
|
|
2297
|
+
systemPrompt: true,
|
|
2298
|
+
maxContextTokens: 128e3
|
|
2299
|
+
}
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
id: "gpt-4o-mini",
|
|
2303
|
+
displayName: "GPT-4o mini (on Azure)",
|
|
2304
|
+
capabilities: {
|
|
2305
|
+
streaming: true,
|
|
2306
|
+
tools: true,
|
|
2307
|
+
vision: true,
|
|
2308
|
+
systemPrompt: true,
|
|
2309
|
+
maxContextTokens: 128e3
|
|
2310
|
+
}
|
|
2311
|
+
},
|
|
2312
|
+
{
|
|
2313
|
+
id: "gpt-4-turbo",
|
|
2314
|
+
displayName: "GPT-4 Turbo (on Azure)",
|
|
2315
|
+
capabilities: {
|
|
2316
|
+
streaming: true,
|
|
2317
|
+
tools: true,
|
|
2318
|
+
vision: true,
|
|
2319
|
+
systemPrompt: true,
|
|
2320
|
+
maxContextTokens: 128e3
|
|
2321
|
+
}
|
|
2322
|
+
},
|
|
2323
|
+
{
|
|
2324
|
+
// Azure spells it `gpt-35-turbo` (no dot). Keep their spelling for the id
|
|
2325
|
+
// so capability lookups against deployment names that echo the Azure id
|
|
2326
|
+
// hit.
|
|
2327
|
+
id: "gpt-35-turbo",
|
|
2328
|
+
displayName: "GPT-3.5 Turbo (on Azure)",
|
|
2329
|
+
capabilities: {
|
|
2330
|
+
streaming: true,
|
|
2331
|
+
tools: true,
|
|
2332
|
+
vision: false,
|
|
2333
|
+
systemPrompt: true,
|
|
2334
|
+
maxContextTokens: 16385
|
|
2335
|
+
}
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
id: "o1-preview",
|
|
2339
|
+
displayName: "o1 preview \u2014 reasoning (on Azure)",
|
|
2340
|
+
capabilities: {
|
|
2341
|
+
streaming: false,
|
|
2342
|
+
tools: false,
|
|
2343
|
+
vision: false,
|
|
2344
|
+
systemPrompt: false,
|
|
2345
|
+
maxContextTokens: 128e3
|
|
2346
|
+
}
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
id: "o1-mini",
|
|
2350
|
+
displayName: "o1 mini \u2014 reasoning (on Azure)",
|
|
2351
|
+
capabilities: {
|
|
2352
|
+
streaming: false,
|
|
2353
|
+
tools: false,
|
|
2354
|
+
vision: false,
|
|
2355
|
+
systemPrompt: false,
|
|
2356
|
+
maxContextTokens: 128e3
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
];
|
|
2360
|
+
var azureOpenAIManifest = {
|
|
2361
|
+
vendor: "azure-openai",
|
|
2362
|
+
displayName: "Azure OpenAI",
|
|
2363
|
+
authKinds: [
|
|
2364
|
+
{
|
|
2365
|
+
kind: "azureOpenAIApiKey",
|
|
2366
|
+
displayName: "API Key",
|
|
2367
|
+
fields: [
|
|
2368
|
+
{
|
|
2369
|
+
name: "apiKey",
|
|
2370
|
+
label: "API Key",
|
|
2371
|
+
type: "password",
|
|
2372
|
+
required: true,
|
|
2373
|
+
help: "Azure OpenAI resource key. Find it in the Azure portal under your OpenAI resource \u2192 Keys and Endpoint."
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
name: "endpoint",
|
|
2377
|
+
label: "Endpoint",
|
|
2378
|
+
type: "url",
|
|
2379
|
+
required: true,
|
|
2380
|
+
help: "Resource endpoint URL, e.g. https://my-resource.openai.azure.com. Shown in the Azure portal alongside the keys."
|
|
2381
|
+
},
|
|
2382
|
+
{
|
|
2383
|
+
name: "deployment",
|
|
2384
|
+
label: "Deployment Name",
|
|
2385
|
+
type: "text",
|
|
2386
|
+
required: true,
|
|
2387
|
+
help: "The name you chose for the deployment in Azure AI Studio (NOT the underlying model id \u2014 deployments can be named anything)."
|
|
2388
|
+
},
|
|
2389
|
+
{
|
|
2390
|
+
name: "apiVersion",
|
|
2391
|
+
label: "API Version",
|
|
2392
|
+
type: "text",
|
|
2393
|
+
required: true,
|
|
2394
|
+
default: "2024-10-21",
|
|
2395
|
+
help: "Data-plane api-version, e.g. 2024-10-21. Microsoft rolls these frequently; see Azure OpenAI API reference docs for the current stable GA version."
|
|
2396
|
+
}
|
|
2397
|
+
]
|
|
2398
|
+
}
|
|
2399
|
+
],
|
|
2400
|
+
knownModels: AZURE_OPENAI_KNOWN_MODELS,
|
|
2401
|
+
// Azure's list-deployments endpoint is on the control plane (ARM) and
|
|
2402
|
+
// requires AAD credentials the data-plane API key doesn't carry. Return
|
|
2403
|
+
// the curated set from the manifest.
|
|
2404
|
+
supportsModelListing: false,
|
|
2405
|
+
docsUrl: "https://learn.microsoft.com/en-us/azure/ai-services/openai/reference"
|
|
2406
|
+
};
|
|
2407
|
+
|
|
2408
|
+
// src/adapters/azure-openai/adapter.ts
|
|
2409
|
+
var AzureOpenAIAdapter = class {
|
|
2410
|
+
vendor = azureOpenAIManifest.vendor;
|
|
2411
|
+
acceptedAuth = ["azureOpenAIApiKey"];
|
|
2412
|
+
client;
|
|
2413
|
+
init(auth, client) {
|
|
2414
|
+
if (auth.kind !== "azureOpenAIApiKey") {
|
|
2415
|
+
throw new Error(
|
|
2416
|
+
`AzureOpenAIAdapter: unsupported auth kind '${auth.kind}'`
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2419
|
+
if (!auth.apiKey) {
|
|
2420
|
+
throw new Error("AzureOpenAIAdapter: apiKey is required");
|
|
2421
|
+
}
|
|
2422
|
+
if (!auth.endpoint) {
|
|
2423
|
+
throw new Error("AzureOpenAIAdapter: endpoint is required");
|
|
2424
|
+
}
|
|
2425
|
+
if (!auth.deployment) {
|
|
2426
|
+
throw new Error("AzureOpenAIAdapter: deployment is required");
|
|
2427
|
+
}
|
|
2428
|
+
if (!auth.apiVersion) {
|
|
2429
|
+
throw new Error("AzureOpenAIAdapter: apiVersion is required");
|
|
2430
|
+
}
|
|
2431
|
+
this.client = new import_openai3.AzureOpenAI({
|
|
2432
|
+
apiKey: auth.apiKey,
|
|
2433
|
+
endpoint: auth.endpoint,
|
|
2434
|
+
apiVersion: auth.apiVersion,
|
|
2435
|
+
deployment: auth.deployment,
|
|
2436
|
+
...client?.timeout !== void 0 ? { timeout: client.timeout } : {},
|
|
2437
|
+
...client?.maxRetries !== void 0 ? { maxRetries: client.maxRetries } : {}
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
stream(req) {
|
|
2441
|
+
return streamFromOpenAI(this.ensureClient(), req, {
|
|
2442
|
+
knownModels: azureOpenAIManifest.knownModels,
|
|
2443
|
+
tokensParam: "max_completion_tokens"
|
|
2444
|
+
});
|
|
2445
|
+
}
|
|
2446
|
+
appendAssistantToolCall(history, toolCalls) {
|
|
2447
|
+
return appendOpenAIAssistantToolCall(history, toolCalls);
|
|
2448
|
+
}
|
|
2449
|
+
appendToolResult(history, toolCallId, result) {
|
|
2450
|
+
return appendOpenAIToolResult(history, toolCallId, result);
|
|
2451
|
+
}
|
|
2452
|
+
async listAvailableModels() {
|
|
2453
|
+
return [...azureOpenAIManifest.knownModels];
|
|
2454
|
+
}
|
|
2455
|
+
async testCredential() {
|
|
2456
|
+
const client = this.ensureClient();
|
|
2457
|
+
await client.chat.completions.create({
|
|
2458
|
+
// Azure ignores `model` when a deployment is in the URL, but the SDK
|
|
2459
|
+
// still requires it as a parameter.
|
|
2460
|
+
model: "probe",
|
|
2461
|
+
messages: [{ role: "user", content: "ping" }],
|
|
2462
|
+
// Use `max_completion_tokens` (not legacy `max_tokens`): gpt-5 family
|
|
2463
|
+
// and o-series reasoning models return 400 on the legacy parameter.
|
|
2464
|
+
// The newer name is a superset — also accepted by gpt-4o, gpt-4-turbo,
|
|
2465
|
+
// and gpt-3.5-turbo deployments — so it's the safe choice for a probe
|
|
2466
|
+
// that has to work regardless of the underlying deployment model.
|
|
2467
|
+
max_completion_tokens: 1,
|
|
2468
|
+
stream: false
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
async warmup() {
|
|
2472
|
+
}
|
|
2473
|
+
ensureClient() {
|
|
2474
|
+
if (!this.client) {
|
|
2475
|
+
throw new Error(
|
|
2476
|
+
"AzureOpenAIAdapter: init() must be called before stream()/listAvailableModels()"
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
return this.client;
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
|
|
2483
|
+
// src/adapters/azure-openai/factory.ts
|
|
2484
|
+
var azureOpenAIFactory = {
|
|
2485
|
+
vendor: azureOpenAIManifest.vendor,
|
|
2486
|
+
manifest: azureOpenAIManifest,
|
|
2487
|
+
create: () => new AzureOpenAIAdapter()
|
|
2488
|
+
};
|
|
2489
|
+
|
|
2273
2490
|
// src/adapters/index.ts
|
|
2274
2491
|
registerAdapter(openAIFactory);
|
|
2275
2492
|
registerAdapter(deepseekFactory);
|
|
@@ -2278,6 +2495,7 @@ registerAdapter(googleFactory);
|
|
|
2278
2495
|
registerAdapter(vertexGeminiFactory);
|
|
2279
2496
|
registerAdapter(vertexOpenAIFactory);
|
|
2280
2497
|
registerAdapter(bedrockFactory);
|
|
2498
|
+
registerAdapter(azureOpenAIFactory);
|
|
2281
2499
|
|
|
2282
2500
|
// src/normalize-auth.ts
|
|
2283
2501
|
function normalizeAuth(vendor, raw) {
|
|
@@ -2298,6 +2516,8 @@ function normalizeAuth(vendor, raw) {
|
|
|
2298
2516
|
return normalizeVertex(vendor, raw);
|
|
2299
2517
|
case "bedrock":
|
|
2300
2518
|
return normalizeBedrock(raw);
|
|
2519
|
+
case "azure-openai":
|
|
2520
|
+
return normalizeAzureOpenAI(raw);
|
|
2301
2521
|
default:
|
|
2302
2522
|
throw new Error(
|
|
2303
2523
|
`normalizeAuth: unknown vendor '${vendor}'. If this is a custom adapter, construct the AuthSpec directly.`
|
|
@@ -2377,6 +2597,27 @@ function normalizeBedrock(raw) {
|
|
|
2377
2597
|
`normalizeAuth: vendor 'bedrock' requires either (access_key_id + secret_access_key) or api_key`
|
|
2378
2598
|
);
|
|
2379
2599
|
}
|
|
2600
|
+
function normalizeAzureOpenAI(raw) {
|
|
2601
|
+
if (!raw.api_key) {
|
|
2602
|
+
throw new Error(`normalizeAuth: vendor 'azure-openai' requires 'api_key'`);
|
|
2603
|
+
}
|
|
2604
|
+
if (!raw.endpoint) {
|
|
2605
|
+
throw new Error(`normalizeAuth: vendor 'azure-openai' requires 'endpoint'`);
|
|
2606
|
+
}
|
|
2607
|
+
if (!raw.deployment) {
|
|
2608
|
+
throw new Error(`normalizeAuth: vendor 'azure-openai' requires 'deployment'`);
|
|
2609
|
+
}
|
|
2610
|
+
if (!raw.api_version) {
|
|
2611
|
+
throw new Error(`normalizeAuth: vendor 'azure-openai' requires 'api_version'`);
|
|
2612
|
+
}
|
|
2613
|
+
return {
|
|
2614
|
+
kind: "azureOpenAIApiKey",
|
|
2615
|
+
apiKey: raw.api_key,
|
|
2616
|
+
endpoint: raw.endpoint,
|
|
2617
|
+
deployment: raw.deployment,
|
|
2618
|
+
apiVersion: raw.api_version
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2380
2621
|
function parseServiceKey(value) {
|
|
2381
2622
|
if (typeof value === "string") {
|
|
2382
2623
|
try {
|
|
@@ -2388,6 +2629,51 @@ function parseServiceKey(value) {
|
|
|
2388
2629
|
return value;
|
|
2389
2630
|
}
|
|
2390
2631
|
|
|
2632
|
+
// src/pick-auth-kind.ts
|
|
2633
|
+
function pickAuthKind(vendor, raw) {
|
|
2634
|
+
const factory = getAdapterFactory(vendor);
|
|
2635
|
+
const { authKinds } = factory.manifest;
|
|
2636
|
+
if (authKinds.length === 1) {
|
|
2637
|
+
return authKinds[0];
|
|
2638
|
+
}
|
|
2639
|
+
switch (vendor) {
|
|
2640
|
+
case "bedrock": {
|
|
2641
|
+
const iam = authKinds.find((k) => k.kind === "bedrockIam");
|
|
2642
|
+
const apiKey = authKinds.find((k) => k.kind === "bedrockApiKey");
|
|
2643
|
+
if (raw.access_key_id && raw.secret_access_key) {
|
|
2644
|
+
if (!iam) throw new Error(`pickAuthKind: bedrock manifest missing 'bedrockIam'`);
|
|
2645
|
+
return iam;
|
|
2646
|
+
}
|
|
2647
|
+
if (raw.api_key) {
|
|
2648
|
+
if (!apiKey) throw new Error(`pickAuthKind: bedrock manifest missing 'bedrockApiKey'`);
|
|
2649
|
+
return apiKey;
|
|
2650
|
+
}
|
|
2651
|
+
throw new Error(
|
|
2652
|
+
`pickAuthKind: bedrock credential missing both 'api_key' and ('access_key_id' + 'secret_access_key')`
|
|
2653
|
+
);
|
|
2654
|
+
}
|
|
2655
|
+
case "google": {
|
|
2656
|
+
const svc = authKinds.find((k) => k.kind === "googleServiceAccount");
|
|
2657
|
+
const apiKey = authKinds.find((k) => k.kind === "googleApiKey");
|
|
2658
|
+
if (raw.service_key) {
|
|
2659
|
+
if (!svc) throw new Error(`pickAuthKind: google manifest missing 'googleServiceAccount'`);
|
|
2660
|
+
return svc;
|
|
2661
|
+
}
|
|
2662
|
+
if (raw.api_key) {
|
|
2663
|
+
if (!apiKey) throw new Error(`pickAuthKind: google manifest missing 'googleApiKey'`);
|
|
2664
|
+
return apiKey;
|
|
2665
|
+
}
|
|
2666
|
+
throw new Error(
|
|
2667
|
+
`pickAuthKind: google credential missing both 'api_key' and 'service_key'`
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
default:
|
|
2671
|
+
throw new Error(
|
|
2672
|
+
`pickAuthKind: vendor '${vendor}' declares ${authKinds.length} authKinds but has no discriminator rule. Add one in src/pick-auth-kind.ts.`
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2391
2677
|
// src/index.ts
|
|
2392
2678
|
async function createLlm(args) {
|
|
2393
2679
|
const factory = getAdapterFactory(args.vendor);
|
|
@@ -2409,6 +2695,7 @@ async function createLlm(args) {
|
|
|
2409
2695
|
getManifest,
|
|
2410
2696
|
listVendors,
|
|
2411
2697
|
normalizeAuth,
|
|
2698
|
+
pickAuthKind,
|
|
2412
2699
|
registerAdapter,
|
|
2413
2700
|
replaceAdapter,
|
|
2414
2701
|
unregisterAdapter
|