@magpie-community/opencode-workbuddy-auth 0.1.36 → 0.1.38
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 +25 -0
- package/index.mjs +171 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,15 @@ The package exports `WorkBuddyAuthPlugin` (`workbuddy`) and
|
|
|
26
26
|
|
|
27
27
|
WorkBuddy 5.6 and later keep the sign-in encrypted, which only the app
|
|
28
28
|
opens, so this way fails there and says so: use the browser sign-in.
|
|
29
|
+
- **API key** (since 0.1.37). A key made on the build's own keys page
|
|
30
|
+
(`https://www.workbuddy.cn/profile/keys` for `workbuddy`,
|
|
31
|
+
`https://www.workbuddy.ai/profile/keys` for `workbuddy-ai`), sent as
|
|
32
|
+
WorkBuddy's own CLI sends one: `X-API-Key` and `Authorization: Bearer`,
|
|
33
|
+
both the key, and `X-User-Id: anonymous_<the key's last 8 characters>`,
|
|
34
|
+
to the same API as the other sign-ins. A key isn't renewed; a refused one
|
|
35
|
+
says to check it. A key's credits are unknown (WorkBuddy's own client reads
|
|
36
|
+
none with a key), and its models are `/v3/config`'s only for `ck_`/`pt_`
|
|
37
|
+
keys, as the CLI asks; any other key keeps the list below.
|
|
29
38
|
|
|
30
39
|
A browser sign-in is kept as an OpenCode `oauth` auth: the access and
|
|
31
40
|
refresh tokens, their expiry, the user id and the domain; desktop's as a
|
|
@@ -219,6 +228,22 @@ some hours of the day (Hy4 preview, free 23:00–8:00) is given as its full
|
|
|
219
228
|
price, never as free: magpie keeps the list until it asks again, so a list
|
|
220
229
|
asked for at night would say "free" all day (#121).
|
|
221
230
|
|
|
231
|
+
### Free models only
|
|
232
|
+
|
|
233
|
+
Each site (WorkBuddy, WorkBuddy AI) has a "Free models only" switch in its
|
|
234
|
+
provider settings in magpie, off by default (#430). When it is on:
|
|
235
|
+
|
|
236
|
+
- the list holds only the models the site serves at no cost now. A model free
|
|
237
|
+
only at night, or one with no price, counts as paid;
|
|
238
|
+
- a request for any other model is answered by the plugin with a 404
|
|
239
|
+
`model_not_found` and never sent, so no credits are spent. magpie rests
|
|
240
|
+
only that model and tries the next provider;
|
|
241
|
+
- if the price list can't be read, nothing is sent (503), since whether the
|
|
242
|
+
model is free is unknown. An API key WorkBuddy lists no prices for lists
|
|
243
|
+
no models.
|
|
244
|
+
|
|
245
|
+
The price list is read again at most once a minute for requests.
|
|
246
|
+
|
|
222
247
|
## Credits in magpie
|
|
223
248
|
|
|
224
249
|
magpie's usage card shows the account's credits from the resource summary.
|
package/index.mjs
CHANGED
|
@@ -67,6 +67,8 @@ const SITES = {
|
|
|
67
67
|
authID: "workbuddy-desktop",
|
|
68
68
|
platform: "workbuddy",
|
|
69
69
|
ai: false,
|
|
70
|
+
// where this build's API keys are made (see keyAccount)
|
|
71
|
+
keys: "https://www.workbuddy.cn/profile/keys",
|
|
70
72
|
models: CN_MODELS,
|
|
71
73
|
// it serves the Claude models on Anthropic's Messages API too (see
|
|
72
74
|
// nativeOf)
|
|
@@ -79,6 +81,7 @@ const SITES = {
|
|
|
79
81
|
authID: "workbuddy-desktop-ai",
|
|
80
82
|
platform: "workbuddy-ai",
|
|
81
83
|
ai: true,
|
|
84
|
+
keys: "https://www.workbuddy.ai/profile/keys",
|
|
82
85
|
models: AI_MODELS,
|
|
83
86
|
// models whose images WorkBuddy AI drops though its config says they
|
|
84
87
|
// take them (see textOnly)
|
|
@@ -299,7 +302,14 @@ async function refreshed(site, auth) {
|
|
|
299
302
|
function sign(site, a, headers) {
|
|
300
303
|
headers.set("Authorization", "Bearer " + a.access)
|
|
301
304
|
headers.set("X-User-Id", a.uid ?? "")
|
|
302
|
-
|
|
305
|
+
if (a.source === "key") {
|
|
306
|
+
// the key's own header, and no X-Domain: a key's session has none
|
|
307
|
+
headers.set("X-API-Key", a.key)
|
|
308
|
+
headers.delete("X-Domain")
|
|
309
|
+
} else {
|
|
310
|
+
headers.delete("X-API-Key")
|
|
311
|
+
headers.set("X-Domain", domainOf(site, a))
|
|
312
|
+
}
|
|
303
313
|
headers.set("X-Product", "SaaS")
|
|
304
314
|
headers.set("X-IDE-Type", "WorkBuddy")
|
|
305
315
|
headers.set("User-Agent", "WorkBuddy/" + UA_VERSION)
|
|
@@ -313,6 +323,31 @@ function sign(site, a, headers) {
|
|
|
313
323
|
headers.set("X-Agent-Type", "main")
|
|
314
324
|
}
|
|
315
325
|
|
|
326
|
+
// keyAccount is the account an API key (OpenCode's {type: "api", key}) is
|
|
327
|
+
// sent as, the way WorkBuddy's own CLI sends one (@tencent-ai/codebuddy-code
|
|
328
|
+
// 2.177.0, CODEBUDDY_API_KEY): its API-key sign-in is a session whose access
|
|
329
|
+
// token is the key and whose uid is "anonymous_" and the key's last eight
|
|
330
|
+
// characters (ACC_USER_ID unset), personal, with no domain and no
|
|
331
|
+
// enterprise; and its model requests carry the key twice, X-API-Key and
|
|
332
|
+
// Authorization: Bearer (getCustomHeaders). Its requests go to the build's
|
|
333
|
+
// own host, the one its other sign-ins use: for the China build that is
|
|
334
|
+
// copilot.tencent.com, the CLI's own endpoint for that build
|
|
335
|
+
// (CODEBUDDY_INTERNET_ENVIRONMENT=internal, product.internal.json), and the
|
|
336
|
+
// same API as www.workbuddy.cn, where the keys are made (the CLI's
|
|
337
|
+
// CN_SAAS_CORE_API_FRONT_DOORS); for the international build,
|
|
338
|
+
// www.workbuddy.ai (the CLI's own default, www.codebuddy.ai, is CodeBuddy's,
|
|
339
|
+
// not WorkBuddy's). Nothing renews a key.
|
|
340
|
+
function keyAccount(auth) {
|
|
341
|
+
const key = typeof auth?.key === "string" ? auth.key.trim() : ""
|
|
342
|
+
if (!key) return null
|
|
343
|
+
return { key, access: key, uid: "anonymous_" + key.slice(-8), source: "key" }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// remoteConfig says whether WorkBuddy's own CLI asks /v3/config for the
|
|
347
|
+
// account's models with this key: only for keys that start ck_ or pt_
|
|
348
|
+
// (shouldLoadRemoteConfig); any other key keeps the built-in list.
|
|
349
|
+
const remoteConfig = (key) => /^(ck_|pt_)/.test(key)
|
|
350
|
+
|
|
316
351
|
// enterpriseHeaders names the enterprise (team) an account signed in as, as
|
|
317
352
|
// WorkBuddy's own client does on every request it makes for that account
|
|
318
353
|
// (its auth interceptor: X-Enterprise-Id and X-Tenant-Id, both the
|
|
@@ -557,6 +592,12 @@ function withoutSignedThinking(body) {
|
|
|
557
592
|
|
|
558
593
|
// chatOf is a chat's body as the object it is, null for one that isn't: a
|
|
559
594
|
// body that isn't text (bytes), or isn't JSON at all.
|
|
595
|
+
// bodyString is a body given as bytes, as text; anything else is null.
|
|
596
|
+
function bodyString(body) {
|
|
597
|
+
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return new TextDecoder().decode(body)
|
|
598
|
+
return null
|
|
599
|
+
}
|
|
600
|
+
|
|
560
601
|
function chatOf(body) {
|
|
561
602
|
if (typeof body !== "string") return null
|
|
562
603
|
try {
|
|
@@ -1419,6 +1460,8 @@ async function unanswered(site, a, body, err, signal) {
|
|
|
1419
1460
|
if (signal?.aborted || err?.name === "AbortError" || err?.name === "TimeoutError") throw err
|
|
1420
1461
|
const size = byteLength(body)
|
|
1421
1462
|
if (size <= EDGE_READS) throw err
|
|
1463
|
+
// the billing API isn't asked with a key: what it answers one is unknown
|
|
1464
|
+
if (a.source === "key") throw err
|
|
1422
1465
|
let status = 0
|
|
1423
1466
|
let challenge = ""
|
|
1424
1467
|
try {
|
|
@@ -1546,6 +1589,18 @@ function refusedText(site, a, why, note) {
|
|
|
1546
1589
|
)
|
|
1547
1590
|
}
|
|
1548
1591
|
|
|
1592
|
+
// keyRefused is the answer to a request WorkBuddy refused an API key for
|
|
1593
|
+
// (401): a key isn't renewed, so it says to check the key. Marked expired
|
|
1594
|
+
// only on WorkBuddy's word that the token itself is refused (invalidToken).
|
|
1595
|
+
function keyRefused(site, expired, note) {
|
|
1596
|
+
const message = `${site.name} refused this API key (401). ${note ? note + " " : ""}Check the key at ${site.keys}, then add it again in magpie: Providers → ${site.name}.`
|
|
1597
|
+
return new Response(JSON.stringify({ error: { message, type: "authentication_error", code: 401 } }), {
|
|
1598
|
+
status: 401,
|
|
1599
|
+
statusText: "Unauthorized",
|
|
1600
|
+
headers: { "content-type": "application/json", "X-Magpie-Sign-In": expired ? "expired" : "kept" },
|
|
1601
|
+
})
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1549
1604
|
// signedOut is the answer to a request WorkBuddy refused this account's
|
|
1550
1605
|
// sign-in for, renewed or not: a 401 that says so and what to do, which
|
|
1551
1606
|
// WorkBuddy's own (an HTML page, its {code, msg}) doesn't. expired marks
|
|
@@ -1978,6 +2033,29 @@ function replyAfterTools(body) {
|
|
|
1978
2033
|
return JSON.stringify(b)
|
|
1979
2034
|
}
|
|
1980
2035
|
|
|
2036
|
+
// FREE_ONLY is the switch that keeps an account off credits (#430): its
|
|
2037
|
+
// list holds only the models WorkBuddy serves at no cost (priceOf's free),
|
|
2038
|
+
// and a request for any other is answered here, never sent. A price that
|
|
2039
|
+
// can't be read is not free, and a list that can't be read sends nothing.
|
|
2040
|
+
const FREE_ONLY = "free_only"
|
|
2041
|
+
// PRICE_TTL is how long a list read for that check is used before it is
|
|
2042
|
+
// read again: a promotion that ends stops counting as free within it.
|
|
2043
|
+
const PRICE_TTL = 60_000
|
|
2044
|
+
|
|
2045
|
+
// notFree is the answer to a request the switch keeps from WorkBuddy. Its
|
|
2046
|
+
// words say the model, not the account, is what is turned away, so magpie
|
|
2047
|
+
// rests that model alone and asks another provider of it; they name no
|
|
2048
|
+
// quota or credit, which would rest the whole account as out of credit.
|
|
2049
|
+
function notFree(site, model, why) {
|
|
2050
|
+
const msg = why
|
|
2051
|
+
? `${site.name}'s model list couldn't be read (${why}), so whether model ${model || "(none)"} is free is unknown; with "Free models only" on it isn't sent`
|
|
2052
|
+
: `model ${model || "(none)"} is not available while "Free models only" is on: ${site.name} charges for it. Turn the switch off in ${site.name}'s provider settings to use it`
|
|
2053
|
+
return new Response(JSON.stringify({ error: { message: msg, type: "invalid_request_error", code: why ? "free_only_unknown" : "model_not_found" } }), {
|
|
2054
|
+
status: why ? 503 : 404,
|
|
2055
|
+
headers: { "content-type": "application/json", "X-Magpie-Sign-In": "kept" },
|
|
2056
|
+
})
|
|
2057
|
+
}
|
|
2058
|
+
|
|
1981
2059
|
function makePlugin(site) {
|
|
1982
2060
|
// the models of this site that refused tool results then the user's
|
|
1983
2061
|
// message, for this run: their next chats go with replyAfterTools at once
|
|
@@ -1985,7 +2063,30 @@ function makePlugin(site) {
|
|
|
1985
2063
|
// the system prompts this run WorkBuddy refused as an unapproved channel:
|
|
1986
2064
|
// their next chats go with systemAsUser at once, not refused first
|
|
1987
2065
|
const refusedSystems = new Set()
|
|
1988
|
-
return async ({ client }) =>
|
|
2066
|
+
return async ({ client, magpie }) => {
|
|
2067
|
+
// each account's list as last read, for FREE_ONLY: {at, list}
|
|
2068
|
+
const lists = new Map()
|
|
2069
|
+
const listKey = (a) => `${a.uid ?? ""}|${a.enterpriseId ?? ""}|${a.source === "key" ? a.key : ""}`
|
|
2070
|
+
// listed is the account's live list, read again past PRICE_TTL
|
|
2071
|
+
const listed = async (a, fresh = false) => {
|
|
2072
|
+
const k = listKey(a)
|
|
2073
|
+
const was = lists.get(k)
|
|
2074
|
+
if (!fresh && was && Date.now() - was.at < PRICE_TTL) return was.list
|
|
2075
|
+
const list = await liveModels(site, a)
|
|
2076
|
+
lists.set(k, { at: Date.now(), list })
|
|
2077
|
+
if (lists.size > 64) lists.delete(lists.keys().next().value)
|
|
2078
|
+
return list
|
|
2079
|
+
}
|
|
2080
|
+
const freeOnly = () => magpie?.option?.(site.id, FREE_ONLY) === true
|
|
2081
|
+
// onlyFree is a list with the switch on: its free models, or a failure
|
|
2082
|
+
// when there are none to tell (magpie then keeps the list it had)
|
|
2083
|
+
const onlyFree = (ms) => {
|
|
2084
|
+
if (!freeOnly()) return ms
|
|
2085
|
+
const free = ms.filter((m) => m.free)
|
|
2086
|
+
if (!free.length) throw new Error(`${site.name} lists no free model, and "Free models only" is on`)
|
|
2087
|
+
return free
|
|
2088
|
+
}
|
|
2089
|
+
return {
|
|
1989
2090
|
config: async (config) => {
|
|
1990
2091
|
config.provider ??= {}
|
|
1991
2092
|
config.provider[site.id] ??= {}
|
|
@@ -2007,15 +2108,37 @@ function makePlugin(site) {
|
|
|
2007
2108
|
// the account's own list, when it's signed in and WorkBuddy answers;
|
|
2008
2109
|
// else the list above
|
|
2009
2110
|
async models(provider, { auth }) {
|
|
2111
|
+
if (auth?.type === "api") {
|
|
2112
|
+
// asked as WorkBuddy's own CLI asks with a key (remoteConfig)
|
|
2113
|
+
const a = keyAccount(auth)
|
|
2114
|
+
if (!a || !remoteConfig(a.key)) {
|
|
2115
|
+
if (freeOnly()) throw new Error(`${site.name} lists no prices for this key, and "Free models only" is on`)
|
|
2116
|
+
return provider.models
|
|
2117
|
+
}
|
|
2118
|
+
let ms
|
|
2119
|
+
try {
|
|
2120
|
+
ms = await listed(a, true)
|
|
2121
|
+
} catch (e) {
|
|
2122
|
+
if (freeOnly()) throw e
|
|
2123
|
+
return provider.models
|
|
2124
|
+
}
|
|
2125
|
+
if (!ms.length && !freeOnly()) return provider.models
|
|
2126
|
+
return Object.fromEntries(onlyFree(ms).map((m) => [m.id, modelOf(site, provider, m)]))
|
|
2127
|
+
}
|
|
2010
2128
|
if (auth?.type !== "oauth" || !(auth.access || auth.source)) return provider.models
|
|
2129
|
+
let ms
|
|
2011
2130
|
try {
|
|
2012
2131
|
const a = await current(site, client, auth)
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2132
|
+
ms = await listed(a, true)
|
|
2133
|
+
} catch (e) {
|
|
2134
|
+
// with the switch on, a list without prices would offer models
|
|
2135
|
+
// that cost credits: the failure goes up, and magpie keeps the
|
|
2136
|
+
// list it had
|
|
2137
|
+
if (freeOnly()) throw e
|
|
2017
2138
|
return provider.models
|
|
2018
2139
|
}
|
|
2140
|
+
if (!ms.length && !freeOnly()) return provider.models
|
|
2141
|
+
return Object.fromEntries(onlyFree(ms).map((m) => [m.id, modelOf(site, provider, m)]))
|
|
2019
2142
|
},
|
|
2020
2143
|
},
|
|
2021
2144
|
auth: {
|
|
@@ -2027,9 +2150,16 @@ function makePlugin(site) {
|
|
|
2027
2150
|
// and is renewed as before.
|
|
2028
2151
|
refreshLead: LEAD_MS,
|
|
2029
2152
|
refresh: (auth) => refreshed(site, auth),
|
|
2153
|
+
options: [
|
|
2154
|
+
{
|
|
2155
|
+
key: FREE_ONLY,
|
|
2156
|
+
label: "Free models only",
|
|
2157
|
+
description: `Lists only the models ${site.name} serves at no cost, and turns away a request for any other here instead of sending it, so no credits are spent. A model free only at night counts as paid.`,
|
|
2158
|
+
},
|
|
2159
|
+
],
|
|
2030
2160
|
async loader(getAuth) {
|
|
2031
2161
|
const auth = await getAuth()
|
|
2032
|
-
if (auth?.type !== "oauth") return {}
|
|
2162
|
+
if (auth?.type !== "oauth" && auth?.type !== "api") return {}
|
|
2033
2163
|
return {
|
|
2034
2164
|
// no baseURL: a model's own api.url says where it is served —
|
|
2035
2165
|
// <endpoint>/v2 for a chat, <endpoint>/v1 for a Claude model on
|
|
@@ -2038,8 +2168,9 @@ function makePlugin(site) {
|
|
|
2038
2168
|
apiKey: "",
|
|
2039
2169
|
async fetch(input, init) {
|
|
2040
2170
|
const stored = await getAuth()
|
|
2041
|
-
|
|
2042
|
-
|
|
2171
|
+
const keyed = stored?.type === "api" ? keyAccount(stored) : null
|
|
2172
|
+
if (stored?.type !== "oauth" && !keyed) throw new Error(`${site.name} isn't signed in`)
|
|
2173
|
+
let a = keyed ?? (await current(site, client, stored))
|
|
2043
2174
|
const req = input instanceof Request ? input : null
|
|
2044
2175
|
const headers = new Headers(init?.headers ?? req?.headers)
|
|
2045
2176
|
headers.delete("authorization")
|
|
@@ -2049,6 +2180,18 @@ function makePlugin(site) {
|
|
|
2049
2180
|
sign(site, a, headers)
|
|
2050
2181
|
let body = init?.body
|
|
2051
2182
|
if (body === undefined && req) body = await req.clone().text()
|
|
2183
|
+
// the switch is checked before anything is sent: a model not
|
|
2184
|
+
// free, or one whose price can't be read, never reaches WorkBuddy
|
|
2185
|
+
if (freeOnly()) {
|
|
2186
|
+
const model = chatOf(typeof body === "string" ? body : bodyString(body))?.model
|
|
2187
|
+
let list
|
|
2188
|
+
try {
|
|
2189
|
+
list = await listed(a)
|
|
2190
|
+
} catch (e) {
|
|
2191
|
+
return notFree(site, model, e?.message ?? String(e))
|
|
2192
|
+
}
|
|
2193
|
+
if (!list.some((m) => m.id === model && m.free)) return notFree(site, model)
|
|
2194
|
+
}
|
|
2052
2195
|
// An Anthropic request goes as the agent sent it: WorkBuddy
|
|
2053
2196
|
// serves these models on Messages itself, and the rewrites
|
|
2054
2197
|
// below (a default system message, the chat endpoint's
|
|
@@ -2096,6 +2239,12 @@ function makePlugin(site) {
|
|
|
2096
2239
|
const res = await post(b)
|
|
2097
2240
|
if (res.status !== 401) return res
|
|
2098
2241
|
if (renewed) return out("it refused the token renewed for it too", invalidToken(res), res)
|
|
2242
|
+
// a key isn't renewed: the 401 says the key was refused
|
|
2243
|
+
if (a.source === "key") {
|
|
2244
|
+
const r = keyRefused(site, invalidToken(res), edgeNotes.get(res))
|
|
2245
|
+
ours.add(r)
|
|
2246
|
+
return r
|
|
2247
|
+
}
|
|
2099
2248
|
if (!resendable(b)) return res
|
|
2100
2249
|
await res.body?.cancel().catch(() => {})
|
|
2101
2250
|
const r = await reissued(site, client, getAuth, a, stored.access)
|
|
@@ -2160,6 +2309,9 @@ function makePlugin(site) {
|
|
|
2160
2309
|
// an account lapsed nor cleared it, but for a 401 (gone, below)
|
|
2161
2310
|
async usage(getAuth) {
|
|
2162
2311
|
const auth = await getAuth()
|
|
2312
|
+
// WorkBuddy's own CLI reads no credits with a key, and what the
|
|
2313
|
+
// billing API answers one is unknown, so a key's card says so
|
|
2314
|
+
if (auth?.type === "api") return { error: `credits unknown with an API key (WorkBuddy's own client reads none with one); see ${site.keys.replace(/\/profile\/keys$/, "")}`, signIn: "kept" }
|
|
2163
2315
|
if (auth?.type !== "oauth" || !(auth.access || auth.source)) return { error: "not signed in", signIn: "kept" }
|
|
2164
2316
|
try {
|
|
2165
2317
|
let a = await current(site, client, auth)
|
|
@@ -2225,9 +2377,17 @@ function makePlugin(site) {
|
|
|
2225
2377
|
label: `${site.name} desktop's sign-in`,
|
|
2226
2378
|
authorize: async () => desktopSignIn(site),
|
|
2227
2379
|
},
|
|
2380
|
+
{
|
|
2381
|
+
// a key made at site.keys, sent as WorkBuddy's CLI sends one
|
|
2382
|
+
// (keyAccount)
|
|
2383
|
+
type: "api",
|
|
2384
|
+
label: `${site.name} API key`,
|
|
2385
|
+
placeholder: `from ${site.keys.replace(/^https:\/\//, "")}`,
|
|
2386
|
+
},
|
|
2228
2387
|
],
|
|
2229
2388
|
},
|
|
2230
|
-
}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2231
2391
|
}
|
|
2232
2392
|
|
|
2233
2393
|
// REFUSED_HINT is what the user can do about WorkBuddy's "Illegal API
|
|
@@ -2332,4 +2492,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
|
2332
2492
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
2333
2493
|
|
|
2334
2494
|
// for tests
|
|
2335
|
-
export const _internal = { cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, 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, answeredBefore, nativeOf, modelOf, configModels, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
|
2495
|
+
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, 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, 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.38",
|
|
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",
|