@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.
@@ -113,7 +113,10 @@ async function* streamFromOpenAI(client, req, options) {
113
113
  }
114
114
  if (req.temperature !== void 0) body.temperature = req.temperature;
115
115
  const effectiveMaxTokens = req.maxTokens ?? options.defaultMaxTokens;
116
- if (effectiveMaxTokens !== void 0) body.max_tokens = effectiveMaxTokens;
116
+ if (effectiveMaxTokens !== void 0) {
117
+ const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
118
+ body[param] = effectiveMaxTokens;
119
+ }
117
120
  let stream;
118
121
  try {
119
122
  stream = await client.chat.completions.create(body, { signal: req.signal });
@@ -296,6 +299,9 @@ function capabilitiesFor(modelId, knownModels) {
296
299
  if (known) return known.capabilities;
297
300
  return defaultCapabilitiesForUnknown(modelId);
298
301
  }
302
+ function needsMaxCompletionTokens(modelId) {
303
+ return /^(o\d|gpt-5)/i.test(modelId);
304
+ }
299
305
  function defaultCapabilitiesForUnknown(modelId) {
300
306
  const isReasoning = /^o[13]([-/]|$)/i.test(modelId);
301
307
  if (isReasoning) {
@@ -1673,7 +1679,12 @@ var VertexOpenAIAdapter = class {
1673
1679
  stream(req) {
1674
1680
  return streamFromOpenAI(this.ensureClient(), req, {
1675
1681
  knownModels: vertexOpenAIManifest.knownModels,
1676
- defaultMaxTokens: 4096
1682
+ defaultMaxTokens: 4096,
1683
+ // Pin legacy `max_tokens`: Vertex's OpenAI-compat partner-model
1684
+ // endpoint predates `max_completion_tokens` and may not recognize it.
1685
+ // The model-id heuristic wouldn't catch a partner model named in the
1686
+ // OpenAI style (unlikely today, but defensive).
1687
+ tokensParam: "max_tokens"
1677
1688
  });
1678
1689
  }
1679
1690
  appendAssistantToolCall(history, toolCalls) {
@@ -2258,6 +2269,211 @@ var bedrockFactory = {
2258
2269
  create: () => new BedrockAdapter()
2259
2270
  };
2260
2271
 
2272
+ // src/adapters/azure-openai/adapter.ts
2273
+ var import_openai3 = require("openai");
2274
+
2275
+ // src/adapters/azure-openai/manifest.ts
2276
+ var AZURE_OPENAI_KNOWN_MODELS = [
2277
+ {
2278
+ id: "gpt-4o",
2279
+ displayName: "GPT-4o (on Azure)",
2280
+ capabilities: {
2281
+ streaming: true,
2282
+ tools: true,
2283
+ vision: true,
2284
+ systemPrompt: true,
2285
+ maxContextTokens: 128e3
2286
+ }
2287
+ },
2288
+ {
2289
+ id: "gpt-4o-mini",
2290
+ displayName: "GPT-4o mini (on Azure)",
2291
+ capabilities: {
2292
+ streaming: true,
2293
+ tools: true,
2294
+ vision: true,
2295
+ systemPrompt: true,
2296
+ maxContextTokens: 128e3
2297
+ }
2298
+ },
2299
+ {
2300
+ id: "gpt-4-turbo",
2301
+ displayName: "GPT-4 Turbo (on Azure)",
2302
+ capabilities: {
2303
+ streaming: true,
2304
+ tools: true,
2305
+ vision: true,
2306
+ systemPrompt: true,
2307
+ maxContextTokens: 128e3
2308
+ }
2309
+ },
2310
+ {
2311
+ // Azure spells it `gpt-35-turbo` (no dot). Keep their spelling for the id
2312
+ // so capability lookups against deployment names that echo the Azure id
2313
+ // hit.
2314
+ id: "gpt-35-turbo",
2315
+ displayName: "GPT-3.5 Turbo (on Azure)",
2316
+ capabilities: {
2317
+ streaming: true,
2318
+ tools: true,
2319
+ vision: false,
2320
+ systemPrompt: true,
2321
+ maxContextTokens: 16385
2322
+ }
2323
+ },
2324
+ {
2325
+ id: "o1-preview",
2326
+ displayName: "o1 preview \u2014 reasoning (on Azure)",
2327
+ capabilities: {
2328
+ streaming: false,
2329
+ tools: false,
2330
+ vision: false,
2331
+ systemPrompt: false,
2332
+ maxContextTokens: 128e3
2333
+ }
2334
+ },
2335
+ {
2336
+ id: "o1-mini",
2337
+ displayName: "o1 mini \u2014 reasoning (on Azure)",
2338
+ capabilities: {
2339
+ streaming: false,
2340
+ tools: false,
2341
+ vision: false,
2342
+ systemPrompt: false,
2343
+ maxContextTokens: 128e3
2344
+ }
2345
+ }
2346
+ ];
2347
+ var azureOpenAIManifest = {
2348
+ vendor: "azure-openai",
2349
+ displayName: "Azure OpenAI",
2350
+ authKinds: [
2351
+ {
2352
+ kind: "azureOpenAIApiKey",
2353
+ displayName: "API Key",
2354
+ fields: [
2355
+ {
2356
+ name: "apiKey",
2357
+ label: "API Key",
2358
+ type: "password",
2359
+ required: true,
2360
+ help: "Azure OpenAI resource key. Find it in the Azure portal under your OpenAI resource \u2192 Keys and Endpoint."
2361
+ },
2362
+ {
2363
+ name: "endpoint",
2364
+ label: "Endpoint",
2365
+ type: "url",
2366
+ required: true,
2367
+ help: "Resource endpoint URL, e.g. https://my-resource.openai.azure.com. Shown in the Azure portal alongside the keys."
2368
+ },
2369
+ {
2370
+ name: "deployment",
2371
+ label: "Deployment Name",
2372
+ type: "text",
2373
+ required: true,
2374
+ help: "The name you chose for the deployment in Azure AI Studio (NOT the underlying model id \u2014 deployments can be named anything)."
2375
+ },
2376
+ {
2377
+ name: "apiVersion",
2378
+ label: "API Version",
2379
+ type: "text",
2380
+ required: true,
2381
+ default: "2024-10-21",
2382
+ 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."
2383
+ }
2384
+ ]
2385
+ }
2386
+ ],
2387
+ knownModels: AZURE_OPENAI_KNOWN_MODELS,
2388
+ // Azure's list-deployments endpoint is on the control plane (ARM) and
2389
+ // requires AAD credentials the data-plane API key doesn't carry. Return
2390
+ // the curated set from the manifest.
2391
+ supportsModelListing: false,
2392
+ docsUrl: "https://learn.microsoft.com/en-us/azure/ai-services/openai/reference"
2393
+ };
2394
+
2395
+ // src/adapters/azure-openai/adapter.ts
2396
+ var AzureOpenAIAdapter = class {
2397
+ vendor = azureOpenAIManifest.vendor;
2398
+ acceptedAuth = ["azureOpenAIApiKey"];
2399
+ client;
2400
+ init(auth, client) {
2401
+ if (auth.kind !== "azureOpenAIApiKey") {
2402
+ throw new Error(
2403
+ `AzureOpenAIAdapter: unsupported auth kind '${auth.kind}'`
2404
+ );
2405
+ }
2406
+ if (!auth.apiKey) {
2407
+ throw new Error("AzureOpenAIAdapter: apiKey is required");
2408
+ }
2409
+ if (!auth.endpoint) {
2410
+ throw new Error("AzureOpenAIAdapter: endpoint is required");
2411
+ }
2412
+ if (!auth.deployment) {
2413
+ throw new Error("AzureOpenAIAdapter: deployment is required");
2414
+ }
2415
+ if (!auth.apiVersion) {
2416
+ throw new Error("AzureOpenAIAdapter: apiVersion is required");
2417
+ }
2418
+ this.client = new import_openai3.AzureOpenAI({
2419
+ apiKey: auth.apiKey,
2420
+ endpoint: auth.endpoint,
2421
+ apiVersion: auth.apiVersion,
2422
+ deployment: auth.deployment,
2423
+ ...client?.timeout !== void 0 ? { timeout: client.timeout } : {},
2424
+ ...client?.maxRetries !== void 0 ? { maxRetries: client.maxRetries } : {}
2425
+ });
2426
+ }
2427
+ stream(req) {
2428
+ return streamFromOpenAI(this.ensureClient(), req, {
2429
+ knownModels: azureOpenAIManifest.knownModels,
2430
+ tokensParam: "max_completion_tokens"
2431
+ });
2432
+ }
2433
+ appendAssistantToolCall(history, toolCalls) {
2434
+ return appendOpenAIAssistantToolCall(history, toolCalls);
2435
+ }
2436
+ appendToolResult(history, toolCallId, result) {
2437
+ return appendOpenAIToolResult(history, toolCallId, result);
2438
+ }
2439
+ async listAvailableModels() {
2440
+ return [...azureOpenAIManifest.knownModels];
2441
+ }
2442
+ async testCredential() {
2443
+ const client = this.ensureClient();
2444
+ await client.chat.completions.create({
2445
+ // Azure ignores `model` when a deployment is in the URL, but the SDK
2446
+ // still requires it as a parameter.
2447
+ model: "probe",
2448
+ messages: [{ role: "user", content: "ping" }],
2449
+ // Use `max_completion_tokens` (not legacy `max_tokens`): gpt-5 family
2450
+ // and o-series reasoning models return 400 on the legacy parameter.
2451
+ // The newer name is a superset — also accepted by gpt-4o, gpt-4-turbo,
2452
+ // and gpt-3.5-turbo deployments — so it's the safe choice for a probe
2453
+ // that has to work regardless of the underlying deployment model.
2454
+ max_completion_tokens: 1,
2455
+ stream: false
2456
+ });
2457
+ }
2458
+ async warmup() {
2459
+ }
2460
+ ensureClient() {
2461
+ if (!this.client) {
2462
+ throw new Error(
2463
+ "AzureOpenAIAdapter: init() must be called before stream()/listAvailableModels()"
2464
+ );
2465
+ }
2466
+ return this.client;
2467
+ }
2468
+ };
2469
+
2470
+ // src/adapters/azure-openai/factory.ts
2471
+ var azureOpenAIFactory = {
2472
+ vendor: azureOpenAIManifest.vendor,
2473
+ manifest: azureOpenAIManifest,
2474
+ create: () => new AzureOpenAIAdapter()
2475
+ };
2476
+
2261
2477
  // src/adapters/index.ts
2262
2478
  registerAdapter(openAIFactory);
2263
2479
  registerAdapter(deepseekFactory);
@@ -2266,6 +2482,7 @@ registerAdapter(googleFactory);
2266
2482
  registerAdapter(vertexGeminiFactory);
2267
2483
  registerAdapter(vertexOpenAIFactory);
2268
2484
  registerAdapter(bedrockFactory);
2485
+ registerAdapter(azureOpenAIFactory);
2269
2486
 
2270
2487
  // src/index.ts
2271
2488
  async function createLlm(args) {