Skip to content

feat(hyper): add Charm Hyper provider and sync module - #3352

Merged
rekram1-node merged 13 commits into
anomalyco:devfrom
oskarkocol:feat/charm-hyper-v2
Jul 28, 2026
Merged

feat(hyper): add Charm Hyper provider and sync module#3352
rekram1-node merged 13 commits into
anomalyco:devfrom
oskarkocol:feat/charm-hyper-v2

Conversation

@oskarkocol

@oskarkocol oskarkocol commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

supersedes #2983

Context

Our friends at charm land shipped a gateway.

I'm adding them as a provider.
And also closing: #2747
Their prices are accessible via API therefore adding automation:

curl -X GET https://hyper.charm.land/v1/models \
     -H "Content-Type: application/json"

Tests

happy tests:

bun test packages/core/test/sync.test.ts --filter "Hyper"

dry run also happy

bun models:sync hyper --dry-run

sync in sync and happy

bun models:sync hyper
image

Comment thread packages/core/src/schema.ts Outdated
@oskarkocol
oskarkocol marked this pull request as ready for review July 21, 2026 14:56
@github-actions

Copy link
Copy Markdown
Contributor

Based on my analysis of the PR, the diff, the schema, sync code, base model files, and existing provider pricing patterns, here are my findings:

Action items

  • [medium] [possible mistake] providers/hyper/models/qwen3.6-flash.toml:11-12, providers/hyper/models/qwen3.6-max.toml:11-12, providers/hyper/models/qwen3.6-plus.toml:12-13, packages/core/src/sync/providers/hyper.ts:354-355 - Check: Verify Hyper API cache_hit/cache_create field semantics match the standard OpenAI convention used in the sync mapping. Why: The sync maps pricing.cache_hit → cost.cache_read and pricing.cache_create → cost.cache_write (standard convention), but the resulting values are inverted from every other provider in the catalog. For all three Qwen3.6 models, cache_read (1.25, 2.5, 2.5) exceeds input (1, 2, 2) while cache_write (0.1, 0.2, 0.2) is far below input — the exact inverse of the 10%/125% ratio documented in AGENTS.md and used by alibaba for the same underlying models (e.g., alibaba's qwen3.6-plus >256K tier: cache_read=0.20, cache_write=2.50, versus Hyper's cache_read=2.5, cache_write=0.2 with identical input=2/output=6). This strongly suggests Hyper's API returns these values under swapped field names, or the values are genuinely inverted. Action: Confirm against Hyper's API documentation whether cache_hit is the read cost (standard) or write cost (non-standard). If the API uses non-standard naming, swap the mapping in buildCost; otherwise confirm the unusual pricing is intentional and cite the source.
  • [low] [violation] .pr-review/pull-request.json:4 - Check: PR body must cite direct provider sources for material data changes. Why: AGENTS.md (Citations, recommended) asks data-changing PRs to link to the provider's pricing page, model docs, or API reference in the PR body, with each citation stating what it supports. The PR body only references a superseded PR and test/sync command output; it does not link to Hyper's pricing page, API docs, or model documentation. This matters because the cache pricing values above cannot be verified without a source, and the schema relaxation (removing Provider.env .min(1)) also lacks documented justification. Action: Add first-party citations to the PR body (e.g., Hyper API reference, pricing page) and state which fields each URL supports.

@oskarkocol
oskarkocol marked this pull request as draft July 21, 2026 15:12
@oskarkocol
oskarkocol marked this pull request as ready for review July 22, 2026 10:50
@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] providers/hyper/provider.toml:2 - Check: Provider env must list auth environment variables; schema requires a non-empty array. Why: This PR sets env = [] and removes Provider.env’s .min(1) in packages/core/src/schema.ts, weakening a global invariant for every provider. No other provider ships an empty env, and README treats env as the auth-key surface for clients. An OpenAI-compatible gateway almost certainly needs a documented key name; empty env leaves consumers unable to configure credentials. Action: Revert the schema change, set the real Hyper API key env var(s) (e.g. whatever Charm documents), or provide first-party evidence that Hyper accepts unauthenticated inference and justify empty env without relaxing validation repo-wide.
  • [medium] [violation] providers/hyper/logo.svg:1 - Check: New-provider logo must be compliant SVG (currentColor, no fixed size, preferably square viewBox). Why: The asset is a wide wordmark (viewBox="68 50 1800 526" plus fixed width/height), not a square icon mark. That breaks the contribution logo checklist and will render poorly wherever provider logos are shown as square badges. Action: Replace with a square icon-only SVG using currentColor, no fixed dimensions, and a square viewBox (e.g. 0 0 24 24).
  • [medium] [possible mistake] providers/hyper/models/deepseek-v4-flash.toml:10 - Check: Synced costs should be clean per-1M USD values. Why: Several models store float noise (0.20000010875000002, 4.790500000000001, 0.9499997000000001, etc.). Final buildCost in packages/core/src/sync/providers/hyper.ts passes API numbers through without rounding, unlike other sync modules, so bad floats will keep being rewritten on every sync. Action: Round catalog prices in the Hyper sync (same style as other providers) and re-sync so TOML costs are stable decimals.
  • [low] [possible mistake] providers/hyper/models/deepseek-v4-flash.toml:5 - Check: Niche-provider reasoning_options should document the exact request syntax and only claim verified controls. Why: Effort options are asserted from /v1/models reasoning.effort_levels, but there is no adjacent API comment (or PR evidence) for the request field/values Hyper accepts (e.g. reasoning_effort vs another path). AGENTS asks niche providers to record that syntax next to options. Action: Add the verified Hyper request syntax next to each [[reasoning_options]] entry (or as a leading provider comment), and drop any effort/toggle claim not backed by Hyper’s API surface.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/src/schema.ts:350 - Check: Provider env must list auth environment variable names (README Contributing; schema previously required .min(1)). Why: The PR sets env = [] on Charm Hyper and drops the non-empty env constraint for every provider. Clients lose a documented API-key hook, and empty env becomes valid catalog-wide. Action: Restore env: z.array(z.string()).min(1, ...), and set Hyper’s env to the real auth var(s) (e.g. HYPER_API_KEY or whatever Charm documents)—do not relax the global schema for one provider.
  • [high] [possible mistake] packages/core/src/sync/providers/hyper.ts:121 - Check: reasoning / reasoning_options must reflect Hyper’s inference surface; absence of effort metadata is not proof the model does not reason (AGENTS.md; chutes/crossmodel patterns). Why: reasoning: model.reasoning !== undefined forces reasoning = false whenever /v1/models omits the reasoning object. After resync this overrides base metadata for known reasoning models (minimax-m2.7, gemma-4-26b-a4b-it, glm-5, kimi-k2.5, kimi-k2.7-code, qwen3.6-*, qwen3.7-*), which is likely wrong if Hyper still serves thinking behavior without advertising effort levels. Action: Only set reasoning = true (and options) when the API positively advertises reasoning; when the field is absent, leave reasoning unset so base_model is inherited, or map always-on reasoning to reasoning = true + reasoning_options = []. Re-sync and fix the affected TOMLs; cite Hyper evidence for any intentional reasoning = false overrides.
  • [medium] [possible mistake] packages/core/src/sync/providers/hyper.ts:67 - Check: Sync should add models the provider serves when a matching models/ entry can be resolved (sync.md; venice/chutes/openrouter). Why: translateModel returns undefined unless a local Hyper TOML already has base_model, so new Hyper catalog IDs are never created and are treated as absent (deleted if present without base_model). Aliases/resolve*BaseModel were removed in the simplify commit. Action: Resolve base_model for unknown IDs (aliases + metadata lookup) and only skip when no canonical metadata exists; keep requiring hand-authored files only when no models/ match is possible.
  • [low] [possible mistake] providers/hyper/models/deepseek-v4-flash.toml:10 - Check: Synced costs should be stable per-1M USD values (other sync modules round). Why: Several models store float noise (0.20000010875000002, 1.52425/4.790500000000001, 0.9499997000000001, etc.), which indicates missing rounding in buildCost and hurts diffs/reviews. Action: Round API prices (e.g. to 6 decimal places like other providers) and re-sync so TOMLs get clean numbers.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [violation] packages/core/src/sync/providers/hyper.ts:136 - Check: Provider attachment and modalities must stay consistent when overriding vision support. Why: buildHyperModel sets attachment from capabilities.vision but never writes modalities. That leaves multimodal bases with attachment = false while still inheriting image/video inputs—already visible on gemma-4-26b-a4b-it and llama-4-maverick-17b-128e-instruct-fp8 (and the reverse risk when vision is true but only a vision boolean is known). Consumers will disagree on whether files/images are accepted. Action: Derive both fields together (e.g. vision → attachment = true and modalities.input including image; no vision → attachment = false and text-only input unless another modality is verified). Update affected Hyper TOMLs and cover this in the Hyper sync tests.
  • [medium] [possible mistake] packages/core/src/sync/providers/hyper.ts:137 - Check: reasoning / reasoning_options must reflect Hyper’s inference surface, not only upstream models/ metadata. Why: When the API omits reasoning, the sync still emits reasoning_options = [] if the base model reasons, so the catalog claims Hyper reasoning with no control. Hyper’s own /v1/models schema treats reasoning as optional metadata, so omission is a real signal; earlier revisions of this PR set reasoning = false for those rows. Action: Confirm against Hyper whether models without a reasoning object still reason on this provider. If not, set reasoning = false and drop reasoning_options; if they do reason with no control, keep reasoning_options = [] and cite that evidence in the PR body.
  • [low] [possible mistake] providers/hyper/models/deepseek-v4-flash.toml:6 - Check: Niche-provider effort options should document the exact request syntax callers must send. Why: Several models advertise [[reasoning_options]] type = "effort" from catalog effort_levels, but neither the TOMLs nor the PR body state the Hyper request field/path (e.g. OpenAI-style reasoning_effort vs another payload). Without that, clients cannot use the declared controls reliably. Action: Add a short adjacent # API: ... comment on the effort options (or PR citation mapped to the claim) with the verified request shape and accepted values.

@github-actions

Copy link
Copy Markdown
Contributor

Action items

  • [high] [possible mistake] packages/core/src/sync/providers/hyper.ts:146 - Check: Provider reasoning must reflect whether the model reasons on this inference provider; absence of controls is reasoning_options = [], not reasoning = false. Why: buildHyperModel sets reasoning: model.reasoning != null, treating a missing Hyper reasoning object (effort metadata) as non-reasoning. That forces reasoning = false on base models that are reasoning = true (minimax/MiniMax-M2.7, alibaba/qwen3.6-*, alibaba/qwen3.7-*, moonshotai/kimi-k2.5, moonshotai/kimi-k2.7-code, zhipuai/glm-5, google/gemma-4-26b-a4b-it), while peers keep those models as reasoning with empty options. Hyper already advertises effort only for some IDs (e.g. kimi-k2.6 vs kimi-k2.5), so omission looks like “no control,” not “does not reason.” Action: Only set reasoning = true when the API confirms reasoning; when the object is absent, leave reasoning unset so base_model can inherit, and emit reasoning_options = [] for inherited reasoning models (restore the TOMLs accordingly). Do not keep reasoning = false unless Hyper evidence shows thinking is disabled for that ID.
  • [medium] [possible mistake] packages/core/src/sync/providers/hyper.ts:127 - Check: Provider modality overrides should not drop capabilities the catalog already attributes to the model unless the provider API is authoritative for those modalities. Why: hyperModalities always rewrites input to either ["text"] or ["text","image"] from capabilities.vision. For vision-capable IDs that still have richer base modalities (e.g. kimi-k2.6, kimi-k2.7-code, qwen3.6-flash, qwen3.6-plus with video), sync permanently strips video (and any non-image attachment types). Action: When vision is true, preserve non-image base input modalities (or only add image instead of replacing the whole array); only force text-only when Hyper explicitly reports no vision.
  • [medium] [possible mistake] packages/core/test/sync.test.ts:734 - Check: Tests should encode the intended reasoning merge behavior, not the incorrect false override. Why: The Hyper tests expect reasoning: false / missing reasoning_options when API reasoning metadata is omitted for minimax/MiniMax-M2.7, locking in the bad inference above. Action: Update tests so omitted API reasoning inherits base reasoning = true and yields reasoning_options = [] (or equivalent), and only assert reasoning = false when the API affirmatively marks a non-reasoning model.

@oskarkocol

Copy link
Copy Markdown
Contributor Author

@rekram1-node the review bot is in a loop 😓 Should a missing reasoning object from Hyper strictly mean "inherits base reasoning" (with empty options)?

All the models in Hyper have reasoning enabled, but they don't expose it as a flag.

Also, for modalities: if a model supports vision, I'm merging "image" into the base modalities rather than overwriting the array so we don't accidentally drop "video". Sound good?

@lgh06

lgh06 commented Jul 23, 2026

Copy link
Copy Markdown

Thanks for your efforts! can't wait for this PR to be merged.

@rekram1-node
rekram1-node merged commit b91080a into anomalyco:dev Jul 28, 2026
2 checks passed
@rekram1-node

Copy link
Copy Markdown
Collaborator

this lgtm, sorry it fell under radar

@YacineMK YacineMK mentioned this pull request Aug 1, 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.

3 participants