@magpie-community/opencode-workbuddy-auth 0.1.20 → 0.1.21

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 (3) hide show
  1. package/README.md +7 -0
  2. package/index.mjs +51 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -134,6 +134,13 @@ is used.
134
134
 
135
135
  A model's reasoning levels are its variants (`reasoningEffort`).
136
136
 
137
+ A model's price is its `credits` ("x0.29") and the config's
138
+ `modelPromotions`. A discount for whole days (Step-5-Preview's 独家限免) is
139
+ the price now, with the price before it (`rateWas`). A price that holds only
140
+ some hours of the day (Hy4 preview, free 23:00–8:00) is given as its full
141
+ price, never as free: magpie keeps the list until it asks again, so a list
142
+ asked for at night would say "free" all day (#121).
143
+
137
144
  ## Credits in magpie
138
145
 
139
146
  magpie's usage card shows the account's credits from the resource summary.
package/index.mjs CHANGED
@@ -1187,6 +1187,8 @@ function modelOf(site, provider, m) {
1187
1187
  free: !!m.free,
1188
1188
  // magpie's own: the credits a request costs, as a multiple (0: none)
1189
1189
  rate: m.rate ?? 0,
1190
+ // magpie's own: the price before a discount running now (0: none)
1191
+ rateWas: m.rateWas ?? 0,
1190
1192
  }
1191
1193
  }
1192
1194
 
@@ -1210,6 +1212,53 @@ function freeCredits(c) {
1210
1212
  return creditsOf(c) === 0
1211
1213
  }
1212
1214
 
1215
+ // discountOf reads a promotion's price: its discountedCredits ("0.50x",
1216
+ // "0.00x"), else the factor times the model's own credits.
1217
+ function discountOf(p, base) {
1218
+ const said = creditsOf(String(p.discount?.discountedCredits ?? "").trim().replace(/x$/i, ""))
1219
+ if (said !== undefined) return said
1220
+ const f = Number(p.discount?.factor)
1221
+ return Number.isFinite(f) && f >= 0 && base !== undefined ? base * f : undefined
1222
+ }
1223
+
1224
+ // running says whether a promotion is on at now: enabled, and inside its
1225
+ // validFrom..validUntil. Its daily hours are not looked at here.
1226
+ function running(p, now) {
1227
+ if (!p || p.enabled === false) return false
1228
+ const from = Date.parse(p.schedule?.validFrom ?? "")
1229
+ const until = Date.parse(p.schedule?.validUntil ?? "")
1230
+ return !(from > now) && !(until <= now)
1231
+ }
1232
+
1233
+ // priceOf is a model's price as magpie keeps it, from its credits and the
1234
+ // config's modelPromotions (what WorkBuddy's picker shows as 限时免费,
1235
+ // 夜间免费, 夜间折扣). magpie keeps the list it is given until it asks
1236
+ // again, so a price that holds only some hours of the day (Hy4 preview,
1237
+ // free 23:00–8:00 only) is given as its full price, never as free: a list
1238
+ // asked for at night would otherwise say "free" all day (#121). A discount
1239
+ // for whole days (Step-5-Preview's 独家限免) is the price now, with the
1240
+ // price before it as rateWas.
1241
+ function priceOf(d, promotions, now = Date.now()) {
1242
+ const base = creditsOf(d.credits)
1243
+ const mine = (Array.isArray(promotions) ? promotions : []).filter(
1244
+ (p) => p?.kind === "discount" && Array.isArray(p.modelIds) && p.modelIds.includes(d.id) && running(p, now),
1245
+ )
1246
+ if (mine.some((p) => Array.isArray(p.schedule?.daily) && p.schedule.daily.length)) {
1247
+ // by the hour: the full price, which the credits are unless a night
1248
+ // discount already took them to its own price
1249
+ const night = mine.filter((p) => p.discount && Array.isArray(p.schedule?.daily) && p.schedule.daily.length)
1250
+ if (base === undefined || (base === 0 && night.some((p) => discountOf(p, base) === 0))) return { free: false }
1251
+ return { free: false, rate: base }
1252
+ }
1253
+ const off = mine.filter((p) => p.discount).map((p) => discountOf(p, base)).filter((r) => r !== undefined)
1254
+ if (off.length) {
1255
+ const r = Math.min(...off)
1256
+ return { free: r === 0, rate: r, ...(base !== undefined && base > r ? { rateWas: base } : {}) }
1257
+ }
1258
+ if (base === undefined) return {}
1259
+ return { free: base === 0, rate: base }
1260
+ }
1261
+
1213
1262
  async function liveModels(site, a) {
1214
1263
  const headers = new Headers()
1215
1264
  sign(site, a, headers)
@@ -1231,11 +1280,7 @@ async function liveModels(site, a) {
1231
1280
  m.context = d.maxInputTokens
1232
1281
  m.output = d.maxOutputTokens
1233
1282
  m.images = d.supportsImages === true && !textOnly(site, id)
1234
- const r = creditsOf(d.credits)
1235
- if (r !== undefined) {
1236
- m.free = r === 0
1237
- m.rate = r
1238
- }
1283
+ Object.assign(m, priceOf(d, cfg.modelPromotions))
1239
1284
  const es = d.reasoning?.supportedEfforts ?? []
1240
1285
  if (es.length) {
1241
1286
  const canOff = d.reasoning?.canDisableThinking
@@ -1513,4 +1558,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
1513
1558
  export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
1514
1559
 
1515
1560
  // for tests
1516
- export const _internal = { 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, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf }
1561
+ export const _internal = { 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 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-workbuddy-auth",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
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",