Repository navigation
qoder 0.2.29: QwenWork (千问办公) — public cloud and enterprise flagship - #319
LittlefishStudent wants to merge 2 commits into
Conversation
yetone
left a comment
There was a problem hiding this comment.
Thanks, @LittlefishStudent. This is the shape the ruling asked for, and the behaviour checks out. Only the tests stand between it and a merge.
What I ran at c228168
- Whole repo,
TMPDIR=$T HOME=$T/home bun test: 2127 pass, 0 fail. (HOMEhas to sit undertmpdir(), or the isolation guards in zcode and others throw.) packages/qoder alone: 195 pass.bun scripts/check.mjs: all ok. scripts/try.sh qoder(magpie 0.1.1296, sandbox HOME): it listsqoder(17 models),qoder-cn(4),qwenwork(3) andqwenwork-enterprise(3).- A recording probe with fetch mocked. It records every request the plugin makes for a model list, a chat (the body decoded), and a usage read that gets 401 and then succeeds on a rotated token. Random fields are normalized.
- Qoder and Qoder CN: base 4d73d22 and this PR give byte-identical recordings. Their behaviour doesn't change.
- QwenWork: the list and the chat both go out with ClientType 6, scene qwork, version 1.1.59 and product qoder_work. The chat body has
session_type: qoder_work,business.product: qoder_workand the QwenWork system prompt. Usage gets 401, refreshes withtarget: "c", reads again, and returnssignIn: "kept". Only when the refresh is refused too does it returnexpired. There is no PAT method and nocheckin. Machine ids arerandomUUID(), andmachineForCampaignruns only forqoder, so Qoder desktop's identity doesn't reach QwenWork.
- qwenwork.cn is Alibaba's own service (whois, see #314), not a relay.
Blocking: hooks that no test catches. The ruling asked that "the signing and body hooks need tests that go red without them". I broke each hook by hand and ran packages/qoder:
| Broken by hand | Red |
|---|---|
chat signed without site (index.mjs:2204) |
1 |
model list signed without site (:619) |
1 |
enterpriseHost routing (:256) |
4 |
503 fallback (:625) |
1 |
PAT / check-in off, normalizeUser |
1 each |
qoderBody(chat, m) without site (:2196) |
0 |
systemPrompt (:897), sessionType (:916) |
0 |
queue status signed without site (:1118) |
0 |
the usage 401 rotation removed (:2045) |
0 |
deviceRefreshTarget (:1687) |
0 |
- The body hooks are the same gap as #313's item 3, still 0 red.
_internal.decodeBodyis already exported. Decode the recordedagent_chat_generationbody in the chat test and assertsession_type,business.product/versionand the system text. - The PR body says the usage 401 rotation is tested, but
qwenwork.test.mjs:172-188uses an expired access token, sofresh()renews it before account-context is ever asked. Please add the case the ruling named: a live access token, account-context answers 401 to it and 200 to the rotated token, and the test assertssignIn !== "expired"and that a refresh was made. Add a second case where the refresh is refused and the result isexpired. - Please also add tests for the queue status headers (a chat whose first answer is a queue refusal) and for the refresh body's
target: "c".
Smaller
qwenwork.test.mjs:118: the title says "to the enterprise's own host", but the test drives the public plugin and asserts no host.:128(pub.loader?.()) is dead code, andqoderKeysat:100-105is never used.index.mjs:1859-1860: "Overridable with QWENWORK_* env vars and defaults.json". Nothing reads either;QWENWORK_ENT_DOMAINis the only variable. Please drop the line or make it true.index.mjs:328: a device-only account still storesemail: "", even though the sign-in read it andaccountIdis now email-first. Unless QwenWork needs the field empty, keep the email, as Qoder does.
Once 1 to 3 are in, I'll merge.
|
All in at eeda75c — every hook that broke 0-red now has a test that goes red without it, and I broke each one again to check:
Smaller: the chat test's dead Whole repo, your isolation style ( |
…y, as its desktop and CLI do (yetone/magpie#2911, #304) witt-bit (yetone/magpie#2911, 10-22): after Qoder CN's update moved its daily 100 Credits into the desktop's 权益中心, magpie's Qoder CN check-in stopped working; Andrew0767 (#304) sees the same with Qoder desktop installed. The plugin sent Qoder CN's campaigns pages no device identity at all ("Qoder CN does not need this local helper"). What Qoder CN's clients do, read from their own packages: - Qoder CN desktop 0.4.9 (the .deb's out/main): its requests carry Cosy-ClientType 10 and, through createAuthorizedHeaders, the identity from <resources>/umid/runtime-info run with environment `regionCode === "global" ? 3 : 0`, i.e. 0 for Qoder CN, the uid on stdin (--account-stdin) on macOS and Windows. Campaigns are found through GET /sash/api/v1/me/notifications (hasClaimableCampaign, campaignPopupUrl). When the identity can't be read it sends the request without it (resolveMachineIdentity's catch returns null). - qoderclicn (@qodercn-ai/qoderclicn 1.1.64, 1.1.70, 1.1.73): campaigns.list is GET /sash/api/v1/me/campaigns, needing the UMID from 1.1.64 and requireMachineIdentity() from 1.1.70, UMID environment ONLINE = 0; its config dir is QODERCN_CONFIG_DIR, else QODERCN_CLI_HOME (or home) + QODERCN_CONFIG_DIR_NAME (or .qoder-cn), and it caches the helper in <config>/.bin/runtime-info-<platform>-<arch>-<hash>. - Install places: Qoder CN.app/Contents/Resources/umid/runtime-info (seen inside Qoder-CN-Installer-mac-arm64.zip's payload, 0.4.9), /opt/Qoder-CN/resources/umid/runtime-info (the .deb), and on Windows umid/runtime-info.exe among Qoder-CN-win-x64-user.exe's owned files, with "Uninstall Qoder CN.exe" (electron-builder's %LOCALAPPDATA%\Programs\<productName>; the folder itself not seen). The plugin now keeps a runtime per site (RUNTIMES): Qoder CN reads its own helper (those paths, its CLI's folders, QODERCN_RUNTIME_INFO, never the international Qoder's) with environment 0, and sends Cosy-MachineToken and Cosy-MachineType on the list, the claim and the campaigns proxy. As the desktop does, a Qoder CN request without a readable identity still goes out, so an account that was claiming without Qoder CN installed (0.2.21's live PAT claim) keeps doing so. When such a list offers no daily claim, the check-in is ineligible for the day, saying to install Qoder CN desktop or sign in to its CLI (no helper), or failed and asked again (a helper that didn't answer), instead of "inactive". International Qoder is unchanged. Run: in packages/qoder, TMPDIR=$H HOME=$H/home bun test: 195 pass, 0 fail. On the old index.mjs the new tests are 9 red (checkin.test.mjs 5 lookup tests and the env-0 proxy test, native-checkin.test.mjs the env-0 claim, the ineligible and the failed cases). Repo root at this commit (rebased on 26e3e5f): 2151 pass, 1 skip, 0 fail; bun scripts/check.mjs ok. Not tried: a real Qoder CN account (none available) or a real Qoder CN install, so whether Qoder CN now hides the daily claim from a request without the identity is inferred from its clients, not seen on the wire; the Windows install folder is electron-builder's default, not seen; the desktop's own claim happens in a remote page (campaignPopupUrl) whose calls weren't seen, so the list/claim pages stay those of 0.2.21; Cosy-MachineCode, which both Qoder CN clients send, is not sent. Version 0.2.29 is open PR #319's (QwenWork).
|
main now holds qoder 0.2.30 (929a8b3, Qoder CN check-in device identity, touches packages/qoder/index.mjs, README.md, package.json and two tests). This PR needs a rebase and 0.2.31. |
eeda75c to
8f16bc1
Compare
|
Rebased on main at 929a8b3 (qoder 0.2.30) and bumped to 0.2.31 — head is now 8f16bc1. The 0.2.30 change (Qoder CN's check-in device identity) touches the campaigns path only; QwenWork's sites set Verified after the rebase, your isolation style: whole repo 2264 pass / 0 fail, |
8f16bc1 to
935c5e9
Compare
|
Rebased again on main at 421117e (qoder 0.2.31) and bumped to 0.2.32 — head is now 935c5e9. The 0.2.31 change (one task per prompt's tool loop, #330) reshaped Verified after the rebase: whole repo 2331 pass / 0 fail, |
…y, as its desktop and CLI do (yetone/magpie#2911, magpie-community#304) witt-bit (yetone/magpie#2911, 10-22): after Qoder CN's update moved its daily 100 Credits into the desktop's 权益中心, magpie's Qoder CN check-in stopped working; Andrew0767 (magpie-community#304) sees the same with Qoder desktop installed. The plugin sent Qoder CN's campaigns pages no device identity at all ("Qoder CN does not need this local helper"). What Qoder CN's clients do, read from their own packages: - Qoder CN desktop 0.4.9 (the .deb's out/main): its requests carry Cosy-ClientType 10 and, through createAuthorizedHeaders, the identity from <resources>/umid/runtime-info run with environment `regionCode === "global" ? 3 : 0`, i.e. 0 for Qoder CN, the uid on stdin (--account-stdin) on macOS and Windows. Campaigns are found through GET /sash/api/v1/me/notifications (hasClaimableCampaign, campaignPopupUrl). When the identity can't be read it sends the request without it (resolveMachineIdentity's catch returns null). - qoderclicn (@qodercn-ai/qoderclicn 1.1.64, 1.1.70, 1.1.73): campaigns.list is GET /sash/api/v1/me/campaigns, needing the UMID from 1.1.64 and requireMachineIdentity() from 1.1.70, UMID environment ONLINE = 0; its config dir is QODERCN_CONFIG_DIR, else QODERCN_CLI_HOME (or home) + QODERCN_CONFIG_DIR_NAME (or .qoder-cn), and it caches the helper in <config>/.bin/runtime-info-<platform>-<arch>-<hash>. - Install places: Qoder CN.app/Contents/Resources/umid/runtime-info (seen inside Qoder-CN-Installer-mac-arm64.zip's payload, 0.4.9), /opt/Qoder-CN/resources/umid/runtime-info (the .deb), and on Windows umid/runtime-info.exe among Qoder-CN-win-x64-user.exe's owned files, with "Uninstall Qoder CN.exe" (electron-builder's %LOCALAPPDATA%\Programs\<productName>; the folder itself not seen). The plugin now keeps a runtime per site (RUNTIMES): Qoder CN reads its own helper (those paths, its CLI's folders, QODERCN_RUNTIME_INFO, never the international Qoder's) with environment 0, and sends Cosy-MachineToken and Cosy-MachineType on the list, the claim and the campaigns proxy. As the desktop does, a Qoder CN request without a readable identity still goes out, so an account that was claiming without Qoder CN installed (0.2.21's live PAT claim) keeps doing so. When such a list offers no daily claim, the check-in is ineligible for the day, saying to install Qoder CN desktop or sign in to its CLI (no helper), or failed and asked again (a helper that didn't answer), instead of "inactive". International Qoder is unchanged. Run: in packages/qoder, TMPDIR=$H HOME=$H/home bun test: 195 pass, 0 fail. On the old index.mjs the new tests are 9 red (checkin.test.mjs 5 lookup tests and the env-0 proxy test, native-checkin.test.mjs the env-0 claim, the ineligible and the failed cases). Repo root at this commit (rebased on 87df5a9): 2151 pass, 1 skip, 0 fail; bun scripts/check.mjs ok. Not tried: a real Qoder CN account (none available) or a real Qoder CN install, so whether Qoder CN now hides the daily claim from a request without the identity is inferred from its clients, not seen on the wire; the Windows install folder is electron-builder's default, not seen; the desktop's own claim happens in a remote page (campaignPopupUrl) whose calls weren't seen, so the list/claim pages stay those of 0.2.21; Cosy-MachineCode, which both Qoder CN clients send, is not sent. Version 0.2.29 is open PR magpie-community#319's (QwenWork).
Per the review of magpie-community#313/magpie-community#314, QwenWork serves from the qoder package itself, as more provider ids beside qoder and qoder-cn, on site hooks this commit adds to the protocol (rebased on main at qoder 0.2.33, so the queue fix, Qoder CN's check-in, the per-task request_set_id and the task's business name keep their behaviour): - qwenwork: the public cloud (gateway.qwenwork.cn), the desktop client's own device flow with redirect_uri=qwenwork-cn://, its account-context for usage. pat: false and checkin: false: the PAT exchange and the campaigns endpoint are Qoder's, and Qoder's desktop device identity is never sent to QwenWork. - qwenwork-enterprise: the enterprise flagship (企业旗舰版, VPC), which serves web/openapi/api on the enterprise's own single domain — asked at sign-in (refusing loopback/intranet suffixes, ports, paths and IPs; QWENWORK_ENT_DOMAIN presets it), routed to by the account's enterpriseHost for every call, its device flow sending no redirect_uri (the flagship's /device/selectAccounts refuses one). Accounts are named <email|uid> (<domain>); usage renews an expired account rather than lapsing it; a 503 catalog (the flagship deploys none) falls back to the shipped qwork list, which says in a comment its flags are copied from the public cloud, not checked against a flagship. - chat, the model list, the queue paths and refresh all sign for the site: its client type, scene, version, product and RSA key; the chat body carries the site's session type, business product and system prompt. The account field is enterpriseHost, not vpcDomain (that names a site's CN VPC suffix); the public account is named email-first. - registry: the qoder entry lists the two new provider ids. Verified end to end against a real deployment (sign-in by email OTP, flash and qwen3.8-max-preview chats, the Enterprise plan's credits); unofficial, not affiliated with Alibaba.
Each hook the review broke by hand to find untested now has a test that goes red without it — verified by breaking every one again: - the chat test decodes the recorded agent_chat_generation body and asserts session_type qoder_work, business.product qoder_work, version 1.1.59 and the QwenWork system prompt (red without qoderBody's site, systemPrompt or sessionType); - a queue-refused chat (code 10605) makes the queue status request, whose headers are asserted for the site (red without queueStatus's site); - usage with a live token that account-context refuses (401) rotates the device token once and stays signed in, counted; a refused refresh then expires it (red without the rotation); - the device token refresh is asserted to be asked with target: "c" (red without deviceRefreshTarget); - a device-only account keeps the email the sign-in read (it was blanked); - the dead qoderKeys block and the QWENWORK_* env line the code doesn't read are gone. All 223 of the package's tests pass with everything in place; the whole repo gives 2461 pass / 0 fail; check.mjs all ok.
935c5e9 to
c543f1b
Compare
|
Rebased again on main (qoder 0.2.32 and 0.2.33 landed since) and bumped to 0.2.34 — head is now c543f1b. 0.2.33's change (a task's business name is the prompt's first ten characters) is kept: the Verified after the rebase: whole repo 2461 pass / 0 fail, |
The single PR the ruling on #313/#314 asked for: QwenWork (千问办公) serves from the qoder package itself, as more provider ids beside
qoderandqoder-cn, rebased on main (0.2.28's queue fix keeps its behaviour), at 0.2.29.What
qwenworkgateway.qwenwork.cn)redirect_uri=qwenwork-cn://; usage reads its account-contextqwenwork-enterpriseredirect_uri— the flagship's/device/selectAccountsrefuses one, as the desktop client's enterprise mode behavesQWENWORK_ENT_DOMAINpresets the domain so the sign-in asks nothing.Both reviews' items, addressed
From #313:
cosyHeaders(CHAT_URL, cred, wire, siteOf(site, cred)), as are the model list and the queue paths — verified by a test that asserts the outgoing headers (ClientType 6, scene qwork, version 1.1.59, product qoder_work) and goes red when the site argument is dropped;package.jsonkeeps its diff to the version, description and keywords lines;enterpriseHost, notvpcDomain(that names a site's CN VPC suffix);protocolexport and its not-a-stable-API caveat, and the QwenWork section.From #314:
pat: false,checkin: false): both are Qoder's, and Qoder's desktop device identity is never sent to QwenWork;bun.lockchange, no separate package, no registry entry of its own: the qoder entry lists the two new provider ids.Verified
flashandqwen3.8-max-previewchats, usage showing the Enterprise plan's credits;HOME=$(mktemp -d) bun test: 2130 pass (Qoder and Qoder CN's 185 untouched);bun scripts/check.mjs: all ok.Unofficial for QwenWork: not affiliated with Alibaba. @harwinvoid FYI — the
qwenworkprovider id your plugin served moves here.