dsh-all-usage 1.1.3 → 1.1.5
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/CHANGELOG.md +58 -2
- package/README.md +31 -44
- package/assets/model-icons/LICENSE.upstream-lobe-icons.txt +51 -0
- package/assets/model-icons/claude-color.svg +1 -0
- package/assets/model-icons/deepseek-color.svg +1 -0
- package/assets/model-icons/doubao-color.svg +1 -0
- package/assets/model-icons/gemini-color.svg +1 -0
- package/assets/model-icons/grok.svg +1 -0
- package/assets/model-icons/kimi-color.svg +1 -0
- package/assets/model-icons/manifest.json +213 -0
- package/assets/model-icons/meta-color.svg +1 -0
- package/assets/model-icons/minimax-color.svg +1 -0
- package/assets/model-icons/openai-color.svg +1 -0
- package/assets/model-icons/qwen-color.svg +1 -0
- package/assets/model-icons/zhipu-color.svg +1 -0
- package/assets/screenshot-1.png +0 -0
- package/assets/screenshot-2.png +0 -0
- package/assets/screenshot-3.png +0 -0
- package/lib/aggregation.js +58 -10
- package/lib/client.js +1 -1
- package/lib/http.js +1 -1
- package/lib/ledger.js +34 -5
- package/lib/plugin.js +4 -0
- package/lib/pricing-runtime.js +135 -11
- package/lib/pricing.js +335 -6
- package/lib/session-sync.js +329 -121
- package/lib/usage-core.js +51 -0
- package/package.json +1 -1
package/lib/aggregation.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
|
-
import { COST_SCHEMA_VERSION, addCostAccumulator, addCostAggregate, calculateCost, createCostAccumulator, decimalSubtract, isCostAccumulator, normalizeCostSnapshot, resolvePricing, serializeCostAggregate } from './pricing.js'
|
|
2
|
+
import { COST_SCHEMA_VERSION, addCostAccumulator, addCostAggregate, calculateCost, createCostAccumulator, decimalSubtract, isCostAccumulator, normalizeCostSnapshot, resolvePricing, serializeCostAggregate, temporalPlanFor } from './pricing.js'
|
|
3
3
|
import { extractUsageEvent, normalizeEventSeq, normalizeUsageValues as usageValues, upsertUsageSample as upsertUsageSampleState, usageStepKey, validEventTime as validUsageEventTime } from './usage-core.js'
|
|
4
4
|
|
|
5
5
|
export function createAggregation(host) {
|
|
@@ -75,14 +75,23 @@ export function createAggregation(host) {
|
|
|
75
75
|
while (state.pricingResolutionCache.size > 5000) state.pricingResolutionCache.delete(state.pricingResolutionCache.keys().next().value)
|
|
76
76
|
return resolved
|
|
77
77
|
}
|
|
78
|
-
function costForUsage(values, identity, previous) {
|
|
78
|
+
function costForUsage(values, identity, previous, pricingAt, pricingTimeSource) {
|
|
79
79
|
const previousCost = normalizeCostSnapshot(previous && previous.cost)
|
|
80
|
-
if (previousCost !== null && previousCost.pricingMode === 'official-model' && usageBasisEqual(previous, identity, values)) return previousCost
|
|
81
|
-
return calculateCost(values, resolveCurrentPricing(identity))
|
|
80
|
+
if (previousCost !== null && previousCost.pricingMode === 'official-model' && previousCost.pricingTimeSource !== 'legacy-unknown' && usageBasisEqual(previous, identity, values) && costTemporalCompatible(previousCost, identity, pricingAt, pricingTimeSource)) return previousCost
|
|
81
|
+
return calculateCost(values, resolveCurrentPricing(identity), pricingAt, pricingTimeSource)
|
|
82
|
+
}
|
|
83
|
+
function costTemporalCompatible(previousCost, identity, pricingAt, pricingTimeSource) {
|
|
84
|
+
if (previousCost.pricingAt === null || previousCost.pricingTimeSource === null) return false
|
|
85
|
+
const resolved = resolveCurrentPricing(identity)
|
|
86
|
+
const plan = temporalPlanFor(resolved, pricingAt)
|
|
87
|
+
const normalizedAt = Number.isFinite(pricingAt) && pricingAt >= 0 ? Math.trunc(pricingAt) : null
|
|
88
|
+
const normalizedSource = pricingTimeSource === 'request-context' || pricingTimeSource === 'usage-event' ? pricingTimeSource : 'usage-event'
|
|
89
|
+
return previousCost.pricingBand === plan.band && previousCost.pricingPolicyId === plan.policyId && previousCost.pricingPolicyHash === plan.policyHash && previousCost.pricingTimezone === plan.timezone && previousCost.temporalApplicable === (plan.status === 'applied') && previousCost.temporalExemptReason === plan.exemptReason && previousCost.pricingAt === normalizedAt && previousCost.pricingTimeSource === normalizedSource
|
|
82
90
|
}
|
|
83
91
|
function resetAggregationState() {
|
|
84
92
|
state.aggregationGeneration += 1
|
|
85
93
|
state.wsMeta.clear()
|
|
94
|
+
if (state.sessionContextTimes) state.sessionContextTimes.clear()
|
|
86
95
|
state.pathIndex.clear()
|
|
87
96
|
state.memberOf.clear()
|
|
88
97
|
state.byDay.clear()
|
|
@@ -343,10 +352,35 @@ export function createAggregation(host) {
|
|
|
343
352
|
adjustDay(state.byDay, dates.local, wsId, values, normalized, direction, sid, cost)
|
|
344
353
|
adjustDay(state.byDayUtc, dates.utc, wsId, values, normalized, direction, sid, cost)
|
|
345
354
|
}
|
|
355
|
+
function removeSession(sid) {
|
|
356
|
+
if (typeof sid !== 'string' || sid === '') return 0
|
|
357
|
+
let removed = 0
|
|
358
|
+
const usageKeys = []
|
|
359
|
+
for (const [key, item] of state.usageByStep) if (item.sid === sid) usageKeys.push([key, item])
|
|
360
|
+
for (const [key, item] of usageKeys) {
|
|
361
|
+
unindexUsage(item)
|
|
362
|
+
adjustUsage(item.wsId, item.time, item.values, item.identity || item.modelId, -1, sid, { local: item.date, utc: item.dateUtc }, item.cost)
|
|
363
|
+
adjustQueryUsage(state.byDay.get(item.date), item, -1, false)
|
|
364
|
+
adjustQueryUsage(state.byDayUtc.get(item.dateUtc), item, -1, true)
|
|
365
|
+
state.usageByStep.delete(key)
|
|
366
|
+
removed += 1
|
|
367
|
+
}
|
|
368
|
+
const turnKeys = []
|
|
369
|
+
for (const [key, turn] of state.turnRecords) if (turn.sid === sid) turnKeys.push([key, turn])
|
|
370
|
+
for (const [key, turn] of turnKeys) {
|
|
371
|
+
removeTurnRecord(turn)
|
|
372
|
+
state.turnRecords.delete(key)
|
|
373
|
+
removed += 1
|
|
374
|
+
}
|
|
375
|
+
state.sessionContextTimes.delete(sid)
|
|
376
|
+
state.sessionModel.delete(sid)
|
|
377
|
+
if (removed > 0) markStatsChanged('data')
|
|
378
|
+
return removed
|
|
379
|
+
}
|
|
346
380
|
function upsertUsageSample(target, sample, options = {}) {
|
|
347
381
|
const previous = target.get(sample.key)
|
|
348
382
|
const candidate = sample.cost === undefined
|
|
349
|
-
? { ...sample, cost: costForUsage(sample.values, sample.identity, options.costPrevious === undefined ? previous : options.costPrevious) }
|
|
383
|
+
? { ...sample, cost: costForUsage(sample.values, sample.identity, options.costPrevious === undefined ? previous : options.costPrevious, sample.pricingAt, sample.pricingTimeSource) }
|
|
350
384
|
: sample
|
|
351
385
|
const result = upsertUsageSampleState(target, candidate)
|
|
352
386
|
if (!result.accepted || target !== state.usageByStep || options.materialize === false) return result
|
|
@@ -383,7 +417,7 @@ export function createAggregation(host) {
|
|
|
383
417
|
update(state.byDay.get(dates.local), false)
|
|
384
418
|
update(state.byDayUtc.get(dates.utc), true)
|
|
385
419
|
}
|
|
386
|
-
function addUsage(wsId, time, usage, model, sid, data, seq, materialization = 'live') {
|
|
420
|
+
function addUsage(wsId, time, usage, model, sid, data, seq, materialization = 'live', pricingAt, pricingTimeSource) {
|
|
387
421
|
if (!validEventTime(time)) return
|
|
388
422
|
const values = usageValues(usage)
|
|
389
423
|
if (values === null || noValues(values)) return
|
|
@@ -405,13 +439,26 @@ export function createAggregation(host) {
|
|
|
405
439
|
step: data && Number.isSafeInteger(data.step) && data.step >= 0 ? data.step : null,
|
|
406
440
|
materialization,
|
|
407
441
|
sid,
|
|
442
|
+
...(pricingAt === undefined ? {} : { pricingAt }),
|
|
443
|
+
...(pricingTimeSource === undefined ? {} : { pricingTimeSource }),
|
|
408
444
|
})
|
|
409
445
|
}
|
|
410
|
-
function addDayTurn(dayMap, date, wsId, sid) {
|
|
446
|
+
function addDayTurn(dayMap, date, wsId, sid, direction = 1) {
|
|
411
447
|
const day = ensureDay(dayMap, date)
|
|
412
|
-
adjustDaySession(day, sid,
|
|
413
|
-
day.turns
|
|
414
|
-
|
|
448
|
+
adjustDaySession(day, sid, direction)
|
|
449
|
+
day.turns = Math.max(0, day.turns + direction)
|
|
450
|
+
const next = (day.perWs.get(wsId) || 0) + direction
|
|
451
|
+
if (next > 0) day.perWs.set(wsId, next)
|
|
452
|
+
else day.perWs.delete(wsId)
|
|
453
|
+
}
|
|
454
|
+
function removeTurnRecord(turn) {
|
|
455
|
+
const ws = state.perWorkspace.get(turn.wsId)
|
|
456
|
+
if (ws !== undefined) ws.turns = Math.max(0, ws.turns - 1)
|
|
457
|
+
state.totals.turns = Math.max(0, state.totals.turns - 1)
|
|
458
|
+
addDayTurn(state.byDay, turn.date, turn.wsId, turn.sid, -1)
|
|
459
|
+
addDayTurn(state.byDayUtc, turn.dateUtc, turn.wsId, turn.sid, -1)
|
|
460
|
+
adjustQueryTurn(state.byDay.get(turn.date), turn, -1, false)
|
|
461
|
+
adjustQueryTurn(state.byDayUtc.get(turn.dateUtc), turn, -1, true)
|
|
415
462
|
}
|
|
416
463
|
function turnRecordKey(sid, turn, seq, time) {
|
|
417
464
|
if (Number.isSafeInteger(turn)) return sid + ':turn:' + turn
|
|
@@ -935,6 +982,7 @@ export function createAggregation(host) {
|
|
|
935
982
|
usageBasisEqual,
|
|
936
983
|
resolveCurrentPricing,
|
|
937
984
|
costForUsage,
|
|
985
|
+
removeSession,
|
|
938
986
|
resetAggregationState,
|
|
939
987
|
ensureDay,
|
|
940
988
|
ensureWs,
|