Repository navigation
Replies: 2 comments
|
Follow-up scope for the same provider: #34215 — ZCode provider: drive |
0 replies
|
Follow-up implementing the T3 attaches to the user-level daemon, so the adapter no longer reads the credential store or mints project tokens itself. Everything else in this idea — GLM model picking, runtime modes, steering — is unchanged. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Ask
Should T3 Code support ZCode — the CLI for Z.AI's GLM Coding Plan — as a provider? This is the product case that was asked for when #33684 was closed: a provider is a product decision that needs maintainer direction before code, so this thread is the place to settle direction and scope, not to request a merge. No PR is open.
Everything that was in the separate
zcode servedesign thread (#34215) is folded into Appendix A below below, so this is the single thread to read.What ZCode is
Z.AI sells GLM Coding Plan subscriptions and ships an official
zcodeCLI for them. A subscriber signs in once withzcode login; the CLI holds the session and the plan entitlements, and exposes a local protocol (app-server --stdio, and a long-runningzcode serve) for hosts to drive turns.Why it fits T3 Code
GLM-5.3andGLM-5.3-Flash, each with reasoning levelslow,high,maxand a 1M context window, so new plan models appear without an adapter change.Two ways to integrate it, and what each costs
zcode app-server --stdio(what feat(provider-zcode): add ZCode as a provider #33684 did). This protocol splits the CLI into a host and an agent, and T3 Code plays the host, so the host has to answer the agent's credential requests: read the CLI's encrypted credential store and mint short-lived project tokens through Z.AI's endpoints. It would be the only provider here that decrypts a vendor credential store or reimplements a vendor endpoint chain — every other one integrates where the vendor binary owns credentials end to end (Kirokiro-cli acp --auth-method=cli, Claude and Antigravity over ACP/SDKauthenticate, Codexaccount/login/start, OpenCodeopencode serve). We do not recommend this route, and it is the main reason not to revive that branch.zcode serve(what feat(provider-zcode): add the ZCode provider on the zcode serve transport #34713 did). The CLI's own server performs the credential exchange in vendor code. T3 Code reads the daemon's local control files (run/status.jsonplus an ingress token) — not Z.AI credentials — and calls the daemon's host services for login state, entitlement, and the model list. Design detail and measurements in Appendix A below.If this is in scope, route 2 is the one we would stand behind.
What it costs the maintainers
packages/provider-zcode) plus registry wiring:builtInDrivers,model-manifest.json,providerStatusCache,settingsSecrets,managedProviders, contracts, settings search on web and mobile, a provider docs page, and the release smoke script.MINIMUM_ZCODE_VERSION = 0.17.0) to pin behavior.zcode serveis a hidden subcommand (absent from--help) and its channel protocol is undocumented, so we reverse-engineered it from the shipped bundle. Any CLI upgrade can move it. That is an argument for keeping the whole transport behind one adapter file, and a fair reason to say no until the CLI documents a host protocol.Evidence that route 2 works
Against zcode 3.17.2 / CLI 0.17.1 on a developer machine: provider status, the GLM picker, a streaming turn, AskUserQuestion, steering, interrupt,
/compact, and resume after a T3 restart. Captures of each are in Appendix D.The credential-free claim is measured, not asserted, and the scripts plus raw payloads are published in Appendix C. An isolated daemon seeded with the runtime catalog,
setting.json, andprovider_config.jsonbut nocredentials.jsonreturnsoauth.getActiveProvider→null, every account provider atavailability: "unavailable"/entitled: false/executable: false/unavailableReason: "not-connected", and an empty model picker. With the real login, the same three read-only calls return the account, the two GLM models with the same reasoning levels, and per-provideraccountState. The entitlement ladder and model enumeration therefore come from the daemon; nothing reads the Z.AI credential store. Details in Appendix A below.Questions for maintainers
zcode servethe route you want, or would you rather wait until the CLI documents a host protocol?Status
Both attempts are closed and unmerged, and both are kept as tags on the fork so this stays reference material rather than a pending PR:
panudetjt/t3code@zcode-ref-33684— app-server transport (closed feat(provider-zcode): add ZCode as a provider #33684)panudetjt/t3code@zcode-ref-serve— serve transport (closed feat(provider-zcode): add the ZCode provider on the zcode serve transport #34713)The former design thread #34215 is now part of this one; see Appendix A.
Appendix A — the `zcode serve` transport, measured
Why route 2 exists
zcode app-server --stdiosplits the CLI into a host and an agent, and the agent asks its host for provider credentials before every account-model request. Playing the host means T3 Code has to read the CLI's encrypted credential store and mint a project access token through Z.AI's business endpoints itself. Theserveroute removes both: the CLI's own server owns the exchange.What it costs to switch transports:
What the daemon exposes instead of the credential store
Read-only calls against a live daemon (zcode 3.17.2, provider CLI 0.17.1):
oauth.getActiveProvider"zai"— the login indicator (2 ms)model-selection.getViewaccount:zai-individual-coding-plan, modelsGLM-5.3andGLM-5.3-Flash,reasoningLevel: [low, high, max],contextWindow: 1000000(1 ms, 1958 B)provider-settings.getViewaccountState { availability, entitled, current, unavailableReason }plusexecutable(1-2 ms, 44 KB)model-selection.getViewmatches what the branch's file-based enumeration produced, model for model, including reasoning levels. Soprovider/updateAccountConfigis not needed at all, and the badge and picker no longer needsetting.json,current.json, or the catalog files.Credential-free negative control
An isolated
serve --supervisorinstance seeded with the runtime catalog,setting.json, andprovider_config.json, but nocredentials.json, returns:Nothing in that path touches the Z.AI credential store. The only local files a client needs are the daemon's own
run/status.jsonandrun/ingress-token.Traps worth recording before anyone builds on this
usage-stats.getEntitlementSnapshot().authenticatedistrueeven with no credentials ({"authenticated": true, "unavailableReason": "not_configured"}), so it is not a login signal. Useoauth.getActiveProvider !== null.unavailableReason: "not-connected", not"not-authenticated".accountStatealone cannot separate "logged out" from "logged in, plan not connected", so pair it withoauth.getActiveProvider.availability: "unknown"(account probe still running) makes models non-executable. An offline probe means an empty picker, where today's catalog enumeration would still list models — the badge has to distinguish "no models" from "not probed yet".Cost
Warm daemon calls are 1-2 ms. The
zcode doctor --jsonprobestatus.tsruns today is ~1.0 s (1.05 / 1.00 / 1.03 over three runs).provider-settings.onDidChangeandmodel-selection.onDidChangeare subscribable, so the badge and picker can refresh without polling.Transport mechanics, for whoever reads the code
Frames are
1 byte kind + u32 id + u32 ack + u32 len, body is tagged/varint. A call header is[100, id, channel, method]with a single-element arg list; replies are 200 initialized, 201 result, 202 error, 203 rejected, 204 event. Dispatch ishandler[cmd].apply(handler, args)on the service object, so the callable surface is exactly that object's methods — there is no introspection endpoint. The capability comes fromPOST /api/rpc-host-capabilitywith the ingress token as Bearer, then travels asx-zcode-rpc-host-capabilityonws://<host>:<port>/ws/host?token=….Appendix B — what already exists in the branches
panudetjt/t3code@zcode-ref-serve(the head of #34713) is the full provider on this transport: packagepackages/provider-zcode, the orchestration adapter and its tests, the daemon client (status.json+ ingress token, capability handshake, v4 conversation channel,resolveInteraction), and the registry wiring listed above.panudetjt/t3code@zcode-ref-33684is the earlier app-server version. The serve branch already carries its adapter work, so that tag is kept only to compare the two credential paths.Neither is a merge candidate as-is: both sit behind 384 commits of
main, and the conflicts are concentrated in the registry files, not in the provider package.Appendix C — the measurements, published so they can be checked
Everything below was measured on this machine against ZCode
3.16.3(CLI0.17.0, the branch's declared floor) and3.17.2(CLI0.17.1). The scripts, raw payloads, and the one patch live on the fork so the numbers are auditable rather than asserted:panudetjt/t3code@zcode-evidence— README is the index.credentials.jsonsession/resumetakes no mode;setModeexists at the floor versionapp-server --stdioon both versionszcodeEndpoint.tsplus the catalog directory nameThree results worth having inline, because they are the ones someone would otherwise take on faith:
Error taxonomy is usable for a version floor.
session/doesNotExist→-32601 Method not found,session/resumewith an unknown key →-32602 Invalid params — Unrecognized key: "mode", unknown session →-32004 Session not found. So "this CLI is too old" is distinguishable from "this call is wrong". Both versions behave identically.A trap in the mode API.
session/create { mode: "guarded" }lands insettings.permission.mode, whilesession.modein the same reply is always"build"— that field is the build/plan interaction mode. Readingsession.modemakes a working permission selection look ignored.session/resumepreserves the permission mode but rejects amodeparameter outright, which is exactly why a host has to callsession/setModeafter a resume and before a turn when the two disagree.The endpoint is an origin, and the catalog hash says so.
normalizeZCodeEndpointOriginreturnsnew URL(value).origin, andbuildZCodeEndpointUrlsrebuilds<origin>/api/v1. The built-in catalog directory is…/3.17.2/endpoint-78d7c3bef4024722642626fe3669a799, andsha256("https://zcode.z.ai")is78d7c3bef4024722642626fe3669a7995df81a7686ae62e0c31d41a14e61faca— the first 32 hex characters of the production origin. Hash the origin for both the environment and the catalog path, or the CLI reports no models for a valid login.No script in the pack sends a prompt or starts a turn, so reproducing any of it costs nothing.
Appendix D — captures from the two branches
All of these are from the closed branches, live against the CLI on one machine. They live on the fork's release tag
pr-evidenceso the links survive the branches; the machine name in the window chrome is the host these ran on.Route 1 —
zcode app-server --stdio(#33684)Route 2 —
zcode serve(#34713)zcode servewhen T3 Code starts the ZCode daemon"model-selection.getViewresolveInteractionFour of them inline, for scanning:
All reactions