Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). Versions use [Se

## [Unreleased]

## [1.23.0] — 2026-10-15

### Added
- Current vendor models, checked against primary docs on 2026-10-15 (#112, phase 2):
- Workers AI: `@cf/meta/llama-3.1-8b-instruct-fp8`, `@cf/ibm-granite/granite-4.0-h-micro`, `@cf/aisingapore/gemma-sea-lion-v4-27b-it`.
- OpenAI: `gpt-6-astra`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`.
- Anthropic: `claude-fable-5-1`, `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`.
- `ModelCatalogEntry.explicitOnly` (optional): the model is served when a request names it, but recommendations and automatic routing skip it. The new OpenAI and Anthropic models and SEA-LION are explicit-only, so OpenAI and Anthropic defaults do not change in this release.
- `MODELS` constants for the new models and for current Workers AI models (`CF_GLM_5_3`, `CF_GLM_5_3_FLASH`, `CF_KIMI_K2_6`, `CF_DEEPSEEK_V4_PRO`, `CF_DEEPSEEK_V4_FLASH`, `CF_GPT_OSS_120B`, `CF_GPT_OSS_20B`, `CF_GEMMA_4_26B`, `CF_QWEN_3_8_27B`, `CF_LLAMA_3_3_70B_FAST`, `CF_LLAMA_3_1_8B_FP8`, `CF_GRANITE_4_MICRO`).

### Changed
- The package is documented as a Cloudflare-first router. A test requires a Workers AI model to rank first for every use case when all providers are configured and healthy (no health, ledger or request context).
- Workers AI models that Cloudflare deprecated are now `retired` in the catalog and are no longer auto-routed: Llama 3.1 8B / 70B, Llama 3 8B, Llama 2 7B int8, Phi-2 and Mistral 7B v0.1 (2026-05-30), OpenChat 3.5, TinyLlama and the four Qwen 1.5 models (2025-10-01). The adapter still accepts them by name. Their `MODELS` constants are marked `@deprecated`.
- `gpt-4`, `gpt-4-turbo` and `gpt-3.5-turbo` (OpenAI shutdown 2026-10-23) and the invalid `gpt-3.5-turbo-16k` are `retired` in the catalog and no longer auto-routed. The adapter still accepts them by name.
- `gpt-4o-mini` stays the OpenAI default. `getRoutingInfo()` reports its 2027-01-14 shutdown in `deprecationWarning`; response metadata does not, because the model is still `active`.
- Claude Opus 4.6, Sonnet 4.6 and Haiku 4.5 stay the Anthropic defaults; their descriptions note that Anthropic lists them as legacy.
- Routing changes from the corrected data:
- Cloudflare long-context requests (and `getProviderDefaultModel('cloudflare', ...)` for long requests) now pick `@cf/zai-org/glm-5.3-flash` instead of `@cf/deepseek-ai/deepseek-v4-flash-0731`, because DeepSeek V4 Flash's context window was corrected from 1.31M to 1.05M tokens and long-context scoring weighs context size.
- `@cf/meta/llama-3.1-8b-instruct-fp8` and `@cf/ibm-granite/granite-4.0-h-micro` join the recommendation lists and fallback pools; neither ranks first for any use case.
- OpenAI's fallback pool shrinks to `gpt-4o-mini` now that `gpt-4`, `gpt-4-turbo` and `gpt-3.5-turbo` are retired.
- OpenAI responses that name a dated snapshot are now priced by their alias. This includes the default `gpt-4o-mini`, whose responses name `gpt-4o-mini-2024-07-18` and were recorded at $0 cost in 1.22; ledgers, budgets and cost tracking will now show real spend for it.
- `@cf/qwen/qwen2.5-coder-32b-instruct` requests that include tools now throw a `ConfigurationError` before any call, because the catalog no longer claims function calling for it (see Fixed).
- OpenAI requests to reasoning models (GPT-5 and later, o-series) send `max_completion_tokens` instead of `max_tokens` and omit `temperature`. `max_completion_tokens` also covers reasoning tokens, so a small `maxTokens` can leave no room for the answer. Only requests that name one of these models are affected.
- Anthropic requests to Claude 5.x models omit `temperature` (non-default values return 400) and default to `max_tokens: 16000` when the request sets none, because these models think by default and thinking counts against `max_tokens`. Preflight cost estimates use the same default.
- Anthropic forced tool choice (`toolChoice: 'required'` or a named function) on Fable 5.1, Opus 5.5 and Sonnet 5.5 now throws a `ConfigurationError` before any API call; those models return 400 for it. Use `toolChoice: 'auto'`. Haiku 5.5 and earlier models still accept it.

### Fixed
- Anthropic JSON mode no longer sends an assistant prefill to Claude Opus 4.6, Sonnet 4.6 or the 5.x models, which reject prefill with a 400. This affected the 1.22 default for JSON requests (`claude-sonnet-4-6`). These models rely on the JSON system instruction; Haiku 4.5 still uses the prefill.
- Streaming JSON mode on models that are prefilled (Haiku 4.5) now restores the opening `{` on the first text chunk, as non-streaming responses already did.
- OpenAI cost was $0 when a response named a dated snapshot (for example `gpt-4o-mini-2024-07-18` or `gpt-5.5-2026-04-23`); IDs with a date suffix are now priced by their alias. Snapshot IDs without a date suffix (for example `gpt-3.5-turbo-0125`) are still not priced. Prompts over 272K tokens on the new 1M-context models are billed at 2x input and 1.5x output.
- Claude Opus 4.8 through the AI Gateway unified catalog no longer receives `temperature` or `top_p`, which Claude 4.7 and later reject.
- Workers AI context windows: Llama 3.3 70B FP8 Fast 24,000 (was 131,072), Llama 3.2 1B 60,000, Llama 3.2 3B 80,000, Qwen3 30B 32,768, Kimi K2.6 and K2.7 Code 262,144, DeepSeek V4 Flash 1,048,576 (was 1,310,720). Kimi K2.7 Code supports vision.
- `@cf/qwen/qwen2.5-coder-32b-instruct` no longer claims function calling; Cloudflare's model page does not list it.
- `deepseek/deepseek-v4-pro` and `anthropic/claude-opus-4.8` are priced from the AI Gateway unified catalog ($1.74/$3.48 and $5/$25 per million tokens) instead of $0, and `deepseek/deepseek-v4-pro` has a 131,072-token context.
- Anthropic cache reads use per-model rates (Fable 5.1 2.5%, Opus 5.5 and Sonnet 5.5 5% of input), and Haiku 5.5 prompts over 100K tokens, cache included, are billed at the 5x long-prompt rate.

### Known limitations
- Claude 5.x thinking blocks are not passed back with tool results, which Anthropic requires for multi-turn tool use. This is why the 5.x models are explicit-only. The adapter also sends `tool_result` blocks without `tool_use_id`, which likely breaks multi-turn tool use on every Claude model (#124).
- `gpt-6-luna` and `gpt-6.1-sol` are not supported yet (tool-calling restrictions on Chat Completions).
- The 16,000-token `max_tokens` default for Claude 5.x does not change the 30-second default `timeout`. It times the wait for response headers, which for a non-streaming request arrive when the response is complete. Long thinking responses from Fable 5.1 or Opus 5.5 can exceed it, and a timeout is retried (`maxRetries`, default 3), so one request can take about two minutes before fallback and each attempt may be billed. Set a larger `timeout` on the Anthropic provider config or use streaming.

## [1.22.1] — 2026-10-15

### Fixed
Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Development status and resume notes: [issue sweep checkpoint](docs/maintenance/issue-sweep.md). The checkpoint identifies APIs and fixes that are still unreleased.

A multi-provider LLM abstraction layer with automatic failover, graduated circuit breakers, cost tracking, and intelligent retry. Built for Cloudflare Workers but runs anywhere with a standard `fetch` API. Extracted from a production orchestration platform handling 80K+ LOC across multiple services.
A Cloudflare-first LLM router: Workers AI models are the primary route, and OpenAI, Anthropic, Cerebras, Groq and NVIDIA NIM serve as secondary providers behind the same interface, with automatic failover, graduated circuit breakers, cost tracking, and intelligent retry. When Workers AI is configured and healthy, catalog routing ranks a Workers AI model first for every use case; breaker state, ledger pressure and request requirements (for example vision) can still move a request to another provider. Built for Cloudflare Workers but runs anywhere with a standard `fetch` API. Extracted from a production orchestration platform handling 80K+ LOC across multiple services.

## Features

Expand Down Expand Up @@ -156,9 +156,9 @@ const llm = LLMProviders.fromEnv(env, {

| Provider | Models | Streaming | Tools | Notes |
|----------|--------|-----------|-------|-------|
| **OpenAI** | GPT-4o Mini, GPT-4 Turbo, GPT-4, GPT-3.5 Turbo | Yes | Yes | Default: `gpt-4o-mini` |
| **Anthropic** | Claude Opus 4.6, Sonnet 4.6, Sonnet 4, Haiku 4.5, 3.7 Sonnet, 3.5 Sonnet/Haiku, 3 Opus/Sonnet | Yes | Yes | Default: `claude-haiku-4-5-20251001` |
| **Cloudflare** | Nemotron-3 120B, Claude Opus 4.8 (CF-managed), Kimi K2.6/K2.7, DeepSeek-R1-Distill, QwQ-32B, GLM-4.7-Flash, DeepSeek V4 Pro, Gemma 4 26B, Llama 4 Scout, GPT-OSS 120B/20B, LLaMA 3.x, Mistral Small 3.1, Qwen 2.5/3, and more | Yes | Nemotron, Kimi, GLM, GPT-OSS, Gemma 4, Llama 4 Scout, Mistral Small | Default is request-aware and catalog-driven; thinking models (DeepSeek-R1, QwQ, GLM) are RESEARCH-only |
| **Cloudflare** (primary) | GLM-5.3 / 5.3 Flash / 5.2 / 4.7 Flash, Kimi K2.6 / K2.7 Code, DeepSeek V4 Flash / Pro, GPT-OSS 120B / 20B, Gemma 4 26B, Qwen 3.8 27B / 3 30B / 2.5 Coder, Llama 4 Scout / 3.3 70B Fast / 3.2 / 3.1 8B FP8, Nemotron-3 120B, Granite 4.0 Micro, Mistral Small 3.1, SEA-LION v4 (explicit requests only), DeepSeek-R1-Distill, QwQ-32B; plus `deepseek/deepseek-v4-pro` and `anthropic/claude-opus-4.8` from the AI Gateway unified catalog | Yes | Most current models (see catalog `supportsTools`) | Default is request-aware and catalog-driven; thinking models (DeepSeek-R1, QwQ, GLM-4.7 Flash) are RESEARCH-only. Kimi, GLM-5.x and DeepSeek V4 need a Workers Paid plan or AI Gateway credits. Models Cloudflare deprecated (Llama 3.1/3 8B, Llama 3.1 70B, Llama 2 7B, Mistral 7B, Phi-2, Qwen 1.5, TinyLlama, OpenChat) are still accepted when named but are never auto-routed; Kimi K2.5 and Gemma 3 12B are no longer accepted |
| **OpenAI** | GPT-4o Mini (shutdown 2027-01-14); GPT-6 Astra, GPT-5.6 Sol / Terra / Luna, GPT-5.5 (explicit requests only); GPT-4, GPT-4 Turbo, GPT-3.5 Turbo (shutdown 2026-10-23, no longer auto-routed) | Yes | Yes | Default: `gpt-4o-mini`. GPT-5 and later get `max_completion_tokens` (which includes reasoning tokens) and no `temperature` |
| **Anthropic** | Opus 4.6, Sonnet 4.6, Haiku 4.5 (legacy at Anthropic); Fable 5.1, Opus 5.5, Sonnet 5.5, Haiku 5.5 (explicit requests only); retired 4 / 3.x IDs | Yes | Yes | Default: catalog-driven by request shape: `claude-haiku-4-5-20251001` for plain requests, `claude-sonnet-4-6` for tools, JSON mode (`response_format`), vision and long context. `claude-opus-4-6` is picked only when a caller asks for the high-performance or research workload (`metadata.useCase` on factory requests, or the workload helpers). Claude 5.x requests omit `temperature` and default `max_tokens` to 16,000; a non-streaming request can exceed the 30-second default `timeout`, which is then retried (`maxRetries`, default 3), so raise `timeout` or stream for long thinking responses; Fable 5.1, Opus 5.5 and Sonnet 5.5 reject forced tool choice. JSON mode prefills `{` only on models that accept it |
| **Cerebras** | GPT-OSS 120B, ZAI-GLM 4.7, LLaMA 3.1 8B *(deprecated 2026-05-27)*, Qwen 3 235B *(deprecated 2026-05-27)* | Yes | GLM, Qwen, GPT-OSS | ~2,200 tok/s |
| **Groq** | LLaMA 3.3 70B Versatile, LLaMA 3.1 8B Instant, GPT-OSS 120B, Compound, Compound Mini | Yes | LLaMA 3.3 70B, GPT-OSS 120B | Ultra-fast inference; Compound systems run built-in tools |
| **NVIDIA NIM** | Llama 3.3/3.1 70B, Llama 4 Maverick, Nemotron 70B/49B/253B, Mistral Large 2, DeepSeek V4 Flash/Pro | Yes | Llama, Nemotron, Mistral Large 2 | Costs $0 placeholder — dev-tier credits; set real rates in `CreditLedger` |
Expand Down Expand Up @@ -551,11 +551,15 @@ try {
import { MODELS, getRecommendedModel } from '@stackbilt/llm-providers';

// Current-gen models
MODELS.CLAUDE_OPUS_4_6; // 'claude-opus-4-6'
MODELS.CF_GLM_5_3_FLASH; // '@cf/zai-org/glm-5.3-flash'
MODELS.CF_KIMI_K2_6; // '@cf/moonshotai/kimi-k2.6'
MODELS.CF_GPT_OSS_120B; // '@cf/openai/gpt-oss-120b'
MODELS.CF_GEMMA_4_26B; // '@cf/google/gemma-4-26b-a4b-it'
MODELS.CLAUDE_SONNET_4_6; // 'claude-sonnet-4-6'
MODELS.CLAUDE_HAIKU_4_5; // 'claude-haiku-4-5-20251001'
MODELS.GPT_4O; // 'gpt-4o' (not routed by this package)
MODELS.GPT_4O_MINI; // 'gpt-4o-mini'
MODELS.GPT_4O_MINI; // 'gpt-4o-mini' (shutdown 2027-01-14)
MODELS.CLAUDE_OPUS_5_5; // 'claude-opus-5-5' (explicit requests only)
MODELS.GPT_6_ASTRA; // 'gpt-6-astra' (explicit requests only)
MODELS.CEREBRAS_ZAI_GLM_4_7; // 'zai-glm-4.7'
MODELS.GROQ_COMPOUND; // 'groq/compound' (RESEARCH; built-in tools)
MODELS.GROQ_COMPOUND_MINI; // 'groq/compound-mini'
Expand Down
4 changes: 2 additions & 2 deletions docs/maintenance/issue-sweep.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Checkpoint: 2026-10-15. Repository: `Stackbilt-dev/llm-providers`.
The sweep below is **merged to `main`** and is versioned as 1.22.0 by release PR [#121](https://github.com/Stackbilt-dev/llm-providers/pull/121) (npm publish is a separate operator step): [#119](https://github.com/Stackbilt-dev/llm-providers/pull/119) (sweep plus review fixes) and [#120](https://github.com/Stackbilt-dev/llm-providers/pull/120) (#116 hook isolation). Each went through adversarial review rounds; review-driven compatibility fixes are recorded in the 1.22.0 CHANGELOG entry. The issues stay open for the remaining scope in the table. No live or billable vendor requests were made.

1. Inspect `git status --short`. Preserve the pre-existing `src/__tests__/factory.test.ts` modification; its diff is line-ending-only when checked with `--ignore-space-at-eol`.
2. Next implementation targets: #112 vendor IDs/pricing, then #109 atomic spend reservations (needs a design pass first).
2. #112 phase 1 shipped in 1.22.1; phase 2 (current models, Workers AI deprecations, reasoning-model request parameters, `explicitOnly`) shipped in 1.23.0 via [#123](https://github.com/Stackbilt-dev/llm-providers/pull/123). Next: #124 (Anthropic `tool_use_id`, tool error text and Claude 5.x thinking blocks in tool loops; prerequisite for routing the 5.x models), then #109 atomic spend reservations (needs a design pass first).
3. Run the validation commands below after substantive code changes, then open reviewable PRs.

`issue-corpus/Stackbilt-dev__llm-providers/` is a June 2026 historical export. `.agent-memory/status.json` belongs to the archive/upload machinery. Neither is the current task checkpoint; preserve their historical/managed contents.
Expand All @@ -28,7 +28,7 @@ The sweep below is **merged to `main`** and is versioned as 1.22.0 by release PR
| [#116](https://github.com/Stackbilt-dev/llm-providers/issues/116) | Quota observers and streaming terminal/schema observers are guarded; stream body deadlines, cancellation, fault/race tests and awaited stream settlement were added. | Hook replay fixed in #120: every factory/adapter hook is guarded. Remaining: non-streaming body deadlines, retry sleep aborts, Retry-After/vendor error fixtures, unproduced hook events, floating non-streaming cache/quota writes, request/tool-loop signals, workerd and coverage baselines |
| [#118](https://github.com/Stackbilt-dev/llm-providers/issues/118) | Coordinating roadmap receives this checkpoint and priorities. | Track reviewed/merged implementation phases separately from local progress. |

Other open items are unchanged: #112 (vendor audit, next), #114 (failure demo/README restructuring/repo cleanup), #117 (optional AI SDK adapter), #77 (supply-chain workflow), #78/#79/#80 (new provider proposals). #90/#95 have existing code surfaces but were not re-audited for closure during this sweep.
Other open items are unchanged: #112 (phase 2 shipped in 1.23.0; remaining: Claude 5.x thinking-block round trip and `tool_use_id` in tool loops, tracked in #124 (then lift `explicitOnly` on the 5.x and GPT-5.6 models), Cerebras/Groq/NVIDIA prices and IDs, GPT-6 Luna / 6.1 Sol tool-calling restrictions, OpenAI cached-input pricing, custom-model escape hatch, unknown-cost semantics, provenance canary), #114 (failure demo/README restructuring/repo cleanup), #117 (optional AI SDK adapter), #77 (supply-chain workflow), #78/#79/#80 (new provider proposals). #90/#95 have existing code surfaces but were not re-audited for closure during this sweep.

## Public behavior to retain

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stackbilt/llm-providers",
"version": "1.22.1",
"version": "1.23.0",
"description": "Multi-LLM failover with circuit breakers, cost tracking, and intelligent retry. Cloudflare Workers native.",
"author": "Stackbilt <admin@stackbilt.dev>",
"license": "Apache-2.0",
Expand Down
12 changes: 7 additions & 5 deletions src/__tests__/model-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ describe('getRoutingInfo', () => {

it('returns deprecation warning for a compatibility-lifecycle model', () => {
const info = getRoutingInfo(
{ messages: [{ role: 'user', content: 'hi' }], model: 'gpt-4' },
['openai']
{ messages: [{ role: 'user', content: 'hi' }], model: 'qwen-3-235b-a22b-instruct-2507' },
['cerebras']
);
expect(info.modelLifecycle).toBe('compatibility');
expect(info.deprecationWarning).toBeTruthy();
Expand Down Expand Up @@ -444,9 +444,11 @@ describe('new CF Workers AI models (v1.16.0)', () => {
}
});

it('prefers the current DeepSeek V4 Flash lane for Cloudflare long-context routing', () => {
it('routes Cloudflare long-context requests to an active 1M-context model', () => {
const ranked = rankModels('LONG_CONTEXT', ['cloudflare']);
expect(ranked[0]?.model).toBe('@cf/deepseek-ai/deepseek-v4-flash-0731');
expect(ranked[0]?.lifecycle).toBe('active');
expect(ranked[0]?.capabilities.maxContextLength).toBeGreaterThanOrEqual(1_048_576);
expect(ranked.slice(0, 3).map(entry => entry.model)).toContain('@cf/deepseek-ai/deepseek-v4-flash-0731');
});
});

Expand All @@ -472,7 +474,7 @@ describe('current CF Workers AI models (August 2026)', () => {
});

it('records the documented context windows and vision capabilities', () => {
expect(getCatalogEntry('@cf/deepseek-ai/deepseek-v4-flash-0731')?.capabilities.maxContextLength).toBe(1_310_720);
expect(getCatalogEntry('@cf/deepseek-ai/deepseek-v4-flash-0731')?.capabilities.maxContextLength).toBe(1_048_576);
expect(getCatalogEntry('@cf/deepseek-ai/deepseek-v4-pro-0813')?.capabilities.maxContextLength).toBe(1_048_576);
expect(getCatalogEntry('@cf/zai-org/glm-5.3')?.capabilities.maxContextLength).toBe(1_048_576);
expect(getCatalogEntry('@cf/qwen/qwen3.8-27b')?.capabilities.supportsVision).toBe(true);
Expand Down
Loading
Loading