Repository navigation
feat: add io.github.yahooyuan666.zcode2pi — ZCode/BigModel Coding Plan free quota as a PI-Desktop model provider - #64
Conversation
… free quota) Adds a model provider that exposes the ZCode / BigModel Coding Plan free quota inside PI-Desktop, together with the packed 0.1.0 artifact and the catalog entry. Design notes worth review: - The provider uses apiStyle "chat_completions" against https://open.bigmodel.cn/api/coding/paas/v4. That is PI-Desktop's own first-class path for Zhipu Coding Plan (ADR 0155), so both ends speak Chat Completions and the relay translates nothing. - The relay binds 127.0.0.1 only and rejects non-loopback Host headers. - The request body is forwarded byte for byte. `stream` is never forced, no placeholder tools are injected and `tool_choice` is never added. That keeps this plugin clear of the two failure modes reported against JasonYu0822/opencode2pi-desktop#1 (free-lane gate) and vastsa#3 (non-streaming callers receiving SSE fragments), both of which stem from that plugin having to satisfy OpenCode's anonymous-channel gate. BigModel has no such gate. - The API key never reaches this plugin: authKind "api_key" keeps it in the host secret store and the relay forwards headers unchanged. Security review signals raised by scripts/security_audit.py (expected for this capability set, all justified in the PR body): manifest.json unknown permission requires host-policy review: provider.register main.js:109 network access main.js:8 credential/secret handling (comment text only) main.js:9 persistent activation/timer passthrough.test.mjs:59 network access (local echo server in the test) No BLOCKERs. passthrough.test.mjs passes 12/12 against a local echo upstream.
|
@YahooYuan666 is attempting to deploy a commit to the vastsa's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Closing this as part of the migration that removed plugin sources from this repository. Since commit 38284f1 the Your work is not lost — your branch and fork stay exactly as they are. To ship
One detail worth keeping: the center rebuilds the published manifest from what you submit, so send This repository still welcomes distribution-side contributions (a broken |
Summary
Adds
io.github.yahooyuan666.zcode2pi— a model provider that exposes the ZCode / BigModel Coding Plan free quota (GLM-5.3-Flash) as a row in PI-Desktop's model picker — plus the packed0.1.0artifact and the catalog entry.Model:
GLM-5.3-Flash, 1M context, vision.What and why
ZCode's client already talks to BigModel's Coding Plan, but PI-Desktop has no way to reach that quota: the keys live encrypted inside ZCode's credential store and there is no API-key path exposed. This plugin closes the gap by declaring a provider that PI-Desktop can authenticate itself, pointed at BigModel's Coding Plan endpoint.
Design decisions
The endpoint is not arbitrary. The provider uses
apiStyle: "chat_completions"againsthttps://open.bigmodel.cn/api/coding/paas/v4. That is PI-Desktop's own first-class path for Zhipu Coding Plan — ADR 0155 defines thezhipuai-coding-planpreset with exactly that URL and apiStyle. Both ends therefore speak Chat Completions and the relay translates nothing; SSE is forwarded chunk by chunk.I first built this against BigModel's Anthropic endpoint (
api/anthropic/v1/messages) and it failed in a way worth recording: PI-Desktop sends OpenAI-shaped tools ({type, function}) and that endpoint rejects them withbody.tools.0.name: Field required. The two endpoints are individually correct and both accept the same API key; they simply cannot be mixed. Anchoring to the documented preset is the fix.The request body is forwarded byte for byte.
streamis never forced, no placeholder tools are injected,tool_choiceis never added. This is what keeps the plugin clear of the two failure modes reported againstJasonYu0822/opencode2pi-desktop:bash/readfree-lane gate is an OpenCode anonymous-channel requirement. BigModel has no such gate.stream: trueupstream to satisfy the gate in Add 草稿计算器 (local.scratch-calc) v0.0.1 #1. The hack that Add 草稿计算器 (local.scratch-calc) v0.0.1 #1 requires is what causes Add 小清新待办 (pi.todo) v0.5.0; rename local.scratch-calc to pi.scratch-calc #3. This plugin needs neither, so it has neither failure.passthrough.test.mjsasserts this against a local echo upstream rather than taking it on faith.The API key never reaches this plugin.
authKind: "api_key"keeps the key in PI-Desktop's secret store and attaches it to the outgoing request; the relay forwards request headers unchanged and has no code path that reads, stores or logs a credential. There is no.env, no hard-coded key, and nothing to revoke here.Capability matrix
This plugin requests
background.serviceand performs outbound network access, so it is High risk underSECURITY.md(two maintainers + manual review + threat-model notes + explicit confirmation tests). Full accounting:startServiceinmain.js127.0.0.1, tries41940→41941→41942listen()only ever passes'127.0.0.1'; port fallback prevents a stale process hijacking the providerhandleRequestHostis not127.0.0.1/localhost/::1with 403isLoopbackHost(); blocks DNS rebinding and other local portshandleForward,main.js:109POSTto the single hard-coded URLhttps://open.bigmodel.cn/api/coding/paas/v4/chat/completionsopen.bigmodel.cnonlyhandleForwardopen.bigmodel.cnstream,toolsortool_choice; asserted by testshandleForwardaccept-encoding: identityforced; everything else forwarded verbatimopen.bigmodel.cnopen.bigmodel.cn, via the hostdescribeShape, called only on upstream 4xx/5xxtools[0]field names, top-level field namesabortUpstreamstreamDone; cancels thereader, not the locked bodyfspermission requested.Threat model
The plugin runs a local network listener, which is the capability worth being careful about.
Hostcheck; there is no separate auth token, because every request it can serve is a request PI-Desktop itself is authorized to make. A local attacker who can already read PI-Desktop's process memory can also read the key; this does not widen that.Hostfrom a browser context, and theHostcheck rejects a cross-origin-shaped request. DNS rebinding is covered because a rebound name resolves to a loopback address but arrives with a non-loopbackHost.open.bigmodel.cnwould see whatever the user already sends there directly.Negative-path tests
passthrough.test.mjs(12 checks, all passing) points the relay at a local echo upstream and covers the failure directions, not just the happy path:Hostrejected with 403stream: falseunmodifiedContent-Type: application/jsondata:fragmentsstreamnot injected astruetoolsinjectedtool_choiceinjectedRun with:
Gate results
python3 scripts/pack_plugin.py plugins/io.github.yahooyuan666.zcode2pi→ ok, sha256a779a30b…, 28465 bytespython3 scripts/security_audit.py --check-packages→ no BLOCKERs for this plugin; five REVIEW signals, each justified in the capability matrix abovepython3 scripts/rebuild_catalog.py→ catalog entry added, sha256 matches the artifact; no existing entry touched (45 insertions / 1 deletion, the deletion being theupdatedAttimestamp)GLM-5.3-Flashselected from the model picker and returned normal streamed completionsOne note for maintainers, unrelated to this PR
scripts/security_audit.py --check-packagescurrently reportsBLOCKER: packed bytes do not match the current plugin sourcefor every package in the repository when run from a Windows checkout. The cause is that this repository has no.gitattributes, so withcore.autocrlf=truethe working tree is checked out as CRLF while the packages were built from LF sources. I verified this onpi.todo-0.6.5: the source has 415 CRLF endings and the packedmain.jshas 415 bare LF, so the two are not byte-identical.The packages themselves are fine. Adding
.gitattributeswith* -text(as the distribution mirrorAIUO-Net/pi-desktop-pluginsalready has) would make the audit meaningful on Windows. I did not add it here, since it is outside the scope of this submission.This plugin avoids the trap: its sources and its packed artifact are both LF and byte-identical, verified against the pushed blobs rather than the working tree.
Credits
The provider-declaration + loopback-relay shape follows
JasonYu0822/opencode2pi-desktop. The.piplugbyte layout was worked out from PI-Desktop'spackages/plugin-devkit/src/pack.tsand confirmed against existing packages in this repository.License
MIT