Skip to content

Add sference provider with public /v1/models sync#3332

Open
jernejstrasner wants to merge 3 commits into
anomalyco:devfrom
s-ference:add-sference-provider
Open

Add sference provider with public /v1/models sync#3332
jernejstrasner wants to merge 3 commits into
anomalyco:devfrom
s-ference:add-sference-provider

Conversation

@jernejstrasner

@jernejstrasner jernejstrasner commented Jul 18, 2026

Copy link
Copy Markdown

What

Adds sference — a managed inference platform for open-weight models, run in Europe behind an OpenAI-compatible API — as a provider.

Why

sference serves open-weight checkpoints (GLM, Qwen, DeepSeek, ThinkingCap) with per-token pricing and a public model catalog. There was no entry for it in models.dev.

Changes

Provider (providers/sference/):

  • provider.toml@ai-sdk/openai-compatible, base URL https://api.sference.com/v1. Reasoning control (enable_thinking = true|false toggle) documented in the header comment.
  • logo.svg — the sference mark, currentColor, square 0 0 32 32 viewBox.

Models (sync-generated, factored onto base_model metadata — no duplicated provider-agnostic facts):

model base_model input output cache_read
zai-org/GLM-5.2 zhipuai/glm-5.2 $1.20 $4.20 $0.26
Qwen/Qwen3.6-35B-A3B alibaba/qwen3.6-35b-a3b $0 $0
deepseek-ai/DeepSeek-V4-Flash deepseek/deepseek-v4-flash $0.14 $0.28 $0.03
bottlecapai/ThinkingCap-Qwen3.6-27B bottlecapai/thinkingcap-qwen3.6-27b $0.40 $2.60

All four reason via sference's enable_thinking = true|false toggle, so each declares [[reasoning_options]] type = "toggle" and an interleaved reasoning_content block.

New model metadata (models/bottlecapai/thinkingcap-qwen3.6-27b.toml) — ThinkingCap had no existing provider-agnostic models/ entry, so one was added (open-weight Qwen3.6-27B fine-tune, cited to HuggingFace + bottlecapai.com).

Sync module (packages/core/src/sync/providers/sference.ts):

  • Reads the public GET /v1/models endpoint (auth-optional, no SFERENCE_API_KEY secret required) for pricing, context limits, and capabilities.
  • Follows the chutes/venice factoring pattern: resolves base_model from the model ID, writes only API-authoritative overrides, and leaves fields the API omits (input limit, full modality arrays, knowledge) to inherit from base metadata.
  • Pricing is already per-1M-token USD in the response (nested pricing object), so no token→1M conversion is needed.
  • Registered in the direct sync group; the hourly CI job needs no secret since the catalog is public.
  • Also reads max_output_tokens and released when present (see below).

Tests (packages/core/test/sference-sync*.test.ts): 9 passing — unit tests for the translate/factoring logic plus an end-to-end test that runs the full sync runner against a mocked public endpoint and verifies idempotency.

How it stays updated

The hourly sync-models.yml workflow auto-discovers providers registered in packages/core/src/sync/index.ts, so registering sference there schedules a job that syncs the public catalog into an automation/sync-models-sference branch and opens/updates a PR whenever pricing, models, or limits change. No workflow edits were needed (no new secrets).

Note on max_output_tokens / released

The sync module already reads max_output_tokens (→ limit.output) and released (→ release_date) from the API. Those fields are implemented on the sference platform side (commits d886540 and 232541a) but not yet deployed to api.sference.com. Until they ship, limit.output and release_date inherit from base metadata, and the sync is idempotent today (verified against the live endpoint). Once deployed, the next hourly sync will write authoritative output limits (e.g. 81_920 for the Qwen3.6 family, which differs from the base's 65_536) and real release dates — no further models.dev changes needed.

Sources

Verification

  • bun validate — sference validates with 4 models
  • bun test — 9/9 sference tests pass
  • tsc --noEmit — clean
  • bun models:sync sference --dry-run — idempotent (0 changes) against the live public endpoint

sference is a managed inference platform for open-weight models, run in
Europe behind an OpenAI-compatible API. This adds it as a provider with a
sync module that reads the public GET /v1/models endpoint (auth-optional,
no secret required) for pricing, context limits, and capabilities.

Provider:
- providers/sference/provider.toml — @ai-sdk/openai-compatible, base URL
  https://api.sference.com/v1; reasoning control (enable_thinking toggle)
  documented in the header comment.
- providers/sference/logo.svg — the sference mark, currentColor, square
  viewBox.

Models (sync-generated, factored onto base_model metadata):
- zai-org/GLM-5.2          -> base_model zhipuai/glm-5.2
- Qwen/Qwen3.6-35B-A3B     -> base_model alibaba/qwen3.6-35b-a3b
- deepseek-ai/DeepSeek-V4-Flash -> base_model deepseek/deepseek-v4-flash
- bottlecapai/ThinkingCap-Qwen3.6-27B -> base_model bottlecapai/...
  (new models/bottlecapai/thinkingcap-qwen3.6-27b.toml metadata entry,
  since ThinkingCap had no existing provider-agnostic metadata)

All four reason via sference's enable_thinking = true|false toggle, so each
declares [[reasoning_options]] type = "toggle" and an interleaved
reasoning_content block.

Sync module (packages/core/src/sync/providers/sference.ts) follows the
chutes/venice factoring pattern: resolves base_model from the model ID,
writes only API-authoritative overrides, and leaves fields the API omits
(input limit, full modality arrays, knowledge) to inherit from base
metadata. Reads the nested pricing object (already per-1M-token USD, no
conversion) and capabilities. Registered in the direct sync group; the
hourly CI job needs no SFERENCE_API_KEY since the catalog is public.

The module also reads max_output_tokens and released when present. Those
fields are not deployed on /v1/models yet (sference-platform commits
d886540/232541a); until they ship, limit.output and release_date inherit
from base metadata, and the sync is idempotent today. Once deployed, the
sync will write authoritative output limits (e.g. 81_920 for the Qwen3.6
family, which differs from the base's 65_536) and real release dates.

Sources:
- https://sference.com/ (serverless pricing table)
- https://sference.com/docs/models
- https://sference.com/docs/quickstart
- sference-platform commit e140c07 (public auth-optional /v1/models)

Tests: packages/core/test/sference-sync*.test.ts (9 passing).
@github-actions

Copy link
Copy Markdown
Contributor

After reading the pull request metadata, diff, AGENTS.md, README.md, sync.md, the reasoning-options audit guide, schema code, and nearby base-revision files, I have completed my review.

No actionable findings.

Comment on lines +19 to +31
const ORG_TO_MODEL_PROVIDER: Record<string, string | undefined> = {
Qwen: "alibaba",
"zai-org": "zhipuai",
thinkingmachines: "thinkingmachines",
bottlecapai: "bottlecapai",
moonshotai: "moonshotai",
MiniMaxAI: "minimax",
"deepseek-ai": "deepseek",
google: "google",
"meta-llama": "meta",
nvidia: "nvidia",
openai: "openai",
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats the point of having mappings if they are openai -> openai? Any mapping thatt is already an exact match should be removed from this, the assumption should be that if there isnt a custom mapper then the provider name is the org name

Comment on lines +7 to +8
[[reasoning_options]]
type = "toggle"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do I toggle it?

Comment on lines +7 to +8
[[reasoning_options]]
type = "toggle"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how?

Comment on lines +6 to +7
[[reasoning_options]]
type = "toggle"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r u sure?

No reasoning effort?

Comment on lines +6 to +7
[[reasoning_options]]
type = "toggle"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r u sure?

jernejstrasner and others added 2 commits July 20, 2026 09:02
- Remove identity org mappings (openai->openai etc.) from
  ORG_TO_MODEL_PROVIDER; fall back to the org name itself so unmapped
  orgs still resolve to base_model metadata.
- DeepSeek V4 Flash's worker accepts reasoning_effort = high|max
  (xhigh->max) in addition to enable_thinking, but the public /v1/models
  catalog only exposes the toggle. Since the API is not authoritative for
  the reasoning control surface, the sync now preserves hand-authored
  reasoning_options instead of overwriting them, and DeepSeek V4 Flash
  declares both a toggle and an effort option (matching ambient).
- Add a test for reasoning_options preservation.
- Pick up updated DeepSeek V4 Flash pricing from the live endpoint
  ($0.08/$0.20 -> $0.14/$0.28, cache $0.02 -> $0.03).
…king

The worker's reasoning_effort handling is unreachable from the public API:
chat ingress validates with extra="ignore" and builds the worker body from
an allowlist, and /v1/responses only forwards enable_thinking. All sference
reasoning models are toggle-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jernejstrasner

Copy link
Copy Markdown
Author

Hey @rekram1-node, thanks for the review.
I addressed your comments about the map.
As for the thinking:
We only support true/false on sference right now, hence the toggle. Passing enable_thinking: true/false in the request is what does it.

@github-actions

Copy link
Copy Markdown
Contributor

Based on my thorough review of the diff, base-revision files, schema, sync infrastructure, and documentation, I've identified the following:

Action items

  • [low] [possible mistake] providers/sference/models/deepseek-ai/DeepSeek-V4-Flash.toml:10-12 - Check: PR body pricing table consistency with committed files. Why: The PR body table lists DeepSeek V4 Flash as input $0.08 / output $0.20 / cache_read $0.02, but the committed file (updated in patch 2 from the live endpoint) has input = 0.14, output = 0.28, cache_read = 0.03. The patch 2 commit message documents the pricing update, but the PR body table was not reconciled with the final files, making it hard for a reviewer to verify the pricing against the cited source. Action: Update the PR body pricing table to reflect the final committed values ($0.14 / $0.28 / $0.03) and confirm the live /v1/models endpoint or pricing page supports them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants