Skip to content

feat(nearai): add catalog sync module - #6776

Open
neo-sky wants to merge 16 commits into
anomalyco:devfrom
nearai:feat/nearai-sync
Open

neo-sky wants to merge 16 commits into
anomalyco:devfrom
nearai:feat/nearai-sync

Conversation

@neo-sky

@neo-sky neo-sky commented Sep 10, 2026

Copy link
Copy Markdown

Summary

Adds a nearai sync provider that reads the public /v1/models catalog on
cloud-api.near.ai. The endpoint needs no credential, so this needs no repository
secret and no change to sync-models.yml: the sync matrix is built from
bun models:sync --list-providers, so registering the provider is the wiring.

This PR is the sync mechanism only. It does not refresh the providers/nearai
catalog, and it never creates or deletes model files.

What the sync takes, and what it does not

The endpoint is authoritative for price and for the context window of models NEAR
AI serves directly. Its other fields are not, and each of these was checked
against live requests rather than read off the response:

  • max_output_length is advisory and not enforced. On zai-org/GLM-5.1-FP8 it
    reports 16384, while max_tokens of 16384, 40000 and 131072 were all accepted
    and only 202752 and above were rejected, with "Requested token count exceeds the
    model's maximum context". The binding limit is the context window, so
    limit.output is never synced.
  • context_length is the serving max_model_len only where owned_by is
    nearai. On relayed routes it is rounded: openai/gpt-4.1 reports 1000000
    against the lab entry's 1047576. So context is synced for hosted models only,
    and taken as the lower of the two values.
  • supported_features is wrong in both directions. It lists reasoning for the
    Claude relay routes, where thinking.type and reasoning_effort are rejected
    and the accepted reasoning object returns no reasoning_content; it omits
    reasoning for others that plainly reason. No capability is taken from it.
  • input_modalities advertises image input for the Moonshot routes, which reject
    it. It also reports an embedding modality the schema has no value for.

Capabilities, modalities, attachment, interleaved and reasoning controls
therefore stay hand-authored, and a follow-up PR carries the catalog data.

Safety

  • skipCreates: new models are not created, because the endpoint exposes no
    release date or knowledge cutoff and most NEAR AI models reason, so they need
    hand-authored controls.
  • deleteMissing: false: absence never removes a model. A truncated response
    would be indistinguishable from a genuine withdrawal.
  • trackMissingModels: false: remote-only models are listed in the sync notice
    rather than filed as one issue each.
  • An entry whose local cost does not resolve is skipped into the notice instead of
    aborting the run for every other model.

Checks

Re-run against dev at 385d8f5f5, which this branch now merges cleanly with.

  • bun validate - exit 0
  • bun test packages/core/test/nearai.test.ts - 18 passed
  • bun models:sync nearai --dry-run - 0 created, 1 updated, 0 removed,
    31 unchanged, and one retained (zai-org/GLM-5.1-FP8, absent from the live
    catalog and kept by deleteMissing: false)
  • full bun test - the same 4 unrelated failures reproduced on dev at
    385d8f5f5

neo-sky and others added 8 commits September 10, 2026 19:28
Refresh providers/nearai against the live gateway model list
(https://cloud-api.near.ai/v1/models, checked 2026-09-08).

- Add 19 models now served by the gateway: GLM 5.2, GLM 5.3 Flash,
  DeepSeek V4 Flash and Qwen 3.8 27B on NEAR TEE hosts, plus the
  pass-through routes for Claude Fable 5/5.1, Opus 4.8, Opus 5,
  Sonnet 5, GPT-5.6 Luna/Sol, GPT-6 Astra, Gemini 3.8 Flash,
  Kimi K2.6/K3, DeepSeek V3.2, Qwen3 32B, Qwen3.5 397B and Qwen3.7 Max.
- Remove 5 models the gateway no longer lists: gemini-3-pro,
  gemma-4-31B-it, gpt-oss-120b, Qwen3-30B-A3B-Instruct-2507,
  Qwen3.5-122B-A10B.
- Fix prices for GLM-5.1-FP8, gpt-5.2 and claude-sonnet-4-5.
- Convert GLM-5.1-FP8 to base_model = "zhipuai/glm-5.1".
- Fix Qwen3-VL-30B limits to the served max_model_len (16 384).
- NEAR-hosted TEE entries carry a " TEE" name suffix and a
  release_date/last_updated of the TEE catalog refresh, following the
  Chutes TEE convention, so they sort first in date-ordered pickers.

Reasoning controls were verified live against the gateway:
GLM 5.2 / 5.3 Flash / Qwen 3.8 toggle with
chat_template_kwargs.enable_thinking; DeepSeek V4 Flash (off by
default) and Kimi K3 toggle with chat_template_kwargs.thinking.
…obes

Addresses the reviewer findings on anomalyco#6584. Every value below was measured on
POST https://cloud-api.near.ai/v1/chat/completions on 2026-09-08.

- qwen3.5-397b-a17b: reasoning is on by default and toggles with
  chat_template_kwargs.enable_thinking. The route also accepts image input,
  so the incorrect text-only modality override and attachment = false are
  dropped in favour of the lab metadata.
- deepseek-v3.2: reasoning is off by default and toggles with
  chat_template_kwargs.thinking.
- qwen3.7-max: reasoning_options stays empty, now with the evidence in the
  header. No reasoning_content is returned under enable_thinking, thinking,
  reasoning_effort, reasoning.enabled or reasoning.effort.
- qwen3-32b: removed. The gateway advertises the route but every request
  returns "The model is currently unavailable".
- Claude Fable 5, Fable 5.1, Opus 4.8, Opus 5 and Sonnet 5: reasoning_options
  is empty. These routes reject thinking.type = "enabled" and reject
  reasoning_effort as an extra input, and the OpenRouter-style reasoning
  object is accepted but returns no reasoning_content. Declaring an effort
  scale would make clients send a parameter the gateway rejects outright.
- Modality overrides now remove only pdf, which the gateway cannot accept in
  any form, and inherit every other input type from the lab entry. Gemini 3.8
  Flash keeps video and audio, the Moonshot entries inherit unchanged.
- Every toggle in the changed set carries a leading wire-path comment.

OpenAI routes are unchanged: reasoning_effort is accepted there.
Addresses review round 2 on anomalyco#6584. The gateway's own /v1/models
input_modalities field proved unreliable in both directions, so each route
was probed with a two-pixel test image (left green, right orange) alongside
a control request with the same prompt and no image. A route is credited
with image input only when the image answer is correct and the control
answer differs and is wrong.

Routes that silently drop images despite advertising them:
- moonshotai/kimi-k2.6 and kimi-k3 both mis-describe the image, and both
  say they cannot see images when none is attached. Now text-only.

Routes that accept images despite advertising text only:
- qwen3.5-397b-a17b, Qwen3.6-35B-A3B-FP8 and Qwen3.8-27B each named both
  colours exactly while their controls guessed wrong. Now text and image.

Also narrowed gemini-3.8-flash and glm-5.3-flash to text and image. Video
and audio were never verified on any route, so they are excluded
everywhere; with audio gone from gemini-3.8-flash there is no audio input
to price, so cost.input_audio is intentionally absent.

deepseek-ai/DeepSeek-V4-Flash and z-ai/glm-5.2 are confirmed text-only and
already match their lab bases, so they carry no override.
… output limit

Addresses review round 3 on anomalyco#6584.

- kimi-k2.6 and kimi-k3 set attachment = false. Both routes are text-only
  here, but the lab entries set attachment = true, so the resolved models
  were advertising file attachments on routes that silently discard images.
  glm-5.2 and DeepSeek-V4-Flash already inherit attachment = false and are
  left untouched.

- GLM-5.1-FP8 keeps the inherited limit.output = 131_072 and now carries the
  evidence in its header instead of only in the PR thread. On this gateway
  max_tokens of 16384, 40000 and 131072 are all accepted, while 202752 and
  above are rejected with "Requested token count exceeds the model's maximum
  context". Validation is bounded by the 202_752 context window, which the
  direct endpoint reports as max_model_len, so context is overridden here and
  output is not. No value changed, comment only.
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/nearai/models/anthropic/claude-haiku-4-5.toml:2 - Check: Relay reasoning_options must match this host’s real controls (and stay consistent with sibling NEAR Claude routes). Why: These files still declare toggle + budget_tokens (opus-4-7: toggle only), while the PR’s own live probes set Fable/Opus 4.8/Opus 5/Sonnet 5 to [] because the gateway rejects or ignores reasoning params and returns no reasoning_content. The PR body also states Claude relay routes accept reasoning params but return no reasoning content. Publishing budget/toggle here misleads clients into sending Anthropic-style controls this OpenAI-compatible surface does not honor. Same issue on claude-opus-4-6.toml, claude-opus-4-7.toml, claude-sonnet-4-5.toml, claude-sonnet-4-6.toml. Action: Re-probe these five routes the same way as the new Claude entries; set reasoning_options = [] with a leading evidence comment if controls are inert, or author only the wire controls that actually change reasoning output—and drop unsupported budget_tokens if that field is not enforced.
  • [high] [violation] providers/nearai/models/google/gemini-3.8-flash.toml:2 - Check: On relays, [] means affirmative no caller control, not uncertainty; baseline is lab/same-surface peers. Why: New entry sets reasoning_options = [] with no probe comment, while first-party providers/google/models/gemini-3.8-flash.toml and OpenRouter peers expose effort low/medium/high. Empty options on a controlled reasoner without host-specific evidence is a policy violation. Action: Verify whether NEAR accepts Gemini reasoning/effort (or equivalent) on this route; copy the working control set, or keep [] only with a leading comment documenting the failed control probes.
  • [medium] [violation] providers/nearai/models/anthropic/claude-haiku-4-5.toml:2 - Check: Every toggle needs a leading top-of-file wire-path comment. Why: These Claude 4.x files were reformatted in this PR and still ship { type = "toggle" } with no leading # Toggle: … comment (required because sync strips mid-file comments). Applies to the same five Claude 4.x files while they retain a toggle. Action: If any toggle remains after the control audit above, add a leading comment with the exact request field/path; if options become [], the comment requirement no longer applies.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/nearai/models/anthropic/claude-haiku-4-5.toml:1 - Check: Provider modality overrides must match this host’s real input surface. Why: The PR states the gateway cannot accept PDF in any form (and that video/audio were never verified), and the new Claude / Gemini / Qwen entries correctly override [modalities].input. Existing base_model files with no modality override still inherit lab pdf (and Gemini still inherits video/audio/pdf), so resolved nearai models keep advertising unsupported inputs. Action: Add host-true [modalities].input (and attachment when that becomes text-only) on every nearai base_model entry that would otherwise inherit PDF/video/audio—at least the Claude 4.x, GPT, and Gemini files left without overrides.
  • [high] [possible mistake] providers/nearai/models/anthropic/claude-sonnet-4-5.toml:2 - Check: reasoning_options must describe effective caller controls on this host. Why: The PR body says Claude relay routes accept documented reasoning parameters but return no reasoning_content, and the new Claude 5.x/Fable/Opus 4.8 entries correctly use reasoning_options = [] after live probes. Claude 4.x still publish toggle + budget_tokens (and Opus 4.7 toggle only) with no wire-path comment, which conflicts with that same-host evidence and will steer clients toward ineffective or invalid controls. Action: Live-probe the Claude 4.x routes the same way as Claude 5.x; set reasoning_options = [] with a leading no-control comment if they match, or keep real controls only with a leading wire-path comment and host-specific evidence that they differ from the new Claude routes.
  • [medium] [violation] providers/nearai/models/Qwen/Qwen3-VL-30B-A3B-Instruct.toml:1 - Check: Non-lab hosts must use base_model for nameable lab models. Why: This PR converts peers such as GLM-5.1-FP8 to override-only base_model files and claims base_model-only authoring, but the refreshed Qwen3-VL TEE entry remains a full third-party inline definition for a nameable Alibaba model with no models/alibaba/… target. Action: Add a complete models/alibaba/… lab entry for Qwen3-VL 30B-A3B Instruct (or the correct lab id), then rewrite the nearai file as base_model + host deltas only (cost, TEE name/dates, served limit, modalities).

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/nearai/models/google/gemini-2.5-flash-lite.toml:1 - Check: Relay reasoning_options must be the intersection this host actually exposes; every toggle needs a leading wire-path comment; budget_tokens only when this host has a real reasoning-budget field. Why: Patch 11 copies first-party Google toggle + budget_tokens (and Pro’s budget bounds) onto the NEAR AI Gemini 2.5 routes while the headers say the wire path was not probed. That invents lab budget controls on an unverified openai-compatible relay (and leaves toggles without a wire comment). Same-surface Claude probes on this gateway already showed native thinking/effort parameters are rejected. Action: For gemini-2.5-flash-lite, gemini-2.5-flash, and gemini-2.5-pro, either live-verify the exact request fields and keep only supported controls (with a leading # Toggle: … / # Budget: … wire comment), or set reasoning_options = [] with affirmative no-control evidence—do not paste lab budget/toggle shapes untested.
  • [medium] [violation] providers/nearai/models/google/gemini-2.5-flash-lite.toml:12 - Check: Provider cost keys must match served modalities (no priced audio when audio input is not offered). Why: These routes now override modalities to text-only or text+image (no audio), but still author input_audio. The PR already dropped input_audio on gemini-3.8-flash for that reason; leaving it on the 2.5 / 3.1 / 3.5 entries publishes a non-usable audio price. Action: Remove input_audio from gemini-2.5-flash-lite, gemini-2.5-flash, gemini-3.1-flash-lite, and gemini-3.5-flash unless audio input is restored and verified on this host.
  • [medium] [possible mistake] providers/nearai/models/openai/gpt-5.toml:1 - Check: Host-true modality / attachment overrides should be applied consistently across the same gateway surface. Why: Patch 11 marks several OpenAI routes text-only (attachment = false, input = ["text"]) while siblings that still inherit lab image/pdf stay unchanged (gpt-5, gpt-5.2, gpt-4.1-nano, o4-mini) and newer GPT-5.6/GPT-6 entries keep explicit text+image. If the text-only findings are host-wide for that generation, unresolved files will keep advertising image input incorrectly. Action: State which OpenAI routes were image-probed and align the remaining entries (including gpt-5, gpt-5.2, gpt-4.1-nano, o4-mini, and the GPT-5.6/GPT-6 files) to the same verified modality set, or restore image where the probe showed it works.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/nearai/models/google/gemini-2.5-flash.toml:1 - Check: Reasoning options must match this host’s OpenAI-compatible surface (lab + same-surface peers), not another API’s wire path. Why: NEAR AI is @ai-sdk/openai-compatible (cloud-api.near.ai/v1). The PR authors Gemini 2.5 Flash / Flash-Lite / Pro with Google-native generationConfig.thinkingConfig.thinkingBudget comments and first-party budget_tokens (plus toggle). Same-surface OpenAI-compat peers such as OpenRouter expose toggle-only for Flash/Flash-Lite (no budget). Documenting a Google AI Studio/Vertex path clients cannot send on this gateway, and inventing budget controls that peers on the same kind of surface do not publish, misleads callers and breaks the host-role rule in AGENTS.md / the audit skill. The PR itself states these Google paths were not probed. Action: Drop Google-native generationConfig… wire comments. Re-author reasoning_options from a live probe of POST /v1/chat/completions on this host, or from verified openai-compat peers of the same models (e.g. OpenRouter toggle-only for 2.5 Flash/Lite). Only keep budget_tokens if this gateway actually accepts a reasoning-budget field and document that wire path in a leading comment.
  • [high] [violation] providers/nearai/models/google/gemini-2.5-flash-lite.toml:1 - Check: Same host-surface / peer baseline rule for Gemini 2.5 Flash-Lite. Why: Same incorrect generationConfig.thinkingConfig.thinkingBudget toggle+budget packaging as Flash, with no host probe. Action: Align with the corrected Flash treatment (probe or openai-compat peers; no Google Messages/generationConfig path).
  • [high] [violation] providers/nearai/models/google/gemini-2.5-pro.toml:1 - Check: Same rule for Gemini 2.5 Pro. Why: Authors budget_tokens with a Google-native wire comment and no probe on this host. Even if some relays expose a budget for Pro, the comment must name NEAR’s request field, not generationConfig.thinkingConfig.thinkingBudget. Action: Probe or cite the actual NEAR request syntax; keep budget only if it works here; fix the leading wire comment accordingly.
  • [medium] [possible mistake] providers/nearai/provider.toml:6 - Check: Provider docs must not contradict the catalog’s host-true reasoning behavior. Why: The header still says third-party routes “pass through their provider-native reasoning controls,” but this PR sets every Anthropic route to reasoning_options = [] (no caller control) and documents that Claude relays reject native thinking/reasoning_effort. That stale claim will send integrators down the wrong path. Action: Rewrite the provider.toml reasoning notes so they match the final catalog (hosted TEE toggles vs OpenAI effort vs Anthropic no-control vs Google only where verified).
  • [low] [possible mistake] providers/nearai/models/deepseek-ai/DeepSeek-V4-Flash.toml - Check: Relay effort set should be the intersection of lab/peers and what this host exposes. Why: First-party DeepSeek and OpenRouter peers for V4 Flash publish toggle + graded effort (high/max or low/high/max). This entry is toggle-only after verifying chat_template_kwargs.thinking. That is valid if effort is truly ignored, but the PR does not record an effort probe the way it does for Anthropic rejections. Action: Confirm whether reasoning_effort (or equivalent) has effect on this route; if yes, add the real effort values and a leading effort wire comment; if no, add a short header note that effort was tested and ignored so the narrower set is intentional.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [medium] [possible mistake] providers/nearai/models/Qwen/Qwen3.6-35B-A3B-FP8.toml:20 - Check: Host limit.output must be a real serving delta, not the catalog’s advisory max_output_length. Why: This entry still forces output = 32_768 while the lab base is 65_536, and the PR/sync policy states max_output_length is not enforced (only context binds). That understates the host’s usable output unless separately verified. Action: Drop the output override to inherit the lab limit, or keep it only with a leading comment citing a live max-token acceptance/rejection result on this route.
  • [medium] [possible mistake] providers/nearai/models/Qwen/Qwen3-VL-30B-A3B-Instruct.toml:16 - Check: Same output-limit evidence standard as above. Why: Context 16_384 is documented from the TEE max_model_len, but output = 8_192 remains while the new lab entry is 32_768, with no probe showing 8192 is binding on this host. Action: Remove the unproven output cap (inherit 32_768) or document a verified host output ceiling.
  • [medium] [possible mistake] providers/nearai/models/google/gemini-3.1-flash-lite.toml:3 - Check: Relay reasoning controls should match this host’s openai-compatible surface and same-surface peers. Why: Final options are effort-only minimal|low|medium|high. OpenRouter’s peer for the same model exposes toggle + that effort set, and this PR already established that NEAR accepts the openai-compatible reasoning object (used as toggle on Gemini 2.5). Omitting toggle may under-report a working off control. Action: Probe reasoning.enabled on this route; add { type = "toggle" } plus a leading wire comment if it works, or document why 3.1-flash-lite cannot be toggled here while 2.5 can.
  • [low] [possible mistake] providers/nearai/models/anthropic/claude-fable-5.toml:8 - Check: Provider cost completeness vs sibling NEAR AI Anthropic routes. Why: New Anthropic relays (claude-fable-5, claude-fable-5-1, claude-opus-4-8, claude-opus-5, claude-sonnet-5) publish cache_read only. Existing NEAR AI Claude 4.x entries and first-party/OpenRouter peers also publish cache_write. If this gateway bills cache writes, these prices are incomplete. Action: Confirm against the NEAR catalog/docs whether cache write is charged on these IDs; add cache_write where it applies (or note in a leading comment if the host truly has no write price).

@neo-sky neo-sky changed the title feat(nearai): add catalog sync and refresh model entries feat(nearai): add catalog sync module Sep 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] .pr-review/diff.patch:3915 - Check: PR delivers the catalog refresh it claims (AGENTS.md contribution completeness; title/body vs final tree). Why: Title and body say the PR refreshes NEAR AI model entries, adds models/alibaba/qwen3-vl-30b-a3b-instruct.toml, converts GLM-5.1 to base_model, and applies live-probed pricing/limits/modalities/reasoning. Patch 14/14 deletes those new models and lab metadata and restores the prior provider TOMLs, so the final tree is sync infrastructure only and contradicts the PR’s own probe notes. Action: Restore the catalog refresh (new routes, lab base_model targets, pricing/limit/modality/reasoning fixes) consistent with the PR evidence, or drop the refresh claims and retitle/redescribe this as sync-only.
  • [medium] [possible mistake] packages/core/src/sync/providers/nearai.ts (hosted owned_by === "nearai" context gate) - Check: Hosted-model context sync only when the gateway actually marks NEAR-hosted routes that way. Why: Context is updated only for owned_by = "nearai", but the unit fixture for the TEE id zai-org/GLM-5.1-FP8 uses owned_by: "zai-org". If live catalog rows for NEAR-hosted models use org owners rather than "nearai", hosted context_length never syncs and stays stale. Action: Confirm live owned_by for NEAR-hosted/TEE models; broaden the hosted predicate (or map known hosted ids) so context sync matches real catalog ownership.

@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 11, 2026
# Conflicts:
#	packages/core/src/sync/index.ts
@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

No actionable findings.

@github-actions github-actions Bot added the reviewer: ready Automated review found no actionable items label Sep 14, 2026
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