Skip to content

feat(tzafon): add Tzafon provider - #3039

Closed
eddieogola wants to merge 10 commits into
anomalyco:devfrom
eddieogola:add-tzafon-provider
Closed

feat(tzafon): add Tzafon provider#3039
eddieogola wants to merge 10 commits into
anomalyco:devfrom
eddieogola:add-tzafon-provider

Conversation

@eddieogola

Copy link
Copy Markdown

Summary

Adds Tzafon as an OpenAI-compatible provider (@ai-sdk/openai-compatible, api = "https://api.tzafon.ai/v1"), an official submission from the Tzafon team with a commitment to keep these entries current.

  • providers/tzafon/provider.toml — provider metadata, doc points at the live pricing page (https://docs.lightcone.ai/guides/pricing/)
  • providers/tzafon/logo.svg — square viewBox, currentColor fill (adapted from Tzafon's icon mark)
  • providers/tzafon/models/tzafon.northstar-cua-fast.toml — CUA model, image input, tool calling
  • providers/tzafon/models/tzafon.northstar-cua-fast-1.6.toml — same shape, newer/smaller-context variant; priced the same as northstar-cua-fast since it isn't broken out separately on the pricing page yet
  • packages/core/src/sync/providers/tzafon.ts — sync module registered under the direct group. It only reconciles release_date from the live /v1/models listing and never auto-creates or auto-deletes models, since that endpoint doesn't expose authoritative pricing/limits/modalities. New/unmatched remote IDs are reported via skippedNotice, not silently created or dropped.

Scoped out for now: tzafon.sm-1 and tzafon.northstar-cua-faster/-faster-1.6 are intentionally not included in this PR — see Verification notes below.

Verification

  • Data verified live against api.tzafon.ai (2026-07-02) with a regular-user API key — context limits probed via oversized max_completion_tokens, and the /v1/models listing is key-scoped to public tzafon.* models only (never internal checkpoints, regardless of key).
  • bun validate passes clean.
  • bun models:sync tzafon --dry-run is clean (0 created, 0 updated, 0 removed).
  • opencode end-to-end: built packages/web, ran opencode against both models with a regular-user key — a real chat completion and a real tool call (bash tool invocation) both succeeded for tzafon.northstar-cua-fast; a real chat completion succeeded for tzafon.northstar-cua-fast-1.6.
  • tzafon.sm-1 is excluded from this PR: it responds to plain completions, but its backend rejects any request with tool_choice: "auto" ("auto" tool choice requires --enable-auto-tool-choice and --tool-call-parser to be set) — confirmed via direct API calls, not an opencode quirk. Since opencode's default agent always sends tools, sm-1 cannot be used from opencode until Tzafon relaunches that model's server with the right vLLM flags. Will follow up with a separate PR once that's fixed.
  • tzafon.northstar-cua-faster is documented on the pricing page but returns model not found on the live API — excluded per the "don't list models regular users can't reach" guidance. This is a Tzafon-side docs/API mismatch being tracked separately, not a models.dev catalog decision.

Test plan

  • bun validate
  • bun models:sync tzafon --dry-run
  • opencode: real completion + tool call against tzafon.northstar-cua-fast
  • opencode: real completion against tzafon.northstar-cua-fast-1.6

@eddieogola
eddieogola marked this pull request as ready for review July 5, 2026 09:33
@eddieogola
eddieogola marked this pull request as draft July 5, 2026 09:34
@eddieogola
eddieogola force-pushed the add-tzafon-provider branch from a0a379d to 42e820d Compare July 5, 2026 09:36
@eddieogola
eddieogola marked this pull request as ready for review July 5, 2026 09:36
@eddieogola
eddieogola marked this pull request as draft July 6, 2026 01:54
@eddieogola
eddieogola force-pushed the add-tzafon-provider branch from 42e820d to 1830930 Compare July 6, 2026 01:55
@eddieogola
eddieogola marked this pull request as ready for review July 6, 2026 01:56
@eddieogola
eddieogola marked this pull request as draft July 7, 2026 07:19
@eddieogola
eddieogola force-pushed the add-tzafon-provider branch from 1830930 to 1e253b7 Compare July 7, 2026 07:23
@eddieogola
eddieogola marked this pull request as ready for review July 7, 2026 07:24
@eddieogola
eddieogola marked this pull request as draft July 9, 2026 06:12
@eddieogola
eddieogola force-pushed the add-tzafon-provider branch from 1e253b7 to d6f3e85 Compare July 9, 2026 06:16
@eddieogola
eddieogola marked this pull request as ready for review July 9, 2026 06:16
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Based on my review of the PR metadata, diff, AGENTS.md, README.md, sync.md, schema code, existing sync providers, and the convention in synced provider TOMLs, here are my findings:

  • [medium] providers/tzafon/models/tzafon.northstar-cua-fast.toml and providers/tzafon/models/tzafon.northstar-cua-fast-1.6.toml — Source citations and rationale (the https://docs.lightcone.ai/guides/pricing/ pricing note, the "probed 2026-07-02" limit comments, and the # /v1/models created timestamp inline notes) are placed inside the [cost]/[limit] sections and as inline field comments rather than in a leading comment block above the first key. AGENTS.md requires citations and rationale to live at the top of the file because sync serialization strips comments elsewhere. Tzafon is registered in the direct sync group (so CI will run bun models:sync tzafon hourly); any future sync that rewrites these files would silently delete the pricing provenance and limit-derivation notes. The synced ovhcloud TOMLs demonstrate the correct pattern — a leading # comment block before name =.

  • [low] packages/core/src/sync/providers/tzafon.ts:61translateModel returns { ...existing, release_date: … } by spreading existing, which is typed as ExistingModel (all top-level fields optional via AuthoredModelShape.partial()). The spread result has optional name/description/attachment/reasoning/tool_call/limit/modalities/etc., which does not structurally satisfy SyncedModel (SyncedFullModel requires those fields as non-optional), so the satisfies SyncProvider<TzafonModel> annotation provides no real type guarantee and would fail under tsc. The google.ts and xai.ts sync providers avoid this by explicitly constructing a SyncedFullModel and throwing when required local fields are missing. Runtime behavior is correct because the hand-authored TOMLs are complete, but the type annotation is not enforced.

@eddieogola
eddieogola marked this pull request as draft July 9, 2026 06:31
@eddieogola
eddieogola marked this pull request as ready for review July 9, 2026 06:34
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

I've reviewed the PR metadata, diff, AGENTS.md, README, sync.md, the reasoning-options audit skill, the schema, the sync runner, and comparable provider modules (xai, ovhcloud, openai). Here's my analysis.

Checklist verification:

  • Logo (blocker): providers/tzafon/logo.svg is present, uses currentColor, has no fixed width/height, and viewBox="0 -1 14 14" is square (14×14). Compliant.
  • base_model (blocker): No models/tzafon/ metadata exists, so the inline definitions for the proprietary Northstar CUA models are correct (no provider-agnostic facts to inherit).
  • reasoning_options (blocker): Both models set reasoning = false; the schema forbids reasoning_options when reasoning is false, and neither file sets it. The sync's preserveReasoningOptions also strips it. Correct.
  • Required schema fields: name, description, attachment, reasoning, tool_call, release_date, last_updated, open_weights, modalities, limit (with context+output), and cost (with input+output) are all present and well-formed. Date strings match the required regex.
  • Citation placement: Both TOMLs place sources/rationale in a leading comment block above name =, which the sync's leadingComments() preserves. Matches AGENTS.md.
  • Sync module: Registered correctly (import, type entry, object entry, direct group, alphabetized). skipCreates: true + deleteMissing: false + skippedNotice mirrors the OpenAI monitoring-only precedent. isPublic() defensively filters to tzafon.* regardless of key scope. buildTzafonModel validates required local fields before returning (xai/google pattern). TZAFON_API_KEY is optional and not added to the workflow env, which is consistent with the PR's "public-only listing" claim. No third-party actions introduced.
  • Provider TOML: @ai-sdk/openai-compatible with api satisfies the Provider refine.

The one material factual claim that cannot be verified from the cited source is the 1.6 pricing.

  • [low] providers/tzafon/models/tzafon.northstar-cua-fast-1.6.toml - [cost] input = 0.50 / output = 1.50 are mirrored from tzafon.northstar-cua-fast as an assumption. The cited pricing page (https://docs.lightcone.ai/guides/pricing/) does not list northstar-cua-fast-1.6 separately, so these values cannot be confirmed against the provided source. The assumption is documented in the file, but a direct price for this model should be confirmed with Tzafon (and updated) once it is broken out on the pricing page.

@eddieogola
eddieogola marked this pull request as draft July 9, 2026 06:44
@eddieogola
eddieogola marked this pull request as ready for review July 9, 2026 06:45
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

I've now thoroughly reviewed the PR. Let me summarize my analysis:

PR overview: Adds a new "Tzafon" provider (OpenAI-compatible) with two CUA models, a compliant logo, and a sync module registered in the direct group.

Key checks performed:

  1. Logo compliance — The final SVG (after patch 4) uses viewBox="0 -1 14 14" (14×14, square), fill="currentColor", no width/height attributes, no hardcoded colors. Compliant with logo guidelines.

  2. base_model requirement — No models/tzafon/ directory exists (confirmed via glob). These are Tzafon-proprietary models (Northstar CUA Fast / 1.6) with no provider-agnostic metadata entry to inherit from. Full inline definitions are correct.

  3. reasoning_options requirement — Both models declare reasoning = false. The schema's refineModel only requires reasoning_options when reasoning = true and forbids it when reasoning = false. No options needed.

  4. Citations — PR body cites https://docs.lightcone.ai/guides/pricing/. In-file citations are in leading comment blocks above name = in both TOMLs (matching the ovhcloud pattern). The runner's leadingComments() function preserves these across sync rewrites. Comments between sections (which sync would delete) were moved to the header in patch 5.

  5. Schema compliance — All required fields present: name, description, attachment, reasoning, tool_call, release_date, last_updated, open_weights, limit (context/input/output), modalities (input/output), cost (input/output). No id field authored (correctly auto-injected from filename). No extra/strict-violating fields.

  6. Sync module — Follows the google/xai thin-endpoint pattern: skipCreates: true, deleteMissing: false, skippedNotice for new remote IDs, translateModel returns undefined for non-existing models. buildTzafonModel validates required local fields and only updates release_date from the API created timestamp (preserving hand-authored values). The isPublic() filter prevents internal tzafon.internal.* checkpoints from entering the catalog regardless of key scope. TZAFON_API_KEY is optional — no workflow secret additions needed. Registered correctly in providers and direct group with proper alphabetical ordering.

  7. Provider TOMLnpm = "@ai-sdk/openai-compatible" with api = "https://api.tzafon.ai/v1" (required pairing per schema). env and doc present.

  8. Workflow — No new third-party actions introduced. No new secrets required (optional API key).

No actionable findings.

@eddieogola
eddieogola marked this pull request as draft July 12, 2026 01:37
eddieogola and others added 5 commits July 12, 2026 04:40
Adds Tzafon (Northstar CUA Fast, Northstar CUA Fast 1.6, SM-1) as an
OpenAI-compatible provider, plus a sync module that reconciles
release_date from the live /v1/models listing without auto-creating
or auto-deleting entries (pricing/limits/modalities aren't
authoritative from that endpoint yet).

Data verified live against api.tzafon.ai on 2026-07-02 with a
regular-user key (context limits probed via oversized
max_completion_tokens; the /v1/models listing is key-scoped to
public tzafon.* models only).

Official submission from Tzafon, maintained by the team going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sm-1's backend currently rejects any request with tool_choice=auto
(missing --enable-auto-tool-choice / --tool-call-parser server flags),
which breaks it for opencode's default agent path. Excluding until
that's fixed server-side; the sync module already reports it via
skippedNotice rather than silently dropping it.

northstar-cua-fast-1.6 isn't broken out separately on the pricing page
yet, so it's priced the same as northstar-cua-fast per Tzafon's call.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swaps in the current icon mark from lightcone.ai/assets/logos, padded
to a square viewBox (source is 14x12) and using currentColor per
models.dev's logo convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Move source citations and rationale (pricing evidence, limit-probe
  notes, capability-flag reasoning) into a single leading comment
  block above `name =` in both model TOMLs, matching the ovhcloud
  pattern. Comments placed between sections or above individual keys
  are silently dropped by the daily sync rewrite, since tzafon is
  registered in the `direct` sync group.
- translateModel now builds the synced model through an explicit
  buildTzafonModel() that validates required fields are present on
  the existing local TOML and throws otherwise, instead of spreading
  a deepPartial ExistingModel into a return typed as SyncedFullModel.
  Mirrors the pattern in xai.ts/google.ts. Confirmed with
  `bunx tsc --noEmit` that this resolves the type mismatch the
  automated review flagged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@eddieogola
eddieogola force-pushed the add-tzafon-provider branch from 15ca719 to d85755b Compare July 12, 2026 01:42
@eddieogola
eddieogola marked this pull request as ready for review July 12, 2026 01:43
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [low] [possible mistake] providers/tzafon/models/tzafon.northstar-cua-fast-1.6.toml:19 - Check: Material pricing values must be supported by a direct first-party citation that actually lists the model. Why: The leading comment states this model is "not yet broken out separately on https://docs.lightcone.ai/guides/pricing/ as of 2026-07-02," so the cited URL does not cover input = 0.50 / output = 1.50 — those values are assumed to match tzafon.northstar-cua-fast. A URL that does not list the model, plus a PR assertion, does not prove the price; an incorrect per-million-token cost would mislead catalog consumers. Action: Provide a direct first-party source (API pricing response, Tzafon documentation/confirmation, or the pricing page once the model is listed) that supports the fast-1.6 cost, or hold the entry until Tzafon publishes a citable number for it.

docs.lightcone.ai/guides/pricing/ now lists tzafon.northstar-cua-fast-1.6
directly, at $0.50/M input — cite that instead of the prior "not yet
published" note. The page's pricing table only carries one price per
model (its Input/Output columns collapse into a single value), so
output still isn't broken out for fast-1.6 there; cost.output remains
an assumption equal to northstar-cua-fast's $1.50/M, now stated
precisely as such per the automated review's request for a direct
citation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
eddieogola and others added 2 commits July 12, 2026 04:51
The pricing page's table has mislabeled headers: description text sits
under "Input" and the sole price value sits under "Output" for every
row, including northstar-cua-fast itself. Cross-referencing the page's
own callout box (northstar-cua-fast: input $0.50/M, output $1.50/M)
confirms the table's $0.50/M values are actually input prices despite
the header. Spell that out in the comment instead of citing the
literal (wrong) column label.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Use the canonical documentation URL (https://docs.lightcone.ai/)
instead of the pricing subpage, matching the README's convention of
linking the provider's documentation, not a specific guide page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [low] [possible mistake] providers/tzafon/models/tzafon.northstar-cua-fast-1.6.toml ([cost] output = 1.50) - Check: Material cost data should be backed by a direct provider citation or verified evidence. Why: The leading comment states the pricing page publishes only fast-1.6's input price ($0.50/M) and that cost.output = 1.50 is "assumed equal to northstar-cua-fast's $1.50/M pending Tzafon publishing it explicitly." The cited source does not confirm the output price for this model, so a user-facing cost field rests on an unverified assumption. Action: Confirm fast-1.6's output price directly with Tzafon (pricing page, API response, or provider statement), update the value and citation, or document why the assumption is acceptable until published.
  • [low] [possible mistake] packages/core/src/sync/providers/tzafon.ts:12 (isPublic) - Check: The isPublic() filter must exclude tzafon.internal.* checkpoint IDs as its own comments claim. Why: id.startsWith("tzafon.") also matches tzafon.internal.* IDs, so internal checkpoints pass the filter. The comment in fetchModels asserts "an admin key must never widen the synced set, which isPublic() enforces regardless," but isPublic() does not enforce this — the real guard is translateModel returning undefined for IDs lacking a local TOML. If an admin key is ever used, internal checkpoint names would pass isPublic() and surface in the skippedNotice sync report; and if skipCreates/translateModel are later refactored relying on isPublic() as the documented gate, internal IDs could leak further. Action: Either make isPublic() actually exclude internal IDs (e.g. id.startsWith("tzafon.") && !id.startsWith("tzafon.internal.")) or correct the comments to attribute the exclusion to translateModel rather than isPublic().

Tzafon fixed the pricing table's column headers. It now directly
states tzafon.northstar-cua-fast-1.6 at $0.50/M input, $1.50/M
output — no more inference from northstar-cua-fast's callout text
needed. cost values are unchanged; only the citation is updated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [low] [possible mistake] packages/core/src/sync/providers/tzafon.ts:101-103 - Check: isPublic() filter matches its documented security intent. Why: The comments above isPublic() and inside fetchModels() state that "Only tzafon.* public IDs may enter the catalog, regardless of which key ran the sync" and that "an admin key must never widen the synced set, which isPublic() enforces regardless." But id.startsWith("tzafon.") also matches tzafon.internal.* IDs, which the same comments explicitly identify as internal checkpoints that should be excluded. If sync is ever run with an admin key, internal IDs pass the filter and surface in skippedNotice; if a local TOML is later hand-authored for an internal ID, translateModel would find it and the sync would update it — the exact scenario isPublic() claims to prevent. Action: Exclude tzafon.internal.* from isPublic() (e.g., id.startsWith("tzafon.") && !id.startsWith("tzafon.internal.")), or correct the comments to attribute the actual enforcement to translateModel returning undefined plus skipCreates: true rather than to isPublic().

State the current pricing and limit facts plainly instead of noting
probe dates, "was $X" price-drop history, or the pricing table's now-
fixed column bug. A reader encountering these files fresh only needs
the current numbers and their source, not the editing history behind
them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@eddieogola eddieogola closed this by deleting the head repository Jul 27, 2026
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.

1 participant