Skip to content

feat(sync): replace Friendli generator with SyncProvider - #7006

Merged
rekram1-node merged 6 commits into
anomalyco:devfrom
Lee-Si-Yoon:friendli-sync-v3
Sep 14, 2026
Merged

rekram1-node merged 6 commits into
anomalyco:devfrom
Lee-Si-Yoon:friendli-sync-v3

Conversation

@Lee-Si-Yoon

@Lee-Si-Yoon Lee-Si-Yoon commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the standalone packages/core/script/generate-friendli.ts generator with a SyncProvider at packages/core/src/sync/providers/friendli.ts, wired into bun models:sync friendli (registered in providers and groups.direct in packages/core/src/sync/index.ts).

Source: https://api.friendli.ai/serverless/v1/models (no auth required).

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/src/sync/providers/friendli.ts:471 - Check: Provider sync must not invent false non-reasoning overrides for lab reasoners. Why: const reasoning = model.reasoning === true treats a missing API reasoning field as false. That value is passed into factorBaseModel, so an omitted flag becomes an explicit reasoning = false override, and preserveReasoningOptions then strips reasoning_options. Hourly sync can mark real reasoners as non-reasoning whenever Friendli omits the field. Action: Treat API reasoning as tri-state: true/false only when present; when absent, leave reasoning unset on factored entries so lab metadata wins (and keep existing authored reasoning for full-inline updates).
  • [medium] [violation] packages/core/src/sync/providers/friendli.ts:480 - Check: Factored Friendli models must surface host-authoritative capability deltas, including tool_call. Why: The full-inline path sets tool_call from model.functionality.tool_call, but the factorBaseModel override object omits it entirely. If Friendli disables tools for a lab model that has tool_call = true (or the reverse), the catalog keeps the lab value and misreports the Friendli surface. Action: Pass tool_call: model.functionality.tool_call into the factored overrides (same as structured_output), so only real deltas are written.
  • [medium] [possible mistake] providers/friendli/models/MiniMaxAI/MiniMax-M2.5.toml:9 - Check: budget_tokens only when this host exposes a real reasoning-budget control for that model. Why: This PR replaces lab/peer reasoning_options = [] (MiniMax first-party and other hosts) with unbounded budget_tokens. The PR body live-verifies reasoning_budget on GLM-5.3, gemma-4-31B-it, and DeepSeek-V3.2, not MiniMax-M2.5. If the catalog advertises budget incorrectly for MiniMax, clients get a fake control. Action: Confirm with a Friendli request on MiniMaxAI/MiniMax-M2.5 that reasoning_budget actually caps reasoning_content; if not, keep [] (or the real control set) instead of authoring budget_tokens.

@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@github-actions github-actions Bot added the reviewer: ready Automated review found no actionable items label Sep 13, 2026
@github-actions github-actions Bot removed the reviewer: ready Automated review found no actionable items label Sep 13, 2026
@Lee-Si-Yoon

Copy link
Copy Markdown
Contributor Author

Follow-up in 1fca2b7, rebalancing toward the repo's conventions per maintainer direction:

  1. budget_tokens dropped everywhere. translateReasoningOptions now filters budget_tokens out (the zod schema still validates the raw shape). MiniMax-M2.5, whose only catalog control was budget, publishes reasoning_options = [] per the established always-on convention (Venice precedent). All 7 TOMLs hand-adjusted to match; bun models:sync friendli --dry-run now reports 0 created / 0 updated / 0 removed / 7 unchanged against the committed files, so the module and the authored files agree byte-for-byte.

  2. Catalog removals are now authoritative. deleteMissing: true: a model absent from GET /serverless/v1/models — or past its deprecation_date — is deleted from this catalog on the next sync (translateModel skips it, the runner removes the file). A deprecation_date in the API is treated as equivalent to the model disappearing from the catalog. skippedNotice/missingNotice updated accordingly.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/src/sync/providers/friendli.ts (translateReasoningOptions) - Check: reasoning_options must reflect this host’s real caller controls; [] means no control, and budget_tokens is allowed when the host exposes a real reasoning-token budget (AGENTS.md → Reasoning options; audit skill budget rules). Why: Patch 3 drops every budget_tokens entry even though the same PR documents a live-verified Friendli reasoning_budget field (GLM-5.3, gemma-4-31B-it, DeepSeek-V3.2, MiniMax-M2.5) and providers/friendli/provider.toml still lists it. That is not “always-on / no control.” For MiniMax-M2.5 the only remaining control becomes reasoning_options = [], which falsely claims no caller control. Other peers (OpenRouter, Requesty, Merge Gateway, etc.) do publish budget_tokens when the host supports it; there is no repo rule that openai-compatible relays may only emit toggle/effort. Action: Keep budget_tokens whenever the Friendli catalog reports it (bounds optional/omitted is fine if min/max are unsafe). Restore budget_tokens on models that expose it, restore the Budget wire-path header for those files, and do not author [] for MiniMax while reasoning_budget is a real control.
  • [low] [possible mistake] providers/friendli/models/zai-org/GLM-5.3.toml - Check: Material pricing changes should be backed by a mapped first-party citation in the PR body. Why: Input/output/cache_read move from 1.4 / 4.4 / 0.26 to 1.26 / 3.96 / 0.234 with no PR-body note of what source supports the new rates. Action: Cite the Friendli pricing/docs/API field that yields these USD/MTok values (and the per-token→per-million conversion if that is how they are derived).

@Lee-Si-Yoon

Copy link
Copy Markdown
Contributor Author

Both findings addressed in 367a40e:

  1. [high] budget_tokens restored, unbounded. You are right — dropping a live-verified control while provider.toml documents it was a false narrowing, and MiniMax-M2.5's [] would claim no caller control on a host that does expose reasoning_budget. translateReasoningOptions again emits { type = budget_tokens } (never min/max — GLM-5.3 accepted reasoning_budget=1_048_577 above its reported max), the Budget wire-path header is restored, and the module comment records the live verification (budget=10 truncated MiniMax reasoning at ~46 chars mid-sentence while completion_tokens continued to a full 2051-token answer; budget=2000 produced 1011 chars of reasoning under the identical prompt). bun models:sync friendli regenerated all 7 files; second dry-run is clean (0/0/0, 7 unchanged).

  2. [low] GLM-5.3 pricing citation. The 1.26/3.96/0.234 USD/MTok rates are Friendli's live catalog: GET /serverless/v1/models → pricing per-token USD strings 0.00000126/0.00000396/0.000000234 × 1e6 (accessed 2026-09-13). The old 1.4/4.4/0.26 were stale hand-authored values from feat(friendli): add GLM-5.3 provider model #5776; the sync now prices every model from the live catalog. Added a 'Pricing source' section to the PR body.

@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@github-actions github-actions Bot added the reviewer: ready Automated review found no actionable items label Sep 13, 2026
@github-actions github-actions Bot removed the reviewer: ready Automated review found no actionable items label Sep 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/src/sync/providers/friendli.ts:796 - Check: Authoritative deleteMissing syncs must not wipe the catalog on an empty/faulty upstream response. Why: Final deleteMissing: true (default-on) plus parseModels returning FriendliResponse.parse(raw).data with no non-empty guard means a transient empty/partial GET /serverless/v1/models body produces zero desired models and deletes every local Friendli TOML. Peers that delete (e.g. LLM Gateway, Cloudflare AI Gateway) fail closed on empty catalogs for this reason. Action: Reject empty (and, if appropriate, suspiciously shrunken) parsed catalogs before translate/delete, or keep deleteMissing: false until that guard exists.
  • [medium] [violation] packages/core/src/sync/providers/friendli.ts:1055 - Check: Sync must preserve base_model on updates when the lab target is temporarily unresolvable (sync.md / deepinfra-style factoring). Why: Creates skip only when existing === undefined && factorBase === undefined. For an already-tracked factored file, if resolveLabModelSync returns undefined (lab file missing, case/map miss, models/ read failure), buildFriendliModel takes the full-inline path and preserveBaseModels: false does not restore the on-disk base_model, so the next sync can expand override-only files into full copies and drop inheritance. Action: On updates, prefer existing.base_model when lab resolution fails (deepinfra pattern), or only full-inline when there was never a base; do not unfactor stable base_model entries.
  • [medium] [violation] packages/core/src/sync/providers/friendli.ts:962 - Check: Authored reasoning_options effort values must be schema-valid (none|minimal|low|medium|high|xhigh|max|default). Why: translateReasoningOptions pushes API effort objects via as with values: z.array(z.string()). Friendli’s own docs list values outside the catalog enum (e.g. ultracode). One invalid value fails SyncedAuthoredModel parse and aborts the whole Friendli sync job. Action: Filter effort values to the schema set (drop/skip unknown); if nothing remains after filter, handle explicitly rather than casting through.
  • [low] [possible mistake] providers/friendli/models/zai-org/GLM-5.3.toml:1367 - Check: Material cost changes should be supported by a direct, claim-mapped source in the PR body. Why: Input/output/cache_read move from 1.4 / 4.4 / 0.26 to 1.26 / 3.96 / 0.234 while the PR body only names the models endpoint generally, so the delta cannot be reviewed against a stated price field or doc section. Action: In the PR body, cite the exact pricing source (API field or docs) and map it to these USD/MTok figures (including the ×1e6 conversion if prices are per-token).

@github-actions

Copy link
Copy Markdown
Contributor

No actionable findings.

@github-actions github-actions Bot added the reviewer: ready Automated review found no actionable items label Sep 14, 2026
@rekram1-node
rekram1-node merged commit 7486711 into anomalyco:dev Sep 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

reviewer: ready Automated review found no actionable items

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants