@magpie-community/opencode-workbuddy-auth 0.2.12 → 0.2.13

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.
Files changed (2) hide show
  1. package/index.mjs +48 -4
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -2674,7 +2674,7 @@ function readLedgerTail(path, st, now, chunks, account, win = FREE_WINDOW_AI) {
2674
2674
  let carry = ""
2675
2675
  let firstPass = true
2676
2676
  let stop = false
2677
- let chain = [] // this account's own rows read, latest first
2677
+ const edge = pinning() // where this account's own rows read so far say the chain is read from
2678
2678
  let reach = 0 // the row below which nothing is kept: 0 until an edge is found
2679
2679
  let answered = false // whether an answered free-model row of it is read
2680
2680
 
@@ -2717,9 +2717,8 @@ function readLedgerTail(path, st, now, chunks, account, win = FREE_WINDOW_AI) {
2717
2717
  }
2718
2718
  if (!ofAccount(row, account, win)) continue
2719
2719
  rev.push(row)
2720
- chain.push(row)
2721
2720
  if (Number(row.status) === 200) answered = true
2722
- if (!reach && Number(row.status) !== 429) reach = pinned(chain, account)
2721
+ if (!reach) reach = edge(row)
2723
2722
  }
2724
2723
  firstPass = false
2725
2724
  }
@@ -2787,6 +2786,51 @@ function pinned(rows, account) {
2787
2786
  return 0
2788
2787
  }
2789
2788
 
2789
+ // pinning is pinned read a row at a time: it is handed the account's own
2790
+ // rows latest first, as readLedgerTail reads them, and answers each with what
2791
+ // pinned would answer for every row handed so far — in constant time.
2792
+ //
2793
+ // readLedgerTail used to call pinned on its whole chain after each row, and
2794
+ // pinned walks the chain, so a chain with no edge in it cost the square of
2795
+ // its rows: 10.5 s for 16,000 rows on mote, a minute and more for an account
2796
+ // a server spends on all day (a call a minute is 43,000 rows in a month).
2797
+ // That ran on the plugin host's one thread at every usage read, and the
2798
+ // ledger changes with every call, so nothing held it over: the host sat at
2799
+ // 99% CPU and every session through it stalled (xmoon76 on Discord, the
2800
+ // China build's window being read since 0.2.12).
2801
+ //
2802
+ // It holds because the rows only ever grow at their oldest end, and pinned
2803
+ // was asked only while it answered 0 — no readable refusal and no day's gap
2804
+ // among the rows so far — so the one new thing a row can bring is:
2805
+ //
2806
+ // - a refusal with a readable reset: the newest such is the first read,
2807
+ // and pinned answers it whatever else the rows hold, once a row that is
2808
+ // not a refusal follows (readLedgerTail asked pinned for those alone);
2809
+ // - a day's gap between it and the oldest answered row before it, the only
2810
+ // pair of answered rows not already looked at. pinned answers that with
2811
+ // the older row of the pair, this one.
2812
+ function pinning() {
2813
+ let denied = null // the newest readable refusal's reset
2814
+ let oldest = null // the oldest answered row's time so far
2815
+ return (row) => {
2816
+ const status = Number(row?.status)
2817
+ if (status === 429) {
2818
+ if (denied === null) {
2819
+ const reset = windowReset(row.err)
2820
+ if (Number.isFinite(reset)) denied = reset
2821
+ }
2822
+ return 0
2823
+ }
2824
+ if (denied !== null) return denied - FREE_WINDOW_LEAD
2825
+ if (status !== 200) return 0
2826
+ const t = Date.parse(row?.t)
2827
+ if (!Number.isFinite(t)) return 0
2828
+ if (oldest !== null && oldest - t >= FREE_WINDOW_GAP) return t - FREE_WINDOW_LEAD
2829
+ oldest = t
2830
+ return 0
2831
+ }
2832
+ }
2833
+
2790
2834
  // _internal is where these are handed to a test: magpie's host calls every
2791
2835
  // exported function of a plugin as one of its own factories (host.js,
2792
2836
  // servers()), so freeWindowRows et al. must not be exports of the plugin.
@@ -3896,4 +3940,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
3896
3940
  export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
3897
3941
 
3898
3942
  // for tests
3899
- export const _internal = { planCodes, idFor, OFF_TAKEN, 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_CN, FREE_WINDOW_AI, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, API_MESSAGES: NPM_MESSAGES, API_CHAT: NPM }
3943
+ export const _internal = { planCodes, idFor, OFF_TAKEN, 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, pinning, rowTime, rowAccount, ofAccount, windowOffset, windowReset, FREE_WINDOW_MODELS, FREE_WINDOW_CN, FREE_WINDOW_AI, FREE_WINDOW_SPAN, FREE_WINDOW_GAP, FREE_WINDOW_LEAD, checkinOf, 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.2.12",
3
+ "version": "0.2.13",
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",