@magpie-community/opencode-workbuddy-auth 0.1.42 → 0.1.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/index.mjs +83 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -235,7 +235,16 @@ is used.
|
|
|
235
235
|
- Kimi-K3, Kimi-K2.6
|
|
236
236
|
- MiniMax-M3
|
|
237
237
|
|
|
238
|
-
A model's reasoning levels are its variants (`reasoningEffort`).
|
|
238
|
+
A model's reasoning levels are its variants (`reasoningEffort`). A chat
|
|
239
|
+
that names no level goes at the model's own default from the config
|
|
240
|
+
(`reasoning.defaultEffort`, "high" for DeepSeek-V4.1-Flash), as WorkBuddy's
|
|
241
|
+
client sends it: WorkBuddy doesn't think when a chat names none, so
|
|
242
|
+
OpenCode's default variant got answers without thinking. An effort the
|
|
243
|
+
client names, `none` too, goes as it came.
|
|
244
|
+
|
|
245
|
+
A chat goes gzipped (`Content-Encoding: gzip`), as WorkBuddy's own client
|
|
246
|
+
sends its model requests (`RequestBodyGzip` in both builds' product.json).
|
|
247
|
+
Claude's Messages route goes as it came.
|
|
239
248
|
|
|
240
249
|
A model's price is its `credits` ("x0.29") and the config's
|
|
241
250
|
`modelPromotions`. A discount for whole days (Step-5-Preview's 独家限免) is
|
package/index.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { createHash, randomBytes } from "node:crypto"
|
|
|
13
13
|
import { readFileSync } from "node:fs"
|
|
14
14
|
import { homedir } from "node:os"
|
|
15
15
|
import { join } from "node:path"
|
|
16
|
+
import { gzipSync } from "node:zlib"
|
|
16
17
|
|
|
17
18
|
const APP_VERSION = "2.0.0" // the version WorkBuddy's sign-in page is opened with
|
|
18
19
|
const POLL_MS = 1000
|
|
@@ -1289,6 +1290,24 @@ function fitted(body) {
|
|
|
1289
1290
|
}
|
|
1290
1291
|
}
|
|
1291
1292
|
|
|
1293
|
+
// gzipped is a chat's body compressed, as WorkBuddy's own client sends its
|
|
1294
|
+
// model requests: its CLI's GzipRequestProcessor (WorkBuddy 5.9.3, CLI
|
|
1295
|
+
// 2.165.0; WorkBuddy AI 5.8.4 the same) gzips each POST's body and sets
|
|
1296
|
+
// Content-Encoding: gzip when the product's RequestBodyGzip feature is on,
|
|
1297
|
+
// which both builds' product.json turn on and /v3/config (merged over it)
|
|
1298
|
+
// doesn't turn off. Sent as plain JSON, a long agent conversation went up
|
|
1299
|
+
// whole on every step: runmiNeverstop on X saw 2.89 GB up to
|
|
1300
|
+
// copilot.tencent.com against 258 MB down. Measured 2026-10-28 on
|
|
1301
|
+
// www.workbuddy.ai: a gzipped chat answers as the plain one does. A
|
|
1302
|
+
// Messages request (Claude on the China build) goes as it came: that route
|
|
1303
|
+
// wasn't tried gzipped. null when the body isn't sent gzipped.
|
|
1304
|
+
function gzipped(native, b) {
|
|
1305
|
+
if (native) return null
|
|
1306
|
+
if (typeof b === "string") return gzipSync(Buffer.from(b))
|
|
1307
|
+
if (b instanceof ArrayBuffer || ArrayBuffer.isView(b)) return gzipSync(b)
|
|
1308
|
+
return null
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1292
1311
|
// prepared is a request's body read once for every change the loader makes
|
|
1293
1312
|
// to it and everything it reads off it (plugins#461): a long chat, 45 MiB
|
|
1294
1313
|
// of history, was parsed six times on its way, once by each step, and
|
|
@@ -2119,6 +2138,37 @@ function effortsOf(d, site, id) {
|
|
|
2119
2138
|
return EFFORT_ORDER.filter((e) => set.has(e))
|
|
2120
2139
|
}
|
|
2121
2140
|
|
|
2141
|
+
// defaultEffortOf is the level WorkBuddy's own client asks a model for when
|
|
2142
|
+
// the user picked none: its CLI's configureThinkingSettings (WorkBuddy
|
|
2143
|
+
// 5.9.3, CLI 2.165.0) takes the session's effort, else the settings', else
|
|
2144
|
+
// the config's reasoning.defaultEffort, else reasoning.effort, and sends it
|
|
2145
|
+
// as reasoning_effort unless thinking was turned off. A request with no
|
|
2146
|
+
// reasoning_effort is not thinking on WorkBuddy's side: measured 2026-10-28
|
|
2147
|
+
// on www.workbuddy.ai, deepseek-v4.1-flash (defaultEffort "high") answered
|
|
2148
|
+
// with 0 reasoning tokens without one, and thought at low and high
|
|
2149
|
+
// (troilus1011 on X, OpenCode's default variant). A default the model's
|
|
2150
|
+
// levels don't hold is left out, as the CLI clamps it to one they do.
|
|
2151
|
+
function defaultEffortOf(d, efforts) {
|
|
2152
|
+
const own = d.reasoning?.defaultEffort ?? d.reasoning?.effort
|
|
2153
|
+
return typeof own === "string" && efforts.includes(own) ? own : undefined
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
// withDefaultEffort gives a chat that names no effort the model's default
|
|
2157
|
+
// (defaultEffortOf), as WorkBuddy's client sends it; true when it did. An
|
|
2158
|
+
// effort the client named, "none" too, goes as it came.
|
|
2159
|
+
function withDefaultEffort(chat, list) {
|
|
2160
|
+
if (!chat || typeof chat !== "object" || namesEffort(chat)) return false
|
|
2161
|
+
const m = list?.find((x) => x.id === chat.model)
|
|
2162
|
+
if (!m?.effort) return false
|
|
2163
|
+
chat.reasoning_effort = m.effort
|
|
2164
|
+
return true
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
// namesEffort is whether a chat names its effort itself, in either spelling
|
|
2168
|
+
function namesEffort(chat) {
|
|
2169
|
+
return chat.reasoning_effort !== undefined || (!!chat.reasoning && typeof chat.reasoning === "object" && chat.reasoning.effort !== undefined)
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2122
2172
|
async function liveModels(site, a) {
|
|
2123
2173
|
const headers = new Headers()
|
|
2124
2174
|
sign(site, a, headers)
|
|
@@ -2145,6 +2195,8 @@ async function liveModels(site, a) {
|
|
|
2145
2195
|
if (es.length) {
|
|
2146
2196
|
const canOff = d.reasoning?.canDisableThinking
|
|
2147
2197
|
m.efforts = [...(!d.onlyReasoning && (canOff == null || canOff) ? ["none"] : []), ...es]
|
|
2198
|
+
const def = defaultEffortOf(d, es)
|
|
2199
|
+
if (def) m.effort = def
|
|
2148
2200
|
}
|
|
2149
2201
|
}
|
|
2150
2202
|
out.push(m)
|
|
@@ -2238,6 +2290,24 @@ function makePlugin(site) {
|
|
|
2238
2290
|
if (lists.size > 64) lists.delete(lists.keys().next().value)
|
|
2239
2291
|
return list
|
|
2240
2292
|
}
|
|
2293
|
+
// effortList is the list a chat's default effort is read from
|
|
2294
|
+
// (withDefaultEffort): listed's, or null when there is none to read — a
|
|
2295
|
+
// key WorkBuddy's CLI reads no config with (as models does), or a read
|
|
2296
|
+
// that failed within PRICE_TTL, so a config that can't be read costs a
|
|
2297
|
+
// chat one try a minute, not one each
|
|
2298
|
+
const unlisted = new Map()
|
|
2299
|
+
const effortList = async (a) => {
|
|
2300
|
+
if (a.source === "key" && !remoteConfig(a.key)) return null
|
|
2301
|
+
const k = listKey(a)
|
|
2302
|
+
if (Date.now() - (unlisted.get(k) ?? 0) < PRICE_TTL) return null
|
|
2303
|
+
try {
|
|
2304
|
+
return await listed(a)
|
|
2305
|
+
} catch {
|
|
2306
|
+
unlisted.set(k, Date.now())
|
|
2307
|
+
if (unlisted.size > 64) unlisted.delete(unlisted.keys().next().value)
|
|
2308
|
+
return null
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2241
2311
|
const freeOnly = () => magpie?.option?.(site.id, FREE_ONLY) === true
|
|
2242
2312
|
// onlyFree is a list with the switch on: its free models, or a failure
|
|
2243
2313
|
// when there are none to tell (magpie then keeps the list it had)
|
|
@@ -2369,10 +2439,20 @@ function makePlugin(site) {
|
|
|
2369
2439
|
let changed = p.changed
|
|
2370
2440
|
body = p.body
|
|
2371
2441
|
if (!native) names = p.names
|
|
2442
|
+
// a chat that names no effort is asked at the model's default,
|
|
2443
|
+
// as WorkBuddy's client asks it (withDefaultEffort); with no
|
|
2444
|
+
// list to read (effortList) the chat goes as it came
|
|
2445
|
+
if (!native && chat && !namesEffort(chat) && withDefaultEffort(chat, await effortList(a))) changed = true
|
|
2372
2446
|
chatHeaders(site, headers)
|
|
2373
2447
|
attendChat(headers, chat, session)
|
|
2374
|
-
const post = (b) =>
|
|
2375
|
-
|
|
2448
|
+
const post = (b) => {
|
|
2449
|
+
// a chat goes gzipped, as WorkBuddy's client sends it
|
|
2450
|
+
// (gzipped); its size on the wire is what unanswered weighs
|
|
2451
|
+
const z = gzipped(native, b)
|
|
2452
|
+
if (z) headers.set("Content-Encoding", "gzip")
|
|
2453
|
+
else headers.delete("Content-Encoding")
|
|
2454
|
+
return fetch(req ? req.url : input, { ...init, method: init?.method ?? req?.method, headers, body: z ?? b }).catch((e) => unanswered(site, a, z ?? b, e, init?.signal))
|
|
2455
|
+
}
|
|
2376
2456
|
// a 401 is answered once, on whichever try meets it: by a
|
|
2377
2457
|
// sign-in with another access token (reissued), the request
|
|
2378
2458
|
// sent once more with it, never again after that; else, or
|
|
@@ -2653,4 +2733,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
|
2653
2733
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
2654
2734
|
|
|
2655
2735
|
// for tests
|
|
2656
|
-
export const _internal = { FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, asReasoning, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
|
2736
|
+
export const _internal = { withDefaultEffort, defaultEffortOf, gzipped, FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, asReasoning, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-workbuddy-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"description": "OpenCode provider plugins for WorkBuddy's plans: WorkBuddy (CodeBuddy, copilot.tencent.com) and WorkBuddy AI (www.workbuddy.ai)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|