@staticeng/opencode-litellm 0.2.4 → 0.2.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/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -61,7 +61,7 @@ When `includeBackends` is present, models are candidates when `model_info.backen
61
61
 
62
62
  LiteLLM metadata does not expose every OpenCode model field. The plugin includes exact built-in contracts for the currently approved GPT-5.4, GPT-5.5, GPT-5.6, DeepSeek V4 Flash, and Qwen3.8 aliases. Use `overrides` to customize those defaults or to add metadata for unknown models.
63
63
 
64
- When LiteLLM publishes `model_info.supported_reasoning_efforts`, the plugin maps that list to OpenCode variants automatically for unknown models. Known contracts use exact alias membership and win over absent, incomplete, or conflicting discovery metadata. No substring, suffix, provider namespace, or base-model inference is used.
64
+ When LiteLLM publishes `model_info.supported_reasoning_efforts`, the plugin maps that list to OpenCode variants automatically. Known contracts contribute their approved defaults; discovered extra efforts remain available unless that exact contract explicitly closes discovery. Currently only `qwen3.8-flash-next` closes discovery so unverified efforts cannot become active. No substring, suffix, provider namespace, or base-model inference is used.
65
65
 
66
66
  ```json
67
67
  {
@@ -102,9 +102,9 @@ The built-in mode matrix is:
102
102
  | GPT-5.6 Luna / Sol / Terra | `none`, `low`, `medium`, `high`, `xhigh`, `max` | `medium` |
103
103
  | DeepSeek V4 Flash | `off`, `low`, `high`, `max` | `max` |
104
104
  | Qwen3.8 27B refusal dial | `off`, `low`, `medium`, `xhigh` | `xhigh` |
105
- | Qwen3.8 Flash Next | `off`, `low` | `low` |
105
+ | Qwen3.8 Flash Next | `off`, `low`, `medium`, `xhigh` | `xhigh` |
106
106
 
107
- DeepSeek `off` sends canonical `none`. Qwen `off` sends only `chat_template_kwargs.enable_thinking=false`, with no reasoning effort. `ultra` is not generated by a built-in contract. For requests without an explicit named variant, the plugin supplies the row's contract default through model options; an explicit variant is merged afterward and wins. Qwen's explicit `off` cleanup removes the model's default effort before serialization. The `variantDefault` compatibility marker is UI-only and is stripped before requests for exact built-in aliases.
107
+ DeepSeek `off` sends canonical `none`. Qwen `off` sends only `chat_template_kwargs.enable_thinking=false`, with no reasoning effort. `ultra` is not generated by a built-in contract. Flash Next activates exactly `off`, `low`, `medium`, and `xhigh`: discovered extras such as `ultra` are suppressed, V2 omits `minimal`, `high`, and `max`, and the legacy OpenCode surface disables unsupported generic choices. For requests without an explicit named variant, the plugin supplies the row's contract default through model options; an explicit variant is merged afterward and wins. Qwen's explicit `off` cleanup removes the model's default effort before serialization. The `variantDefault` compatibility marker is UI-only and is stripped before requests for exact built-in aliases.
108
108
 
109
109
  The exact dynamically discovered alias `qwen3.8-flash-next` also receives verified static metadata that overrides incomplete or conflicting LiteLLM group metadata: text and image input, text output, attachment, reasoning, tool calling, and a 262144-token context. Its output limit remains unknown and is represented by the package's `0` sentinel; pricing and other modalities are not supplied. The contract is still discovery-gated and never creates the alias when LiteLLM omits it.
110
110
 
package/dist/helpers.d.ts CHANGED
File without changes
package/dist/helpers.js CHANGED
File without changes
package/dist/index.d.ts CHANGED
File without changes
package/dist/index.js CHANGED
File without changes
package/dist/litellm.d.ts CHANGED
File without changes
package/dist/litellm.js CHANGED
File without changes
package/dist/mapping.d.ts CHANGED
File without changes
package/dist/mapping.js CHANGED
@@ -327,6 +327,8 @@ function generatedModel(model, tombstones = false) {
327
327
  if (!name)
328
328
  return undefined;
329
329
  const mappedModalities = modalities(model);
330
+ const discoveredVariants = supportsReasoning(model) ? reasoningVariants(model) : undefined;
331
+ const suppressDiscoveredVariants = modelContract(name)?.suppressDiscoveredVariants === true;
330
332
  const generated = {
331
333
  id: name,
332
334
  name,
@@ -336,7 +338,7 @@ function generatedModel(model, tombstones = false) {
336
338
  modalities: mappedModalities,
337
339
  ...(mappedModalities.input.includes("image") || mappedModalities.input.includes("pdf") ? { attachment: true } : {}),
338
340
  ...(supportsReasoning(model) ? { reasoning: true } : {}),
339
- ...(supportsReasoning(model) && reasoningVariants(model) ? { variants: reasoningVariants(model) } : {}),
341
+ ...(discoveredVariants && !suppressDiscoveredVariants ? { variants: discoveredVariants } : {}),
340
342
  ...(model.model_info?.supports_function_calling || model.model_info?.supports_tool_choice ? { tool_call: true } : {}),
341
343
  };
342
344
  const defaults = contractDefaults(name, tombstones);
@@ -368,20 +370,26 @@ function v2Variants(model) {
368
370
  return undefined;
369
371
  return Object.entries(variants).map(([id, value]) => ({ id, body: v2VariantBody(value) }));
370
372
  }
371
- function contractV2Variants(name, override) {
373
+ function contractV2Variants(name, model, override) {
372
374
  const entry = modelContract(name);
373
375
  if (!entry)
374
376
  return undefined;
375
377
  const variants = entry.modes.map((mode) => ({ id: mode.id, body: { ...mode.v2Body } }));
376
- if (!isRecord(override?.variants))
377
- return variants;
378
378
  const byID = new Map(variants.map((variant) => [variant.id, variant]));
379
- for (const [id, value] of Object.entries(override.variants)) {
380
- const current = byID.get(id);
381
- byID.set(id, {
382
- id,
383
- body: deepMerge(current?.body ?? {}, v2VariantBody(value)),
384
- });
379
+ if (isRecord(override?.variants)) {
380
+ for (const [id, value] of Object.entries(override.variants)) {
381
+ const current = byID.get(id);
382
+ byID.set(id, {
383
+ id,
384
+ body: deepMerge(current?.body ?? {}, v2VariantBody(value)),
385
+ });
386
+ }
387
+ }
388
+ if (!entry.suppressDiscoveredVariants && isRecord(model.variants)) {
389
+ for (const [id, value] of Object.entries(model.variants)) {
390
+ if (!byID.has(id))
391
+ byID.set(id, { id, body: v2VariantBody(value) });
392
+ }
385
393
  }
386
394
  return Array.from(byID.values());
387
395
  }
@@ -449,7 +457,7 @@ export function mapModelsV2(models, options = {}) {
449
457
  const legacy = mapModels(models, options);
450
458
  return Object.fromEntries(Object.entries(legacy).map(([name, model]) => {
451
459
  const mapped = v2Model(model, options.baseURL);
452
- const variants = contractV2Variants(name, options.overrides?.[name]);
460
+ const variants = contractV2Variants(name, model, options.overrides?.[name]);
453
461
  return [name, variants ? { ...mapped, variants } : mapped];
454
462
  }));
455
463
  }
package/dist/merge.d.ts CHANGED
File without changes
package/dist/merge.js CHANGED
File without changes
File without changes
@@ -12,7 +12,7 @@ function effortModes(ids) {
12
12
  v2Body: freezeJson({ reasoning_effort: id }),
13
13
  })));
14
14
  }
15
- function contract(family, aliases, modes, defaultMode, metadata) {
15
+ function contract(family, aliases, modes, defaultMode, metadata, suppressDiscoveredVariants = false) {
16
16
  if (!modes.some((mode) => mode.id === defaultMode))
17
17
  throw new Error(`Model contract ${family} has an invalid default`);
18
18
  return Object.freeze({
@@ -22,6 +22,7 @@ function contract(family, aliases, modes, defaultMode, metadata) {
22
22
  defaultMode,
23
23
  reasoning: true,
24
24
  variantDefault: false,
25
+ ...(suppressDiscoveredVariants ? { suppressDiscoveredVariants: true } : {}),
25
26
  ...(metadata ? { metadata } : {}),
26
27
  });
27
28
  }
@@ -44,7 +45,6 @@ const QWEN_MODES = Object.freeze([
44
45
  Object.freeze({ id: "medium", legacy: freezeJson({ reasoningEffort: "medium" }), v2Body: freezeJson({ reasoning_effort: "medium" }) }),
45
46
  Object.freeze({ id: "xhigh", legacy: freezeJson({ reasoningEffort: "xhigh" }), v2Body: freezeJson({ reasoning_effort: "xhigh" }) }),
46
47
  ]);
47
- const QWEN_FLASH_NEXT_MODES = Object.freeze(QWEN_MODES.slice(0, 2));
48
48
  const QWEN_FLASH_NEXT_METADATA = Object.freeze({
49
49
  modalities: Object.freeze({
50
50
  input: Object.freeze(["text", "image"]),
@@ -69,7 +69,7 @@ export const MODEL_CONTRACTS = Object.freeze([
69
69
  contract("GPT-5.6 Terra", chatGptAliases("gpt-5.6-terra"), GPT_MAX_MODES, "medium"),
70
70
  contract("DeepSeek V4 Flash", ["deepseek-v4-flash-fp8-mtp", "deepseek-v4-flash-fp8-mtp-norefusal"], DEEPSEEK_MODES, "max"),
71
71
  contract("Qwen3.8", ["qwen3.8-27b-refusal-dial"], QWEN_MODES, "xhigh"),
72
- contract("Qwen3.8", ["qwen3.8-flash-next"], QWEN_FLASH_NEXT_MODES, "low", QWEN_FLASH_NEXT_METADATA),
72
+ contract("Qwen3.8", ["qwen3.8-flash-next"], QWEN_MODES, "xhigh", QWEN_FLASH_NEXT_METADATA, true),
73
73
  ]);
74
74
  export const RETIRED_MODEL_ALIASES = Object.freeze([
75
75
  ...chatGptAliases("gpt-5.3-codex"),
package/dist/options.d.ts CHANGED
File without changes
package/dist/options.js CHANGED
File without changes
package/dist/types.d.ts CHANGED
@@ -23,6 +23,7 @@ export type ModelContract = Readonly<{
23
23
  defaultMode: string;
24
24
  reasoning: true;
25
25
  variantDefault: false;
26
+ suppressDiscoveredVariants?: true;
26
27
  metadata?: ModelContractMetadata;
27
28
  }>;
28
29
  export type OpenCodeModel = JsonObject & {
package/dist/types.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staticeng/opencode-litellm",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "OpenCode plugin that discovers LiteLLM models at runtime.",
5
5
  "type": "module",
6
6
  "license": "MIT",