@magpie-community/opencode-workbuddy-auth 0.2.2 → 0.2.4
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 +38 -15
- package/index.mjs +219 -4
- package/package.json +16 -4
package/README.md
CHANGED
|
@@ -174,21 +174,33 @@ default one, as the app does.
|
|
|
174
174
|
|
|
175
175
|
WorkBuddy refuses some agents' identity lines as an "unapproved channel"
|
|
176
176
|
(11128), so those lines are reworded before a chat goes out. Since 0.1.27
|
|
177
|
-
(#279) that includes DeepSeek Harness's opening line.
|
|
178
|
-
not reworded yet is
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
177
|
+
(#279) that includes DeepSeek Harness's opening line. Since 0.2.3 a refusal
|
|
178
|
+
of words not reworded yet is answered first by saying the same line with one
|
|
179
|
+
more comma — a vendor matches such a line whole and exactly, so the comma
|
|
180
|
+
passes it while the line still names the harness (measured 2026-10-30; a word
|
|
181
|
+
added after the product name did not pass, the comma did). The comma is set in
|
|
182
|
+
the system and assistant messages only — the two WorkBuddy reads — so the
|
|
183
|
+
user's own words and tools' results go out as they were sent. A system prompt
|
|
184
|
+
whose comma passed is remembered while the plugin is loaded, as a moved one
|
|
185
|
+
is, and its next chats go with the comma already in before the first send:
|
|
186
|
+
otherwise every turn, and every step of a tool loop, would pay the refusal
|
|
187
|
+
once. Only a chat refused still is sent once more, since 0.1.29, with the
|
|
188
|
+
system prompt moved into the first user message (inside `<instructions>` tags)
|
|
189
|
+
and WorkBuddy's default system prompt in its place: WorkBuddy checks only the
|
|
190
|
+
system and assistant messages, and the line it matched is then in neither. A system message later
|
|
191
|
+
in the chat becomes a user message where it stands. The plugin remembers each
|
|
192
|
+
refused system prompt while it is loaded, so that agent's next chats go moved
|
|
193
|
+
at once. The move can't reach an assistant message, so words the model quotes
|
|
194
|
+
back into one keep that chat refused until they are in the list reworded in
|
|
195
|
+
every message (since 0.1.30, the "Web GUI whose URL the runtime context names"
|
|
196
|
+
line, #291); otherwise only a new chat clears it. A refusal that stands after
|
|
197
|
+
the move ends in a hint that names no one client (since 0.1.28): WorkBuddy
|
|
198
|
+
refused words in this client's prompt; use it from Hermes, OpenCode or Pi, or
|
|
199
|
+
add another provider to the group. Since 0.2.3 that hint is preceded by the
|
|
200
|
+
address of [REFUSED.md](REFUSED.md), which says what the check reads, how a
|
|
201
|
+
line is reworded to pass it, and how to turn such a line off in an agent that
|
|
202
|
+
has a switch for it — so the error carries its own fix, for the person who
|
|
203
|
+
reads it or the agent they paste it to. Neither refusal rests the account.
|
|
192
204
|
|
|
193
205
|
The loader also translates OpenAI-compatible request spellings WorkBuddy
|
|
194
206
|
doesn't take: `max_completion_tokens` becomes `max_tokens`, `developer`
|
|
@@ -227,6 +239,17 @@ serves; a model that refused it once gets it that way from then on, until
|
|
|
227
239
|
the plugin restarts. A chat ending with the assistant's message (a prefill)
|
|
228
240
|
is refused as before.
|
|
229
241
|
|
|
242
|
+
WorkBuddy's safety filter can refuse a reply it has begun:
|
|
243
|
+
`deepseek-v4.1-flash` reasoned, said "Sorry, I can't respond to this
|
|
244
|
+
question.", and ended with `finish_reason: "content_filter"` and no output
|
|
245
|
+
tokens, all under a 200 (#540). Since 0.2.4 that line is taken out of a
|
|
246
|
+
streamed chat ending `content_filter`, so the reply says nothing before the
|
|
247
|
+
filter's stop: magpie hands such a refusal to the group's next member
|
|
248
|
+
instead of passing it to the agent as an answer. Only text that is still
|
|
249
|
+
the filter's line is held, so any other reply's words go as they come; the
|
|
250
|
+
same words ending `stop`, or the filter cutting off a reply after other
|
|
251
|
+
words, go through as they came.
|
|
252
|
+
|
|
230
253
|
## Models
|
|
231
254
|
|
|
232
255
|
When you are signed in, the models are the ones WorkBuddy's product config
|
package/index.mjs
CHANGED
|
@@ -1008,6 +1008,79 @@ function systemAsUserOn(b) {
|
|
|
1008
1008
|
return true
|
|
1009
1009
|
}
|
|
1010
1010
|
|
|
1011
|
+
// OPENERS are the shapes in which an agent's opening says which harness it
|
|
1012
|
+
// runs in, as a vendor may have fingerprinted one. A vendor matches a refused
|
|
1013
|
+
// line whole and exactly — one extra space passes it, as FLAGGED's note above
|
|
1014
|
+
// has it — so the same line with one more comma passes while still saying
|
|
1015
|
+
// what it said. Measured 2026-10-30 against copilot.tencent.com, one account,
|
|
1016
|
+
// streamed, deepseek-v4.1-flash at max: DeepSeek Harness's opener answered
|
|
1017
|
+
// 400 code 11128 as written, and 200 with the comma, the harness's name still
|
|
1018
|
+
// in it; a suffix in its place (…Harness Desktop., …Harness CLI.) changed
|
|
1019
|
+
// nothing, so it is the line's shape the vendor knows, not the product alone.
|
|
1020
|
+
const OPENERS = [
|
|
1021
|
+
[/(\bYou are (?:an?|the)\s[^\n.,]{0,60}?\b(?:agent|assistant))\s+(powered by|running on|running in|built on|based on)\b/gi, "$1, $2"],
|
|
1022
|
+
]
|
|
1023
|
+
|
|
1024
|
+
function opened(text) {
|
|
1025
|
+
for (const [re, to] of OPENERS) text = text.replace(re, to)
|
|
1026
|
+
return text
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// commaPaused is body with OPENERS' comma set in its system and assistant
|
|
1030
|
+
// messages — the two WorkBuddy reads (REFUSED.md). The user's messages and
|
|
1031
|
+
// tools' results are not among them: a comma in a message the vendor never
|
|
1032
|
+
// matches changes what someone said without changing what was refused, and
|
|
1033
|
+
// the user's own words come back altered. It is tried before systemAsUser,
|
|
1034
|
+
// which takes the system prompt out of the slot an agent's instructions are
|
|
1035
|
+
// read in. null when there was nothing to set a comma in.
|
|
1036
|
+
//
|
|
1037
|
+
// The two roles are read off the message's own role: a message with no role,
|
|
1038
|
+
// or one of another kind, is left as it is. roles, when given, collects the
|
|
1039
|
+
// roles the comma went into — the caller uses it to tell a comma that made a
|
|
1040
|
+
// chat pass in its system prompt from one that only set an assistant
|
|
1041
|
+
// message's (commaSystems).
|
|
1042
|
+
const PAUSED_ROLES = new Set(["system", "assistant"])
|
|
1043
|
+
|
|
1044
|
+
function commaPaused(body, roles) {
|
|
1045
|
+
const b = chatOf(body)
|
|
1046
|
+
return commaPausedOn(b, roles) ? JSON.stringify(b) : null
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// commaPausedOn makes commaPaused's change on a chat's object, in place; false
|
|
1050
|
+
// when there was nothing to set a comma in. commaPaused is this on a body, and
|
|
1051
|
+
// the first send of a system prompt whose comma passed is this too
|
|
1052
|
+
// (commaSystems), so the two can never drift apart.
|
|
1053
|
+
function commaPausedOn(b, roles) {
|
|
1054
|
+
const msgs = b?.messages
|
|
1055
|
+
if (!Array.isArray(msgs)) return false
|
|
1056
|
+
let changed = false
|
|
1057
|
+
for (const m of msgs) {
|
|
1058
|
+
if (!PAUSED_ROLES.has(m?.role)) continue
|
|
1059
|
+
let mine = false
|
|
1060
|
+
if (typeof m.content === "string") {
|
|
1061
|
+
const t = opened(m.content)
|
|
1062
|
+
if (t !== m.content) {
|
|
1063
|
+
m.content = t
|
|
1064
|
+
mine = true
|
|
1065
|
+
}
|
|
1066
|
+
} else if (Array.isArray(m.content)) {
|
|
1067
|
+
for (const p of m.content) {
|
|
1068
|
+
if (typeof p?.text !== "string") continue
|
|
1069
|
+
const t = opened(p.text)
|
|
1070
|
+
if (t === p.text) continue
|
|
1071
|
+
p.text = t
|
|
1072
|
+
mine = true
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
// a message whose parts held no opening of their own is not changed, and
|
|
1076
|
+
// is not reported as one that was
|
|
1077
|
+
if (!mine) continue
|
|
1078
|
+
changed = true
|
|
1079
|
+
roles?.add(m.role)
|
|
1080
|
+
}
|
|
1081
|
+
return changed
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1011
1084
|
// normalizeToolChoice converts the object form emitted by OpenAI clients to
|
|
1012
1085
|
// WorkBuddy's string form. It runs after fitted(), so a named choice follows a
|
|
1013
1086
|
// tool name that was made safe for WorkBuddy.
|
|
@@ -1526,6 +1599,106 @@ function renamed(res, names) {
|
|
|
1526
1599
|
return new Response(body, { status: res.status, statusText: res.statusText, headers })
|
|
1527
1600
|
}
|
|
1528
1601
|
|
|
1602
|
+
// FILTER_SAYS is the text WorkBuddy's safety filter puts in a reply it ends
|
|
1603
|
+
// with finish_reason "content_filter": deepseek-v4.1-flash on
|
|
1604
|
+
// copilot.tencent.com reasoned, said this, and ended content_filter with
|
|
1605
|
+
// no output tokens counted (itspig, plugins #540).
|
|
1606
|
+
const FILTER_SAYS = ["Sorry, I can't respond to this question."]
|
|
1607
|
+
|
|
1608
|
+
// filterSaid tells whether text said so far may still be FILTER_SAYS.
|
|
1609
|
+
const filterSaid = (text) => {
|
|
1610
|
+
const t = text.replace(/’/g, "'").trimStart()
|
|
1611
|
+
return t !== "" && FILTER_SAYS.some((s) => s.startsWith(t))
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// unsaid is a streamed chat whose reply WorkBuddy's filter refused with its
|
|
1615
|
+
// text (FILTER_SAYS) and finish_reason content_filter, with the text taken
|
|
1616
|
+
// out: a reply that says nothing before content_filter is the refusal magpie
|
|
1617
|
+
// asks the group's next member for, where a 200 that said something is an
|
|
1618
|
+
// answer the agent fails on ("The model refused to complete the request",
|
|
1619
|
+
// plugins #540). Only text that is still the filter's is held, so any other
|
|
1620
|
+
// reply's first words go as they come, and one that only begins like it is
|
|
1621
|
+
// let through at its first word that isn't, or at its end.
|
|
1622
|
+
function unsaid(res) {
|
|
1623
|
+
if (!res.body || !/event-stream/i.test(res.headers.get("content-type") ?? "")) return res
|
|
1624
|
+
const headers = new Headers(res.headers)
|
|
1625
|
+
headers.delete("content-length")
|
|
1626
|
+
headers.delete("content-encoding")
|
|
1627
|
+
const dec = new TextDecoder()
|
|
1628
|
+
const enc = new TextEncoder()
|
|
1629
|
+
let rest = ""
|
|
1630
|
+
let open = true // the reply may still be the filter's
|
|
1631
|
+
let said = ""
|
|
1632
|
+
let held = [] // events held while it may be
|
|
1633
|
+
const chunkOf = (ev) => {
|
|
1634
|
+
const m = /^data:\s?(.*)$/m.exec(ev)
|
|
1635
|
+
if (!m || m[1] === "[DONE]") return null
|
|
1636
|
+
try {
|
|
1637
|
+
const v = JSON.parse(m[1])
|
|
1638
|
+
return v && typeof v === "object" ? v : null
|
|
1639
|
+
} catch {
|
|
1640
|
+
return null
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
// without is ev with the filter's text taken out, or "" when nothing
|
|
1644
|
+
// else is in it
|
|
1645
|
+
const without = (ev) => {
|
|
1646
|
+
const v = chunkOf(ev)
|
|
1647
|
+
const c = v?.choices?.[0]
|
|
1648
|
+
if (!c?.delta || typeof c.delta.content !== "string") return ev
|
|
1649
|
+
delete c.delta.content
|
|
1650
|
+
const left = Object.keys(c.delta).filter((k) => k !== "role")
|
|
1651
|
+
if (!left.length && c.finish_reason == null && v.usage == null) return ""
|
|
1652
|
+
return `data: ${JSON.stringify(v)}`
|
|
1653
|
+
}
|
|
1654
|
+
const event = (ev) => {
|
|
1655
|
+
if (!open) return [ev]
|
|
1656
|
+
const c = chunkOf(ev)?.choices?.[0]
|
|
1657
|
+
const text = typeof c?.delta?.content === "string" ? c.delta.content : ""
|
|
1658
|
+
const finish = c?.finish_reason
|
|
1659
|
+
if (c?.delta?.tool_calls || (text && !filterSaid(said + text))) {
|
|
1660
|
+
open = false
|
|
1661
|
+
const out = [...held, ev]
|
|
1662
|
+
held = []
|
|
1663
|
+
return out
|
|
1664
|
+
}
|
|
1665
|
+
said += text
|
|
1666
|
+
if (finish === "content_filter" && said) {
|
|
1667
|
+
open = false
|
|
1668
|
+
const out = [...held, ev].map(without).filter(Boolean)
|
|
1669
|
+
held = []
|
|
1670
|
+
return out
|
|
1671
|
+
}
|
|
1672
|
+
if (finish) {
|
|
1673
|
+
open = false
|
|
1674
|
+
const out = [...held, ev]
|
|
1675
|
+
held = []
|
|
1676
|
+
return out
|
|
1677
|
+
}
|
|
1678
|
+
if (!said) return [ev] // reasoning, the role, before any text
|
|
1679
|
+
held.push(ev)
|
|
1680
|
+
return []
|
|
1681
|
+
}
|
|
1682
|
+
const body = res.body.pipeThrough(
|
|
1683
|
+
new TransformStream({
|
|
1684
|
+
transform(chunk, ctl) {
|
|
1685
|
+
rest = (rest + dec.decode(chunk, { stream: true })).replace(/\r\n/g, "\n")
|
|
1686
|
+
const evs = rest.split("\n\n")
|
|
1687
|
+
rest = evs.pop()
|
|
1688
|
+
const out = evs.flatMap(event)
|
|
1689
|
+
if (out.length) ctl.enqueue(enc.encode(out.map((e) => e + "\n\n").join("")))
|
|
1690
|
+
},
|
|
1691
|
+
flush(ctl) {
|
|
1692
|
+
rest += dec.decode()
|
|
1693
|
+
const out = held.map((e) => e + "\n\n").join("") + rest
|
|
1694
|
+
held = []
|
|
1695
|
+
if (out) ctl.enqueue(enc.encode(out))
|
|
1696
|
+
},
|
|
1697
|
+
}),
|
|
1698
|
+
)
|
|
1699
|
+
return new Response(body, { status: res.status, statusText: res.statusText, headers })
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1529
1702
|
// ---- signing in -------------------------------------------------------------
|
|
1530
1703
|
|
|
1531
1704
|
// poll asks path until WorkBuddy answers with data, retrying the codes
|
|
@@ -3040,6 +3213,13 @@ function makePlugin(site) {
|
|
|
3040
3213
|
// the system prompts this run WorkBuddy refused as an unapproved channel:
|
|
3041
3214
|
// their next chats go with systemAsUser at once, not refused first
|
|
3042
3215
|
const refusedSystems = new Set()
|
|
3216
|
+
// the system prompts this run WorkBuddy refused as written and took with
|
|
3217
|
+
// OPENERS' comma: their next chats go with the comma set before the first
|
|
3218
|
+
// send, as a moved one goes moved. Without it every turn of that agent —
|
|
3219
|
+
// and every step of its tool loop — pays a refused round trip first, which
|
|
3220
|
+
// is latency on each request and a pattern of channel refusals on the
|
|
3221
|
+
// account. Bounded as refusedSystems is.
|
|
3222
|
+
const commaSystems = new Set()
|
|
3043
3223
|
return async ({ client, magpie }) => {
|
|
3044
3224
|
// each account's list as last read, for FREE_ONLY: {at, list}
|
|
3045
3225
|
const lists = new Map()
|
|
@@ -3290,6 +3470,10 @@ function makePlugin(site) {
|
|
|
3290
3470
|
// words at once (see systemAsUser)
|
|
3291
3471
|
const sysKey = native ? "" : systemKeyOf(chat)
|
|
3292
3472
|
if (sysKey && refusedSystems.has(sysKey) && systemAsUserOn(chat)) changed = true
|
|
3473
|
+
// a system prompt whose comma passed once goes with the comma
|
|
3474
|
+
// set before the first send (see commaSystems), the way one
|
|
3475
|
+
// refused before goes moved above
|
|
3476
|
+
if (sysKey && commaSystems.has(sysKey) && commaPausedOn(chat)) changed = true
|
|
3293
3477
|
// shaped is a body as such a model takes it. The first try's
|
|
3294
3478
|
// is made on the chat already parsed, after the move above,
|
|
3295
3479
|
// as shaped would make it of the body written; a resend with
|
|
@@ -3317,7 +3501,27 @@ function makePlugin(site) {
|
|
|
3317
3501
|
else res = new Response(text, { status: res.status, statusText: res.statusText, headers: res.headers })
|
|
3318
3502
|
}
|
|
3319
3503
|
if (res.status === 400 && !native) { let text = await res.text()
|
|
3320
|
-
|
|
3504
|
+
// the vendor may know a shape of the agent's opening that FLAGGED
|
|
3505
|
+
// doesn't: the same words said with one more comma pass it, and
|
|
3506
|
+
// that is tried before the system prompt is moved out of its slot.
|
|
3507
|
+
// The roles the comma went into are kept: one set in the system
|
|
3508
|
+
// prompt is what its next chats go with, one set in an assistant
|
|
3509
|
+
// message alone says nothing about the next chat's.
|
|
3510
|
+
const roles = new Set()
|
|
3511
|
+
const paused = REFUSED.test(text) ? commaPaused(body, roles) : null
|
|
3512
|
+
if (paused) {
|
|
3513
|
+
body = paused
|
|
3514
|
+
res = await send(shaped(body))
|
|
3515
|
+
if (res.status === 400) text = await res.text()
|
|
3516
|
+
// not refused this time: the comma is what passed the
|
|
3517
|
+
// vendor's check, so this system prompt's next chats go
|
|
3518
|
+
// with it set before the first send
|
|
3519
|
+
else if (sysKey && roles.has("system")) {
|
|
3520
|
+
commaSystems.add(sysKey)
|
|
3521
|
+
if (commaSystems.size > 256) commaSystems.delete(commaSystems.values().next().value)
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
const moved = res.status === 400 && REFUSED.test(text) && sysKey && !refusedSystems.has(sysKey) ? systemAsUser(body) : null
|
|
3321
3525
|
if (moved) {
|
|
3322
3526
|
refusedSystems.add(sysKey)
|
|
3323
3527
|
if (refusedSystems.size > 256) refusedSystems.delete(refusedSystems.values().next().value)
|
|
@@ -3335,7 +3539,7 @@ function makePlugin(site) {
|
|
|
3335
3539
|
}
|
|
3336
3540
|
if (ours.has(res)) return res
|
|
3337
3541
|
// renewed here: a mark the account had comes off
|
|
3338
|
-
return res.status >= 400 ? explained(res) : kept(native ? res : await renamed(res, names), renewed ? "renewed" : "kept")
|
|
3542
|
+
return res.status >= 400 ? explained(res) : kept(native ? res : unsaid(await renamed(res, names)), renewed ? "renewed" : "kept")
|
|
3339
3543
|
},
|
|
3340
3544
|
}
|
|
3341
3545
|
},
|
|
@@ -3446,6 +3650,13 @@ function makePlugin(site) {
|
|
|
3446
3650
|
// apart from WorkBuddy's own words.
|
|
3447
3651
|
const REFUSED_HINT =
|
|
3448
3652
|
"WorkBuddy refused words in this client's prompt (most often its system prompt); use it from Hermes, OpenCode or Pi, or add another provider to this group"
|
|
3653
|
+
|
|
3654
|
+
// REFUSED_DOC is where a refusal's fix is written down, for whoever holds the
|
|
3655
|
+
// error next: the person reading it, or the agent they paste it to. It goes
|
|
3656
|
+
// before the hint, never after, because magpie's Routing page tells the hint
|
|
3657
|
+
// from WorkBuddy's own words by the error ending in it.
|
|
3658
|
+
const REFUSED_DOC = "https://github.com/magpie-community/plugins/blob/main/packages/workbuddy/REFUSED.md"
|
|
3659
|
+
|
|
3449
3660
|
const REFUSED = /unapproved channel|illegal api invocation/i
|
|
3450
3661
|
|
|
3451
3662
|
// BAD_SIGNATURE is WorkBuddy's refusal of a thinking block whose signature it
|
|
@@ -3524,7 +3735,11 @@ async function explained(res) {
|
|
|
3524
3735
|
const hint = isRefused ? REFUSED_HINT : isRestricted ? RESTRICTED_HINT : EXHAUSTED_HINT
|
|
3525
3736
|
const type = isRefused || isRestricted ? "permission_error" : "insufficient_quota"
|
|
3526
3737
|
const errCode = isRefused ? null : isRestricted ? RESTRICTED_CODE : 14018
|
|
3527
|
-
|
|
3738
|
+
// a refusal says where its fix is written down, so whoever holds the error
|
|
3739
|
+
// — the person, or the agent they paste it to — can go and read it. It goes
|
|
3740
|
+
// before the hint, never after: the hint is the message's end.
|
|
3741
|
+
const where = isRefused ? `${REFUSED_DOC} — ` : ""
|
|
3742
|
+
msg = `${msg} — ${where}${hint}`
|
|
3528
3743
|
const headers = new Headers(res.headers)
|
|
3529
3744
|
headers.set("content-type", "application/json")
|
|
3530
3745
|
headers.delete("content-length")
|
|
@@ -3537,4 +3752,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
|
|
|
3537
3752
|
export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
|
|
3538
3753
|
|
|
3539
3754
|
// for tests
|
|
3540
|
-
export const _internal = { idFor, replyAfterToolsOn, withDefaultEffort, defaultEffortOf, gzipped, FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, accountName, 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, scopeOf, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, freeWindowOf, tokensShort, freeWindowRows, freeWindowLedger, readLedgerTail, pinned, rowTime, rowAccount, ofAccount, windowOffset, windowReset, FREE_WINDOW_MODELS, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
|
3755
|
+
export const _internal = { idFor, replyAfterToolsOn, withDefaultEffort, defaultEffortOf, gzipped, FREE_ONLY, PRICE_TTL, keyAccount, remoteConfig, cycleOf, typeUnions, systemAsUser, systemKey, DEFAULT_SYSTEM, EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, accountName, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, asReasoning, normalizeToolChoice, fitTools, fitted, renamed, unsaid, FILTER_SAYS, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, REFUSED_DOC, commaPaused, commaPausedOn, opened, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, scopeOf, turnKey, conversationKey, signatureOf, isMessages, withoutUnsigned, withoutSignedThinking, prepared, answeredBefore, nativeOf, modelOf, configModels, freeWindowOf, tokensShort, freeWindowRows, freeWindowLedger, readLedgerTail, pinned, rowTime, rowAccount, ofAccount, windowOffset, windowReset, FREE_WINDOW_MODELS, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
|
package/package.json
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-workbuddy-auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
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",
|
|
7
7
|
"exports": "./index.mjs",
|
|
8
|
-
"files": [
|
|
9
|
-
|
|
8
|
+
"files": [
|
|
9
|
+
"index.mjs",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"opencode",
|
|
14
|
+
"opencode-plugin",
|
|
15
|
+
"workbuddy",
|
|
16
|
+
"codebuddy"
|
|
17
|
+
],
|
|
10
18
|
"license": "MIT",
|
|
11
|
-
"repository": {
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/magpie-community/plugins.git",
|
|
22
|
+
"directory": "packages/workbuddy"
|
|
23
|
+
}
|
|
12
24
|
}
|