@magpie-community/opencode-workbuddy-auth 0.1.8 → 0.1.10
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/index.mjs +89 -12
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -257,17 +257,75 @@ function sign(site, a, headers) {
|
|
|
257
257
|
headers.set("X-Request-ID", msg)
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
// FLAGGED are the words WorkBuddy refuses a chat for, "Illegal API
|
|
261
|
+
// invocation from an unapproved channel" (magpie #182), each with words
|
|
262
|
+
// that say the same and pass: tried one by one against both builds with
|
|
263
|
+
// the requests Claude Code 2.1.280 and Codex 0.159.2 send. WorkBuddy reads
|
|
264
|
+
// every message, not only the system prompt (Claude Code puts its main
|
|
265
|
+
// branch in the first user message), and pays no mind to case. Claude
|
|
266
|
+
// Code's billing header means nothing to WorkBuddy's models and goes.
|
|
267
|
+
const FLAGGED = [
|
|
268
|
+
[/x-anthropic-billing-header:[^\n]*\n?/gi, ""],
|
|
269
|
+
[/You are Claude Code, Anthropic['’]s official CLI for Claude/gi, "You are Claude Code, Anthropic's CLI for Claude"],
|
|
270
|
+
[/Main branch \(you will usually use this for PRs\)/gi, "Main branch (usually the base for PRs)"],
|
|
271
|
+
[/(?<!the )Codex CLI is an open source project led by OpenAI\./gi, "The Codex CLI is an open source project led by OpenAI."],
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
function unflagged(text) {
|
|
275
|
+
for (const [re, to] of FLAGGED) text = text.replace(re, to)
|
|
276
|
+
return text
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// unflag puts FLAGGED's words in place in every message of a chat, and
|
|
280
|
+
// leaves out a text that had nothing else (the billing header's system
|
|
281
|
+
// block). It says whether it changed anything.
|
|
282
|
+
function unflag(messages) {
|
|
283
|
+
let changed = false
|
|
284
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
285
|
+
const m = messages[i]
|
|
286
|
+
if (typeof m?.content === "string") {
|
|
287
|
+
const t = unflagged(m.content)
|
|
288
|
+
if (t === m.content) continue
|
|
289
|
+
changed = true
|
|
290
|
+
if (t.trim() || m.role !== "system") m.content = t
|
|
291
|
+
else messages.splice(i, 1)
|
|
292
|
+
} else if (Array.isArray(m?.content)) {
|
|
293
|
+
const parts = []
|
|
294
|
+
let here = false
|
|
295
|
+
for (const p of m.content) {
|
|
296
|
+
const t = typeof p?.text === "string" ? unflagged(p.text) : null
|
|
297
|
+
if (t === null || t === p.text) {
|
|
298
|
+
parts.push(p)
|
|
299
|
+
continue
|
|
300
|
+
}
|
|
301
|
+
here = true
|
|
302
|
+
if (t.trim()) parts.push({ ...p, text: t })
|
|
303
|
+
}
|
|
304
|
+
if (!here) continue
|
|
305
|
+
changed = true
|
|
306
|
+
if (parts.length || m.role !== "system") m.content = parts
|
|
307
|
+
else messages.splice(i, 1)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return changed
|
|
311
|
+
}
|
|
312
|
+
|
|
260
313
|
// withSystem gives a chat that doesn't open with a system message
|
|
261
|
-
// WorkBuddy's default one, as its app does
|
|
314
|
+
// WorkBuddy's default one, as its app does, and takes FLAGGED's words out
|
|
315
|
+
// of it.
|
|
262
316
|
function withSystem(body) {
|
|
263
317
|
// a body magpie or OpenCode hands over as bytes is read as the text it is
|
|
264
318
|
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) body = new TextDecoder().decode(body)
|
|
265
319
|
if (typeof body !== "string") return body
|
|
266
320
|
try {
|
|
267
321
|
const b = JSON.parse(body)
|
|
268
|
-
if (!Array.isArray(b?.messages) || !b.messages.length
|
|
269
|
-
|
|
270
|
-
|
|
322
|
+
if (!Array.isArray(b?.messages) || !b.messages.length) return body
|
|
323
|
+
let changed = unflag(b.messages)
|
|
324
|
+
if (b.messages[0]?.role !== "system") {
|
|
325
|
+
b.messages.unshift({ role: "system", content: "You are a helpful assistant." })
|
|
326
|
+
changed = true
|
|
327
|
+
}
|
|
328
|
+
return changed ? JSON.stringify(b) : body
|
|
271
329
|
} catch {
|
|
272
330
|
return body
|
|
273
331
|
}
|
|
@@ -696,13 +754,22 @@ function makePlugin(site) {
|
|
|
696
754
|
|
|
697
755
|
// REFUSED_HINT is what the user can do about WorkBuddy's "Illegal API
|
|
698
756
|
// invocation from an unapproved channel": both builds answer it to a chat
|
|
699
|
-
//
|
|
700
|
-
//
|
|
757
|
+
// holding words of Codex's or Claude Code's own (magpie #182), whatever the
|
|
758
|
+
// headers. FLAGGED rewrites the ones known; this is for one it doesn't know. It ends the error's message, as magpie's built-in
|
|
701
759
|
// put it (provider.WBRefusedHint), so magpie's routing page says it apart.
|
|
702
760
|
const REFUSED_HINT =
|
|
703
761
|
"WorkBuddy refuses chats from Codex and Claude Code (their system prompt); use it from Hermes, OpenCode or Pi, or add another provider to this group"
|
|
704
762
|
const REFUSED = /unapproved channel|illegal api invocation/i
|
|
705
763
|
|
|
764
|
+
// EXHAUSTED_HINT explains WorkBuddy's requirement of an active package
|
|
765
|
+
// even for 0-rate / free models. When an account has no packages or 0 credits,
|
|
766
|
+
// WorkBuddy returns code 14018 ("Credits exhausted...").
|
|
767
|
+
const EXHAUSTED_HINT =
|
|
768
|
+
"WorkBuddy requires an active credit package even for 0-rate free models; check your account package balance"
|
|
769
|
+
// The code is matched whole: a code that only begins with 14018 (140185) is
|
|
770
|
+
// another error, and insufficient_quota would rest the account as out of credit.
|
|
771
|
+
const EXHAUSTED_TEXT = /credits exhausted|额度已用尽|["']code["']\s*:\s*["']?14018(?![\d.])/i
|
|
772
|
+
|
|
706
773
|
// kept is an answer that went through, saying the sign-in is kept: the
|
|
707
774
|
// built-in never cleared a WorkBuddy account's mark, as it never set one.
|
|
708
775
|
function kept(res) {
|
|
@@ -711,7 +778,7 @@ function kept(res) {
|
|
|
711
778
|
return new Response(res.body, { status: res.status, statusText: res.statusText, headers })
|
|
712
779
|
}
|
|
713
780
|
|
|
714
|
-
// explained is res with REFUSED_HINT added to that refusal's message.
|
|
781
|
+
// explained is res with REFUSED_HINT or EXHAUSTED_HINT added to that refusal's message.
|
|
715
782
|
// Each refusal says the sign-in is kept: the built-in passed WorkBuddy's
|
|
716
783
|
// 401 on and never marked a WorkBuddy account lapsed.
|
|
717
784
|
async function explained(res) {
|
|
@@ -723,27 +790,37 @@ async function explained(res) {
|
|
|
723
790
|
headers.set("X-Magpie-Sign-In", "kept")
|
|
724
791
|
return new Response(b, { status: res.status, statusText: res.statusText, headers })
|
|
725
792
|
}
|
|
726
|
-
if (!REFUSED.test(text)) return again(text)
|
|
727
|
-
let msg = text.trim()
|
|
728
793
|
let v
|
|
729
794
|
try {
|
|
730
795
|
v = JSON.parse(text)
|
|
731
796
|
} catch {}
|
|
732
797
|
const at = v?.error && typeof v.error === "object" ? v.error : v && typeof v === "object" ? v : null
|
|
798
|
+
const code = at?.data?.code ?? at?.code ?? v?.code ?? v?.data?.code
|
|
799
|
+
const isRefused = REFUSED.test(text)
|
|
800
|
+
const isExhausted = code === 14018 || Number(code) === 14018 || EXHAUSTED_TEXT.test(text)
|
|
801
|
+
if (!isRefused && !isExhausted) return again(text)
|
|
802
|
+
|
|
803
|
+
let msg = text.trim()
|
|
733
804
|
if (at && typeof at.message === "string") msg = at.message
|
|
805
|
+
else if (typeof at?.data?.msg === "string") msg = at.data.msg
|
|
734
806
|
else if (typeof v?.error === "string") msg = v.error
|
|
735
807
|
else if (typeof v?.msg === "string" && v.msg) msg = v.msg // WorkBuddy's own {"code", "msg"}
|
|
736
|
-
msg
|
|
808
|
+
else if (typeof v?.data?.msg === "string") msg = v.data.msg
|
|
809
|
+
|
|
810
|
+
const hint = isRefused ? REFUSED_HINT : EXHAUSTED_HINT
|
|
811
|
+
const type = isRefused ? "permission_error" : "insufficient_quota"
|
|
812
|
+
const errCode = isRefused ? null : 14018
|
|
813
|
+
msg = `${msg} — ${hint}`
|
|
737
814
|
const headers = new Headers(res.headers)
|
|
738
815
|
headers.set("content-type", "application/json")
|
|
739
816
|
headers.delete("content-length")
|
|
740
817
|
headers.delete("content-encoding")
|
|
741
818
|
headers.set("X-Magpie-Sign-In", "kept")
|
|
742
|
-
return new Response(JSON.stringify({ error: { message: msg, type
|
|
819
|
+
return new Response(JSON.stringify({ error: { message: msg, type, code: errCode } }), { status: res.status, statusText: res.statusText, headers })
|
|
743
820
|
}
|
|
744
821
|
|
|
745
822
|
export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
746
823
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
747
824
|
|
|
748
825
|
// for tests
|
|
749
|
-
export const _internal = { withSystem, usageOf, desktopHeld, explained, REFUSED_HINT, freeCredits, creditsOf, fresh, SITES, renewing, renewed }
|
|
826
|
+
export const _internal = { withSystem, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, fresh, SITES, renewing, renewed }
|
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.10",
|
|
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",
|