Skip to content

Add ElectronHub DevPass provider#5255

Open
larkinwc wants to merge 11 commits into
can1357:mainfrom
larkinwc:electronhub-devpass-login
Open

Add ElectronHub DevPass provider#5255
larkinwc wants to merge 11 commits into
can1357:mainfrom
larkinwc:electronhub-devpass-login

Conversation

@larkinwc

Copy link
Copy Markdown

Remakes closed PR #4858 (auto-closed: author not vouched). Adds ElectronHub Coding Plan (DevPass) as a login/model provider with all six live DevPass models (kimi-k2.6:dev, minimax-m2.7:dev, gpt-oss-120b:dev, glm-5.2:dev, gemma-4-31b-it:dev, qwen3.6-27b:dev), dynamic discovery filtered to DevPass-only records, GLM/Z.AI thinking compat, and a fixture-backed contract test asserting the static seed matches a live /v1/models snapshot. See #4858 and #4872 for prior context/review discussion.

@github-actions github-actions Bot added the vouched Passed the vouch gate label Jul 12, 2026
@larkinwc larkinwc force-pushed the electronhub-devpass-login branch from 7c60636 to 3e38417 Compare July 12, 2026 04:14

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c606365ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts Outdated
@roboomp roboomp added auth Authentication and login flows cli CLI commands and arguments feat provider:electronhub providers LLM provider-specific issues review:p2 triaged labels Jul 12, 2026

@roboomp roboomp left a comment

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.

P2: coherent new ElectronHub DevPass provider, with package changelogs, focused login/catalog tests, and generated catalog data; still a new provider surface requiring maintainer sign-off, and prior related PR #4872 was closed rather than landed.

One blocking inline finding: dynamic discovery can disable tool calling from metadata.function_call === false even though ElectronHub documents all DevPass models as function-calling capable.

Verification run locally: bun test packages/ai/test/electronhub-login.test.ts packages/catalog/test/electronhub-provider.test.ts passed (11 tests); bun run check:types passed in packages/ai and packages/catalog. Thanks for the contribution.

Comment thread packages/catalog/src/provider-models/openai-compat.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 76115e6b34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts Outdated
@larkinwc larkinwc force-pushed the electronhub-devpass-login branch from 76115e6 to 2cc02be Compare July 12, 2026 20:52

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2cc02becc7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts
@larkinwc larkinwc force-pushed the electronhub-devpass-login branch from 2cc02be to 3fd2ea4 Compare July 12, 2026 23:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3fd2ea4019

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88d363be2d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts Outdated
larkinwc added 10 commits July 13, 2026 20:26
- Add gpt-oss-120b:dev, glm-5.2:dev, gemma-4-31b-it:dev, and
  qwen3.6-27b:dev to ELECTRONHUB_DEVPASS_STATIC_MODELS alongside the
  existing kimi-k2.6:dev / minimax-m2.7:dev entries, matching the live
  DevPass catalog confirmed via extensive OMP + direct API smoke
  testing on all six models.
- Force reasoning: true on every DevPass model in the discovery
  mapper (docs.electronhub.ai/billing/coding-plan states all DevPass
  models support reasoning; qwen3.6-27b:dev's live metadata reports
  reasoning:false but has been observed returning non-zero
  reasoning_tokens).
- Add a pricing.plan === "devpass" fallback signal to
  isElectronHubDevpassModel, since two of the six live records omit
  metadata.devpass_only entirely.
- Keep (do not drop) the existing GLM/Z.AI thinking compat
  (thinkingFormat: "zai", reasoningDisableMode: "omit",
  reasoningContentField: "reasoning_content") and the
  metadata.function_call === false -> supportsTools: false guard,
  both load-bearing given ElectronHub's DevPass integration has
  changed behavior mid-flight during testing.
- Add a live-snapshot fixture
  (test/fixtures/electronhub-devpass-models.json) plus contract tests
  asserting the static seed's ids/contextWindow match it, addressing
  the "unverifiable extra models" review concern raised on PR can1357#4872.
- Regenerate models.json (electronhub section only; unrelated
  provider churn from this run was discarded).
roboomp (blocking): mapElectronHubDevpassModel no longer sets
supportsTools: false from metadata.function_call === false.
ElectronHub's Coding Plan docs state every DevPass model supports
function calling; trusting a possibly stale/bad /v1/models record
over that would silently strip tool use from a coding agent, the
same failure mode the reasoning:true override already guards
against.

Codex (P2): electronHubCompatForModel now forces
thinkingFormat: "openai" for Qwen-family DevPass ids
(qwen3.6-27b:dev today). Without an explicit override,
buildOpenAICompat's id-based detection classifies any "qwen"-named
id into the native Qwen dialect (top-level enable_thinking boolean),
but ElectronHub's gateway expects the generic OpenAI-shaped
reasoning_effort surface for every proxied model regardless of
backend -- the same reason Fireworks already carries an
isQwen && isFireworks -> "openai" carve-out in buildOpenAICompat.
Applied to both the static seed entry and the dynamic-discovery
mapper so the override holds pre- and post-login.

Regenerated models.json (electronhub section only) and added tests
covering both fixes.
…nHub

Codex (P2): thinkingFormat "zai" made getModelDefinedEfforts
(model-thinking.ts) restrict glm-5.2:dev to the Z.ai-native two-tier
high/max effort ladder and let the unsupported "max" value reach the
wire. ElectronHub's /v1/chat/completions documents a flat
reasoning_effort enum (none/minimal/low/medium/high/xhigh) for every
proxied model -- confirmed directly against
docs.electronhub.ai/api-reference/chat/completions's OpenAPI schema.

Fix: switch glm-5.2:dev's ElectronHub compat to thinkingFormat
"openai" (matching the rest of the DevPass fleet), which resolves to
the wider five-tier ladder, and add reasoningEffortMap: { max: "xhigh" }
so the remaining top tier still lands on a value ElectronHub actually
accepts instead of "max".

Moving off "zai" also silently drops its reasoning_content
continuation-replay behavior -- openai-completions.ts only fires that
branch for thinkingFormat === "zai". ElectronHub is exactly the
documented "custom proxy setup" escape hatch for this
(compat/openai.ts's PROXY_OPENAI_COMPAT_PROVIDERS comment), so
glm-5.2:dev now opts back in explicitly via
replayReasoningContent: true to keep cross-turn reasoning replay
unchanged by the dialect switch.

Regenerated models.json (electronhub section only) and extended the
GLM contract test to cover the new dialect, effort remap, and replay
flag.
A prior rebase onto main picked up an unrelated upstream change that
stamps stored api_key credentials with a `source: "login"` field
(see openrouter-login.test.ts, auth-storage-api-key-login.test.ts,
auth-storage-email-dedupe.test.ts for the same shape already updated
elsewhere). This PR's electronhub-login test predates that change and
still asserted the old two-field shape, so it started failing
silently -- packages/ai wasn't in this PR's routine verification
scope until now. Bring the assertion in line with the established
sibling-provider pattern.
…ub disable

Codex (P2): when a caller disables reasoning (Thinking Off), the
shared ElectronHub compat fell back to generic per-dialect behavior
instead of an ElectronHub-specific mapping:

- Five of six DevPass models default to thinkingFormat "openai" ->
  reasoningDisableMode "lowest-effort", which sends the ladder's floor
  tier (e.g. reasoning_effort: "minimal") -- reasoning is reduced, not
  disabled.
- glm-5.2:dev explicitly used "omit", which drops the field entirely,
  falling back to ElectronHub's own server-side default rather than
  honoring the caller's disable choice.

ElectronHub's /v1/chat/completions documents reasoning_effort: "none"
as its own distinct wire value (below "minimal") for fully hiding
reasoning output. Neither existing behavior reaches it.

No existing OpenAIReasoningDisableMode sends an explicit "none" --
added a new "reasoning-effort-none" mode:
- packages/catalog/src/types.ts: new union member.
- packages/ai/src/providers/openai-shared.ts: encodeChatCompletions
  DisabledReasoning sets reasoning_effort = "none" for the new mode.
- packages/catalog/src/provider-models/openai-compat.ts: set on the
  shared ELECTRONHUB_OPENAI_COMPAT base so all six DevPass models
  inherit it (dynamic discovery included, since mapElectronHubDevpass
  Model routes through the same helper); dropped glm-5.2:dev's now-
  redundant "omit" override so it inherits the same base value.

Considered reusing the existing reasoningEffortMap mechanism (as
Fireworks does: FIREWORKS_REASONING_EFFORT_MAP remaps its lowest
selectable tier's wire value to "none") instead of a new disable mode,
but rejected it -- that only works because Fireworks' own vocabulary
treats "none" as a rename of its floor tier. ElectronHub's "none" is a
genuinely separate, lower value than "minimal" in a six-tier ladder;
remapping the floor tier to "none" would incorrectly disable reasoning
whenever a caller explicitly selected the lowest non-off effort.

Regenerated models.json (electronhub section only). Added a shared
reasoningDisableMode assertion across all six bundled DevPass models
in packages/catalog/test/electronhub-provider.test.ts, and a wire-
level test in packages/ai/test/openai-completions-disable-reasoning
.test.ts asserting reasoning_effort: "none" reaches the request body
when disableReasoning: true.
An earlier rebase onto main (which had cut real 16.3.x releases in the
interim) mechanically placed this branch's changelog additions inside
now-released `## [16.3.12]` sections instead of `## [Unreleased]`,
also leaving a duplicate `### Added` heading in each file. Confirmed
via `git log -S` that every displaced line traces only to this
branch's own commits, never to genuine upstream 16.3.12 content, so
moving them is a correction, not an edit to released history.

Moved to `## [Unreleased]` and removed the duplicate headings in:
- packages/ai/CHANGELOG.md (ElectronHub `/login` entry; also added a
  new entry for the reasoning-effort-none disable mode)
- packages/catalog/CHANGELOG.md (ElectronHub DevPass catalog entry;
  also added entries for the accumulated review-round dialect fixes:
  GLM/Qwen thinkingFormat, reasoningEffortMap, reasoning-effort-none,
  and the function_call guard removal)
- packages/coding-agent/CHANGELOG.md (ELECTRONHUB_DEV_API_KEY docs
  entry)

Verified with `bun scripts/fix-changelogs.ts` — zero further changes,
confirming the sections are already in the format the release tooling
expects.
…rt-none

Codex (P2): minimax-m2.7:dev is a MiniMax M2-family id, so
isMinimaxM2FamilyModelId backfills thinking.requiresEffort, and
normalizeMandatoryReasoningOptions (packages/ai/src/stream.ts) clamps
a Thinking Off request to the ladder's lowest effort ("low") before
the compat-level reasoning-effort-none branch ever runs. Correct
observation: the new disable mapping genuinely is unreachable for
this one bundled model.

Investigated whether that's an actual regression before changing
anything. Live-probed ElectronHub's real /v1/chat/completions directly
for minimax-m2.7:dev across reasoning_effort "none", "minimal", "low",
and an omitted field (2 trials each): reasoning content length stayed
in the same noisy 200-600+ character range for every value, with no
measurable suppression from "none" versus "low" (330 vs 250 chars on
the first pair, no consistent gap across repeats). The gateway does
not make this architecturally mandatory-reasoning model honor "off"
either -- confirming the family.ts predicate's existing rationale
("Underlying model accepts only low|medium|high ... 400s on minimal,
xhigh, or none") describes a real constraint that ElectronHub's proxy
doesn't paper over, and matching the exact same requiresEffort:true
treatment minimax-m2.7 already gets on Fireworks (see the "MiniMax M2
is a reasoning-first architecture" precedent in
packages/catalog/test/model-thinking.test.ts).

Setting thinking.suppressWhenOff to route "off" to reasoning_effort:
"none" here would not achieve the reviewer's actual goal (suppressing
reasoning) and would break consistency with every other MiniMax M2
host in the catalog for a change that is empirically a no-op. Left the
mandatory-reasoning clamp as-is; added a code comment at the model
definition (packages/catalog/src/provider-models/openai-compat.ts)
documenting the investigation, and a regression test locking in
requiresEffort: true / suppressWhenOff not set for minimax-m2.7:dev
specifically, so this isn't "fixed" into a regression later without
re-deriving the same empirical finding.
Rebasing onto origin/main (67 new commits, including a real 16.5.0
release cut on both packages/ai and packages/coding-agent) mechanically
displaced this branch's Unreleased changelog additions into the new
`## [16.5.0]` sections again, each leaving a duplicate/misplaced
`### Added` entry. Same class of issue fixed twice already this PR --
moved both entries back to `## [Unreleased]`:
- packages/ai/CHANGELOG.md (ElectronHub `/login` entry, reasoning-
  effort-none entry)
- packages/coding-agent/CHANGELOG.md (ELECTRONHUB_DEV_API_KEY docs
  entry)

packages/catalog/CHANGELOG.md had no upstream commits touching it this
round and needed no changes.

Verified with `bun scripts/fix-changelogs.ts` -- zero further changes
needed. Rebased branch retested clean: bun --cwd=packages/ai run test
(2822 pass) and bun --cwd=packages/catalog run test (430 pass), both
check:types clean.
…mode

Codex (P2): the shared ElectronHub base compat's reasoning-effort-none
disable mode also applies to gpt-oss-120b:dev, sending reasoning_effort:
"none" on Thinking Off. The existing GPT-OSS handling in model-thinking.ts
restricts this family to low/medium/high, and the issue can1357#2315 regression
coverage (packages/ai/test/issue-2315-repro.test.ts) keeps GPT-OSS
disable requests on the lowest supported tier specifically because
Harmony rejects minimal/xhigh/none -- this entry bypassed that
protection by opting the model into ElectronHub's provider-wide mode.

Unlike minimax-m2.7:dev (previous round: thinking.requiresEffort
already makes the new mode structurally unreachable, confirmed as a
harmless no-op), gpt-oss-120b:dev has no such interception --
reasoning-effort-none genuinely reaches the wire for this model. Live-
probed ElectronHub's /v1/chat/completions directly and reasoning_effort:
"none" did not 400 (3 trials, all 200s, reasoning length noisy but
comparable across none/minimal/low/omitted) -- but that's weaker
evidence than an established cross-provider regression test built from
a real prior production failure, and there's no guarantee the gateway
won't tighten validation to match the underlying Harmony backend later.
Overrode gpt-oss-120b:dev to explicitly retain reasoningDisableMode:
"lowest-effort" (the same tested-safe path used by every other GPT-OSS
host in the catalog) rather than the shared reasoning-effort-none mode,
in both the static seed and the dynamic-discovery mapper (both route
through electronHubCompatForModel).

Updated the shared "bundles all six" test to no longer assert a uniform
reasoningDisableMode across all six models (no longer true), split it
into a shared assertion for the four models that do use reasoning-
effort-none (kimi/glm/gemma/qwen) plus dedicated static- and dynamic-
discovery tests for gpt-oss-120b:dev's lowest-effort exception. Also
corrected the catalog changelog's "five of the six" wording -- it's
four of six now that both minimax and gpt-oss are excluded, each for
a distinct documented reason.
@larkinwc larkinwc force-pushed the electronhub-devpass-login branch from 88d363b to 28099ea Compare July 14, 2026 01:36

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28099eab07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/catalog/src/provider-models/openai-compat.ts
Codex (P2): the shared ElectronHub compat left maxTokensField unset,
so buildOpenAICompat defaulted it to max_completion_tokens (compat/
openai.ts's useMaxTokens allowlist -- Mistral, Moonshot-native, Z.ai/
Zhipu, Chutes, Fireworks, direct DeepSeek -- does not include
ElectronHub). ElectronHub's /v1/chat/completions documents max_tokens
as the output cap field. For kimi-k2.6:dev specifically, the existing
Kimi-family alwaysSendMaxTokens flag (isKimiModel, compat/openai.ts)
means the wrong field gets sent on every request, not just capped
ones.

Live-probed this directly against ElectronHub's real endpoint before
changing anything: a request with max_completion_tokens:5 was silently
ignored (the model produced its full ~100-line uncapped response),
while the identical request with max_tokens:5 correctly capped output
(finish_reason "length", completion_tokens 5). This confirms the bug
is real and was silently defeating kimi-k2.6:dev's runaway-reasoning
protection on ElectronHub specifically -- that safeguard exists (per
its own code comment) precisely because Kimi can otherwise emit very
long reasoning traces before the final answer.

Set maxTokensField: "max_tokens" on the shared ELECTRONHUB_OPENAI_COMPAT
base so all six DevPass models inherit the correct field (both the
static seed, via the bare constant, and dynamic discovery, via
electronHubCompatForModel). Regenerated models.json (electronhub
section only).

Added a maxTokensField assertion to the existing shared six-model
bundle test, plus a dedicated wire-level test that builds the real
bundled kimi-k2.6:dev model, drives it through streamOpenAICompletions
with a mock fetch, and asserts the captured request body carries
max_tokens (not max_completion_tokens) -- proving the fix end-to-end
rather than only at the config level.
@larkinwc larkinwc requested a review from roboomp July 14, 2026 02:24

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3a5c0f408

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1858 to +1860
const ELECTRONHUB_OPENAI_COMPAT = {
supportsStore: false,
supportsDeveloperRole: false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Map ElectronHub forced tool choices to auto

When the coding-agent forces a tool (for example guided setup or the final retry forcing respond), this new ElectronHub compat falls through to buildOpenAICompat's default supportsForcedToolChoice: true, so openai-completions.ts can send tool_choice: "required" or a named function object. ElectronHub's chat-completions docs only advertise tool_choice values none and auto, so those forced-tool requests can be rejected instead of letting the model choose; set supportsForcedToolChoice: false for this provider so the existing mapper downgrades forced choices to auto.

Useful? React with 👍 / 👎.

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

Labels

auth Authentication and login flows cli CLI commands and arguments feat provider:electronhub providers LLM provider-specific issues review:p2 triaged vouched Passed the vouch gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants