Skip to content

feat(runtime): support z.ai Start Plan providers in standalone mode - #249

Closed
Erencv wants to merge 1 commit into
kingsword09:mainfrom
Erencv:feat/start-plan-standalone
Closed

Erencv wants to merge 1 commit into
kingsword09:mainfrom
Erencv:feat/start-plan-standalone

Conversation

@Erencv

@Erencv Erencv commented Oct 31, 2026

Copy link
Copy Markdown

Draft — opened alongside #248 for early feedback; I'll finalize (or withdraw, or retarget upstream) per maintainer guidance.

What this does

Makes account:zai-start-plan / account:bigmodel-start-plan providers usable in standalone mode (CLI + TUI) when the account is entitled to them — e.g. Z.ai's ZCODE WEEKEND BUILD promos, which today are Desktop-only. Full analysis, evidence and reproduction in #248.

How it works

The runtime already ships everything needed: the bundled catalog contains the start-plan providers, the OpenAI-compatible request path branches on accountAccess.mode === "start-plan" (retry/captcha recovery), and the signed-header transport is provider-agnostic. Only the standalone account plumbing refuses to see the mode. Following the existing runtime-*-patches.ts conventions (acorn-anchored on bundler labels, exact-shape matching, incompatible() on drift), runtime-start-plan-patches.ts makes five minimal edits:

# Anchor (bundler label) Change
1 readStandaloneCodingPlanCatalog enumerate start-plan providers beside individual-coding-plan, so they reach the registry and get an entitlement computed
2 resolveStandaloneCodingPlanProvider exclude start-plan ids from login's "exactly one provider per family" assertion, so browser/api-key login keeps targeting the Coding Plan flow
3 standaloneAccountIdentityCredentialKey map start-plan provider ids to the family's Coding Plan identity credential — the identity is account-scoped, and z.ai reports start-plan grants for the same account
4 createStandaloneProviderRuntimeHeadersPort accept the start-plan access mode in refreshBeforeModelRequest
5 createStandaloneProviderRuntimeHeadersPort for start-plan requests, authenticate with the zcodejwttoken credential — zcode.z.ai/api/v1/zcode-plan/* rejects both the Coding Plan api-key (manual path) and the exchanged api.z.ai project JWT (OAuth path) with 401

No protocol changes: requests are still built, anti-bot-signed and sent by the genuine runtime. Billing is domain-isolated (zcode-plan endpoints can only draw start-plan buckets), so this cannot silently spend the paid plan.

Registration

sync-runtime.ts: new start-plan-standalone entry, requirement: "optional", verify: hasRuntimeStartPlan — if a future upstream runtime ships native support (or renames the anchors), the patch skips/fails loudly instead of corrupting the bundle.

Testing

  • test/runtime/start-plan.test.ts:
    • fixture patch: pristine-shaped account functions → all five edits applied, has* flips, idempotent
    • behavioral: the patched standaloneAccountIdentityCredentialKey maps account:zai-start-plan / account:bigmodel-start-plan to the family Coding Plan identity key and leaves other providers untouched
    • synced-runtime guard: vendor/zcode.cjs ships the support after sync
  • Verified locally against the real 3.17.1-42 runtime artifact (pristine copy):
    • bun test test/runtime/start-plan.test.ts → 3 pass
    • ZCODE_NODE=node bun bin/zcode.ts --model account:zai-start-plan/GLM-5.3-Flash --prompt 'Reply with exactly: ok' → ok, exit 0
    • TUI: /model lists account:zai-start-plan/GLM-5.3-Flash, GLM-5.2, GLM-5-Turbo; switching and real turns work; Desktop's Start Plan balance decreases accordingly

Notes for review

  • Edit 5 is the only "semantic" choice: it selects a different stored credential for start-plan requests. I validated it empirically (header-diff via a fetch hook + curl matrix against zcode-plan/anthropic/v1/messages — see Standalone CLI cannot use z.ai Start Plan providers (e.g. ZCODE WEEKEND BUILD) — analysis + proposed patch #248); if you'd prefer a different credential strategy (e.g. deriving a plan-scoped token from the OAuth access token), I'm glad to rework.
  • bun lockfile untouched; no new dependencies (reuses acorn already used by runtime-shared-oauth-patches.ts).
  • The entitlement snapshot itself stays host-computed semantics: standalone computes entitled from stored credentials (identity + OAuth token), exactly as it already does for the coding plan.

The bundled provider catalog ships account:zai-start-plan /
account:bigmodel-start-plan (e.g. the ZCODE WEEKEND BUILD token promos),
and Desktop's host registers them whenever the account is entitled, but
the standalone account paths only enumerate Individual Coding Plan
providers, so the CLI fails with 'Provider Registry 中不存在 Model'.

Five minimal edits, AST-anchored on the existing bundler labels:

- readStandaloneCodingPlanCatalog: enumerate Start Plan providers too
- resolveStandaloneCodingPlanProvider: keep login's one-provider-per-family
  contract by excluding Start Plan ids
- standaloneAccountIdentityCredentialKey: map Start Plan providers to the
  family's Coding Plan identity (the identity is account-scoped)
- createStandaloneProviderRuntimeHeadersPort: accept the Start Plan access
  mode, and authenticate Start Plan requests with the zcode-scoped JWT
  credential, since zcode.z.ai/api/v1/zcode-plan rejects the Coding Plan
  api-key and the exchanged api.z.ai project JWT with 401

No protocol changes: requests are still built and signed by the genuine
runtime. Registered as an optional patch with a behavioral test
(test/runtime/start-plan.test.ts) covering the fixture patch, identity
mapping and idempotency.
@kingsword09

Copy link
Copy Markdown
Owner

Thanks @Erencv — the investigation in #248 and this PR was very helpful, especially identifying the standalone catalog gates and the ZCode JWT required by Start Plan.

I've opened #251 as a maintainer follow-up to integrate this with our existing shared OAuth flow. It keeps one account login for both plans, handles Desktop-only sessions without aliasing Coding Plan identities, and selects the Start Plan JWT before any Coding Plan project-token resolution. It also covers account switching, rejected/missing sessions, and JWTs without an optional exp claim.

I've now verified locally that Start Plan works with my account, and the automated regression suite also passes (158 tests). Your work is credited in the new PR and commit message, and I'd appreciate your review there.

Once #251 is merged, we can close this PR as superseded. Thanks again for getting this started!

kingsword09 added a commit that referenced this pull request Nov 1, 2026
Reuse the existing ZCode account session for standalone Start Plan providers without aliasing Coding Plan identities, exchanging project tokens, or falling back to paid credentials. Guard account changes, cancellation and rejected sessions, and support JWTs without optional expiry claims.

Follow up on #248 and #249; thanks to Erencv for investigating the standalone gates and identifying the ZCode JWT credential.
@kingsword09

Copy link
Copy Markdown
Owner

已合并 #251,现将此 PR 作为已被替代的实现关闭。感谢 @Erencv 在 #248 和本 PR 中对 Start Plan provider 目录限制及 ZCode JWT 的调查,相关贡献已在 #251 中保留致谢。Start Plan 已通过本地账号实测,#251 的 CI 也已全部通过。

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.

2 participants