dsh-all-usage 1.1.3 → 1.1.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/CHANGELOG.md CHANGED
@@ -4,6 +4,48 @@ All notable changes to `dsh-all-usage` are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ### Added
8
+
9
+ - DeepSeek peak/off-peak billing as a first-class, versioned **temporal pricing plan**: the cost schema is v2, and each cost snapshot records the billing instant, its time source (request-context / usage-event), the UTC band (peak / off-peak), the policy id, and a policy hash. Request logs show the band and UTC billing time, and the cost settings panel marks which usage models follow the DeepSeek band plan.
10
+ - Built-in first-party DeepSeek profiles (deepseek-v4-flash, deepseek-v4-flash-vision-exp, deepseek-v4-pro) with explicit per-band rates for the UTC windows 01:00-04:00 and 06:00-10:00 on weekdays; the peak rates are stored as data, never derived as an automatic discount rule.
11
+ - UTC band boundaries are half-open: 00:59:59 off-peak, 01:00:00 peak, 03:59:59 peak, 04:00:00 off-peak, 06:00:00 peak, 10:00:00 off-peak; weekends are off-peak. Band selection uses UTC fields only, so viewer timezones, DST, and fractional-hour zones cannot change a result.
12
+ - Deterministic reuse: a later usage sample for the same turn/step reuses the previous cost snapshot only when identity, token buckets, band, policy id/hash, and applicability all match, so a message crossing a peak boundary never inherits the chunk price.
13
+ - Requests preferred as the billing instant when the request/context time matches the usage turn/step; otherwise the usage event time is the auditable fallback. Both are persisted in the snapshot.
14
+ - Controlled DeepSeek temporal reconciliation: first-party DeepSeek snapshots are re-priced against the usage instant on baseline/backfill/sync, v1 snapshots are migrated to the v2 shape in memory and in the persisted ledger, and a plan whose effective window does not cover the instant fails closed as unsupported (temporal-price-history-unavailable) instead of guessing.
15
+ - Route safety boundary: the band plan applies only to first-party deepseek routes or routes explicitly mapped to the DeepSeek official entry; reseller routes (OpenRouter and other gateways) keep the static official price and are labelled route-not-official.
16
+
17
+ - Respect the official effective instant: the built-in DeepSeek band plan starts exactly at 2026-08-16T16:00:00Z (V4-Flash-Vision-Exp at 2026-08-21), and usage before it fails closed as unsupported instead of inheriting today's V4 rates.
18
+ - Persist the request-context archive inside ledger records and seed incremental folds from it after a restart, so an open request whose context arrived in a previous batch keeps its peak/off-peak billing instant.
19
+ - Clear stale request-context instants and route identity on full folds (baseline rebuilds and live resyncs), so a history rewrite that removes a request no longer leaves its band attached to later usage.
20
+ - Keep priced v2 snapshots auditable across catalog refreshes: the policy hash no longer includes live entry rates and reconciliation never rewrites priced history; an explicit repriceTemporal=true request re-estimates every snapshot.
21
+ - Support an ordered policy archive (policies: [...]) with non-overlapping effective windows, reject overlapping rules across rules (JSON array order can never decide a price), keep an invalid temporal config visible and fail closed instead of silently falling back to the built-in profile, and compare temporal plans in the duplicate-candidate check so conflicting band plans resolve ambiguous.
22
+ - Include pricingAt, pricingTimeSource, band, policy id and policy hash in the reconciliation equivalence check and in the CSV audit export.
23
+
24
+ - Persist the invalid temporal-config sentinel through the serialize/normalize cycle: a rejected temporalPricing edit stays fail-closed across restarts instead of re-enabling the built-in DeepSeek profile.
25
+ - Rebuild a session atomically on authoritative live resyncs: usage samples, turn records, date indexes and cost aggregates are removed before the snapshot is folded, so usage deleted by a rewritten history disappears from the aggregate (lagging snapshots keep upsert semantics until the follow-up resync aligns).
26
+ - Base the live resync cursor on the snapshot tail (merged with an absorbed fallback event) instead of the previous cursor, so truncated or rewritten history cannot skip over missing events that arrive later.
27
+ - Accept deepseek-official as a first-party catalog provider in the official provider rules, so its entries price and follow the band plan like deepseek.
28
+ - Validate that a priced snapshot's instant is still covered and band-consistent when deciding whether a policy still matches: snapshots that slipped into a gap (same id/hash, window moved) fail closed instead of staying priced.
29
+ - Include pricingAt and pricingTimeSource in the live/incremental reuse check, so audit metadata refreshes when the request instant or its source changes even within one band.
30
+ - Use real LRU eviction (delete + set) for the bounded request-context archive, applying the same 512-entry cap to the live fold, the persisted ledger, and deserialization.
31
+
32
+ - An authoritative live resync (full snapshot or a snapshot that provably contains the triggering event with a monotonic sequence) rebuilds the session's ledger record from the snapshot, replaces it in state and persists it, so a restart after a live history rewrite cannot resurrect deleted usage; persist failures keep explicit dirty/recovery state and surface as resync-ledger-persist-failed.
33
+ - Live resync authority is now proof-based: snapshots that only have a higher tail, or events without a usable sequence, are treated as lagging (upsert the event, stay pending, align on the follow-up resync) instead of being destructively replaced.
34
+
35
+ - Show real vendor brand icons instead of neutral dots for models in the request log, the selected-call details, the model summary table, and the cost-settings match table. The 11 brand SVGs live in assets/model-icons/ with a manifest (provider aliases, model prefixes, exact overrides, source and licence) and are validated and embedded as data: URIs by scripts/build-client.mjs, so the runtime never reads local paths or the network. Model namespaces win over the DSH provider name so reseller and gateway routes are attributed by the model they actually served; unknown or mixed-brand rows keep the neutral fallback, and workspace colour dots plus chart legend dots are unchanged.
36
+
37
+ - Harden the model brand icons: the load-failure flag is scoped to one icon identity (a shared component that later shows another brand retries instead of staying neutral), an unrecognised actualModel no longer inherits the requested model's brand, model prefixes match on token boundaries only (o10-preview and o3x stay neutral), the resolution cache is bounded, and labelled icons expose the brand through the image's accessible name instead of a title on an aria-hidden host.
38
+ - Build-time SVG validation now decodes XML entities before checking, rejects unquoted URI attributes, external CSS url()/image-set() and @import targets (including escaped/commented/CDO-CDC/namespaced <svg:style> forms), DOCTYPE/CDATA/processing instructions and every external-resource element; the CSS checks run only on style attributes and <style> bodies so icon text and comments stay inert. It lives in scripts/svg-guard.mjs so the tests exercise the exact same guard with adversarial fixtures.
39
+ - Bundle the icon provenance required for release: the manifest pins the upstream commit, records per-file upstream paths and modification flags, and assets/model-icons/LICENSE.upstream-lobe-icons.txt ships the MIT notice, copyright, trademark disclaimer and the local modifications. The build fails if the pinned revision, licence file or per-file attribution is missing.
40
+
41
+ ## [1.1.4] - 2026-09-03
42
+
43
+ ### Fixed
44
+
45
+ - Hardened the model-icon build guard after an independent audit: the CSS checks now reject CDO/CDC-adjacent `@import`, external `@import` inside namespaced `<svg:style>` elements, CSS-escaped `url(` identifiers and external `image-set()` targets, all matching Blink's own tokenizer. Style-attribute `url(...)` references are checked on both the raw and entity-decoded document so `&quot;` quoting cannot split a payload while encoded `@import` is still caught after decoding.
46
+ - CSS `url()`/`image-set()` checks now run only on style attributes and `<style>` bodies, so provenance comments, `<text>` content and CSS comments stay inert (no false positives); the adversarial fixtures assert the rejection reason instead of accepting any error.
47
+ - The model filter dropdown now renders the vendor brand icon for each model option (actual model first, neutral fallback for unknown/private models) instead of the generic line icon, and the three usage-dashboard screenshots were refreshed to the current UI.
48
+
7
49
  ## [1.1.3] - 2026-09-01
8
50
 
9
51
  ### Added
@@ -13,7 +55,9 @@ All notable changes to `dsh-all-usage` are documented here.
13
55
  - Added a Node 22/24 CI matrix with package-content checks and required real DSH runtime smoke coverage for DSH 0.1.1-rc.1 and 0.1.1-rc.2.
14
56
  - Added community issue templates for data inconsistencies, plugin startup failures, and cost calculation issues.
15
57
 
16
- ### Performance
58
+ ### Performance Optimizations
59
+
60
+ This release reduces historical scan work, storage write amplification, and Dashboard render churn while preserving durable-ledger recovery guarantees.
17
61
 
18
62
  - Avoid rebuilding and writing a clean session's derived ledger at `session/flush`; queue and coalesce dirty records, then drain pending writes during disposal.
19
63
  - Store derived ledger records in 32 stable-hash JSON units so a session update rewrites only its shard; retain the legacy single-unit migration path.
@@ -191,6 +235,7 @@ All notable changes to `dsh-all-usage` are documented here.
191
235
  - Allowed same-origin browser balance GET requests that omit `Origin` while retaining token protection.
192
236
  - Standardized English date buckets, range filters, streaks, heatmap dates, and export timestamps on UTC.
193
237
 
238
+ [1.1.4]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.4
194
239
  [1.1.3]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.3
195
240
  [1.1.2]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.2
196
241
  [1.1.0]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.0
package/README.md CHANGED
@@ -104,27 +104,11 @@ node scripts/replay-fixture.mjs fixtures/usage-events.json
104
104
 
105
105
  **v1.1.3**
106
106
 
107
- - 成本统计支持经验证的 context-tiered 官方费率、可展开费率表和显式价格覆盖
108
- - durable usage ledger 支持稳定分片、dirty flush 合并、revision 快路径和安全的增量/全量重建恢复
109
- - 查询、趋势和固定 53 周热力图改用写入时聚合索引,减少冷读取时的历史 usage 扫描
110
- - 定价目录、价格同步、模型检索和映射编辑强化确定性与并发刷新边界
111
- - 加强非法序列、旧账本、工作区重建、滞后 persistence revision 与复合账本键的恢复保护
112
- - 增加 Node 22/24、DSH rc.1/rc.2 runtime smoke、脱敏 fixture replay 和包内容发布门禁
113
-
114
- **v1.1.2**
115
-
116
- - 模型与工作区环图及右侧列表新增 Token 数、成本和占比展示,其他分组同步合并成本
117
- - Host 增加日期索引、快照/日志查询缓存、实时事件恢复和写入生命周期保护
118
- - 成本设置官方模型检索增加防抖,新增 body、别名、时间戳和扫描失败边界校验
119
- - 更新插件自有截图清单,使用全量看板、成本设置和请求日志截图
120
-
121
- **v1.1.1**
122
-
123
- - 结构化模型身份与兼容 ledger v2:区分 Provider、请求模型和实际模型,旧账本自动升级
124
- - 统一 scope 查询:时间、时区、工作区、Provider、模型筛选同时作用于摘要、热力图、趋势、表格和 CSV
125
- - Token 趋势折线图:单日范围按小时、跨日范围按日;平滑单调曲线、分层入场动画、多桶图例切换、悬停精确值和点位审计钻取
126
- - **模型与工作区统计**:在明细表上方提供 Token 占比环形图、中心总量、Top 项目图例和 hover 明细;环段与右侧列表同时展示 Token、成本和占比,tooltip 会跟随鼠标位置
127
- - turn / step 审计明细:常驻请求日志标签、紧凑分页表、选中行分组详情、脱敏来源标记和当前筛选范围明细 CSV
107
+ - 成本统计支持经验证的 context-tiered 官方费率、可展开费率表和显式价格覆盖。
108
+ - **性能优化**:账本采用稳定分片、dirty flush 合并和 revision 快路径;查询、趋势和固定 53 周热力图改用写入时聚合索引,减少历史扫描、存储写放大和 Dashboard 重渲染。
109
+ - 定价目录、价格同步、模型检索和映射编辑强化确定性与并发刷新边界。
110
+ - 加强非法序列、旧账本、工作区重建、滞后 persistence revision 与复合账本键的恢复保护。
111
+ - 增加 Node 22/24、DSH rc.1/rc.2 runtime smoke、脱敏 fixture replay 和包内容发布门禁。
128
112
 
129
113
  完整版本记录见 [CHANGELOG.md](CHANGELOG.md)。
130
114
 
@@ -306,22 +290,11 @@ The command loads the real plugin Host, calls its compatible APIs, checks the do
306
290
 
307
291
  **v1.1.3**
308
292
 
309
- - Added validated context-tiered official pricing, expandable rate schedules, and explicit price overrides
310
- - Reworked the durable usage ledger with stable shards, dirty-flush coalescing, revision reuse, and safe incremental/full recovery
311
- - Built scoped queries, trends, and the fixed 53-week heatmap from ingest-time aggregates to reduce cold historical scans
312
- - Hardened deterministic pricing catalogs, pricing sync, official-model search, and mapping refresh races
313
- - Strengthened recovery for invalid sequences, legacy ledgers, recreated workspaces, lagging persistence revisions, and composite ledger keys
314
- - Added Node 22/24, DSH rc.1/rc.2 runtime smoke, redacted fixture replay, and package-content release gates
315
-
316
- **v1.1.2**
317
-
318
- - Official models.dev pricing, cache/reasoning token buckets, and persisted pricing configuration
319
- - Assistant chunk usage is retained and replaced by the final message for the same turn/step
320
- - Structured model identity with backward-compatible ledger v2 migration
321
- - Unified scope queries for time, timezone, workspace, provider, and model filters
322
- - Token trend line chart with hourly single-day data, selectable series, exact hover values, and point-to-audit drill-down
323
- - Model and workspace analytics with Token-share donut charts, center totals, ranked legends, animated arc reveals, and cursor-following hover details
324
- - Paginated turn/step audit records with redacted provenance and scoped detail CSV export
293
+ - Added validated context-tiered official pricing, expandable rate schedules, and explicit price overrides.
294
+ - **Performance optimizations**: the durable ledger uses stable shards, dirty-flush coalescing, and revision reuse; scoped queries, trends, and the fixed 53-week heatmap use ingest-time aggregates to reduce historical scans, storage write amplification, and Dashboard rerenders.
295
+ - Hardened deterministic pricing catalogs, pricing sync, official-model search, and mapping refresh races.
296
+ - Strengthened recovery for invalid sequences, legacy ledgers, recreated workspaces, lagging persistence revisions, and composite ledger keys.
297
+ - Added Node 22/24, DSH rc.1/rc.2 runtime smoke, redacted fixture replay, and package-content release gates.
325
298
 
326
299
  See [CHANGELOG.md](CHANGELOG.md) for the complete version history.
327
300
 
@@ -0,0 +1,51 @@
1
+ Model brand icons bundled in assets/model-icons/
2
+ =================================================
3
+
4
+ Upstream project : lobe-icons
5
+ Repository : https://github.com/lobehub/lobe-icons
6
+ Pinned revision : 0863807f3a6ce4d7ea23ad86a6693a17638747da
7
+ Upstream licence : MIT
8
+ Licence URL : https://github.com/lobehub/lobe-icons/blob/0863807f3a6ce4d7ea23ad86a6693a17638747da/LICENSE
9
+
10
+ MIT License
11
+
12
+ Copyright (c) 2023 LobeHub
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+
32
+ Trademark notice
33
+ ----------------
34
+
35
+ The brand names, logos and marks depicted by these files remain the property
36
+ of their respective owners (DeepSeek, OpenAI, Anthropic, Google, Meta, Zhipu
37
+ AI, xAI, Alibaba, ByteDance, Moonshot AI, MiniMax). They are bundled only to
38
+ identify which vendor served a recorded request (nominative use) and do not
39
+ imply any endorsement, affiliation or sponsorship.
40
+
41
+ Local modifications
42
+ -------------------
43
+
44
+ 1. Whitespace between tags is collapsed at build time before base64 encoding
45
+ (no visual change to the artwork).
46
+ 2. grok.svg and openai-color.svg: fill="currentColor" was replaced with the
47
+ fixed neutral colour #8a8f98, because currentColor does not inherit into an
48
+ <img> element.
49
+
50
+ Per-file provenance is recorded in assets/model-icons/manifest.json
51
+ (upstreamPath + modified flag for every icon).
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="#D97757" fill-rule="nonzero"></path></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>DeepSeek</title><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z" fill="#4D6BFE"></path></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Doubao</title><path d="M5.31 15.756c.172-3.75 1.883-5.999 2.549-6.739-3.26 2.058-5.425 5.658-6.358 8.308v1.12C1.501 21.513 4.226 24 7.59 24a6.59 6.59 0 002.2-.375c.353-.12.7-.248 1.039-.378.913-.899 1.65-1.91 2.243-2.992-4.877 2.431-7.974.072-7.763-4.5l.002.001z" fill="#1E37FC"></path><path d="M22.57 10.283c-1.212-.901-4.109-2.404-7.397-2.8.295 3.792.093 8.766-2.1 12.773a12.782 12.782 0 01-2.244 2.992c3.764-1.448 6.746-3.457 8.596-5.219 2.82-2.683 3.353-5.178 3.361-6.66a2.737 2.737 0 00-.216-1.084v-.002z" fill="#37E1BE"></path><path d="M14.303 1.867C12.955.7 11.248 0 9.39 0 7.532 0 5.883.677 4.545 1.807 2.791 3.29 1.627 5.557 1.5 8.125v9.201c.932-2.65 3.097-6.25 6.357-8.307.5-.318 1.025-.595 1.569-.829 1.883-.801 3.878-.932 5.746-.706-.222-2.83-.718-5.002-.87-5.617h.001z" fill="#A569FF"></path><path d="M17.305 4.961a199.47 199.47 0 01-1.08-1.094c-.202-.213-.398-.419-.586-.622l-1.333-1.378c.151.615.648 2.786.869 5.617 3.288.395 6.185 1.898 7.396 2.8-1.306-1.275-3.475-3.487-5.266-5.323z" fill="#1E37FC"></path></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Gemini</title><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="#3186FF"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-0-_R_0_)"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-1-_R_0_)"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-2-_R_0_)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-0-_R_0_" x1="7" x2="11" y1="15.5" y2="12"><stop stop-color="#08B962"></stop><stop offset="1" stop-color="#08B962" stop-opacity="0"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-1-_R_0_" x1="8" x2="11.5" y1="5.5" y2="11"><stop stop-color="#F94543"></stop><stop offset="1" stop-color="#F94543" stop-opacity="0"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-2-_R_0_" x1="3.5" x2="17.5" y1="13.5" y2="12"><stop stop-color="#FABC12"></stop><stop offset=".46" stop-color="#FABC12" stop-opacity="0"></stop></linearGradient></defs></svg>
@@ -0,0 +1 @@
1
+ <svg fill="#8a8f98" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Grok</title><path d="M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815"></path></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z" fill="#1783FF"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" fill="#fff"></path></svg>
@@ -0,0 +1,213 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "note": "Brand-level model icons embedded into lib/client.js at build time as data: URIs. The runtime never reads these files, the network, or any machine-local icon directory.",
4
+ "upstream": {
5
+ "project": "lobe-icons",
6
+ "repository": "https://github.com/lobehub/lobe-icons",
7
+ "revision": "0863807f3a6ce4d7ea23ad86a6693a17638747da",
8
+ "revisionUrl": "https://github.com/lobehub/lobe-icons/tree/0863807f3a6ce4d7ea23ad86a6693a17638747da",
9
+ "license": "MIT",
10
+ "licenseUrl": "https://github.com/lobehub/lobe-icons/blob/0863807f3a6ce4d7ea23ad86a6693a17638747da/LICENSE",
11
+ "licenseFile": "LICENSE.upstream-lobe-icons.txt",
12
+ "copyright": "Copyright (c) 2023 LobeHub",
13
+ "notice": "MIT-licensed SVG sources. Brand names, logos and trademarks remain the property of their respective owners; they are bundled solely to identify the vendor that served a request (nominative use), not to imply endorsement."
14
+ },
15
+ "modifications": [
16
+ "Whitespace between tags is collapsed at build time before base64 encoding (no visual change).",
17
+ "grok.svg and openai-color.svg: fill=\"currentColor\" replaced with the fixed neutral #8a8f98, because currentColor does not inherit into an <img> element.",
18
+ "openai-color.svg was taken from the vendor mark set below after the original download produced an HTTP 404 body instead of an SVG."
19
+ ],
20
+ "fallbackKey": null,
21
+ "icons": [
22
+ {
23
+ "key": "deepseek",
24
+ "file": "deepseek-color.svg",
25
+ "label": "DeepSeek",
26
+ "upstreamPath": "packages/static-svg/svg/deepseek-color.svg",
27
+ "modified": false,
28
+ "providers": [
29
+ "deepseek",
30
+ "deepseek-official"
31
+ ],
32
+ "prefixes": [
33
+ "deepseek-"
34
+ ],
35
+ "exact": []
36
+ },
37
+ {
38
+ "key": "openai",
39
+ "file": "openai-color.svg",
40
+ "label": "OpenAI",
41
+ "upstreamPath": "packages/static-svg/svg/openai.svg",
42
+ "modified": true,
43
+ "providers": [
44
+ "openai",
45
+ "azure-openai"
46
+ ],
47
+ "prefixes": [
48
+ "gpt-",
49
+ "o1-",
50
+ "o3-",
51
+ "o4-",
52
+ "o5-",
53
+ "codex-"
54
+ ],
55
+ "exact": [
56
+ "o1",
57
+ "o3",
58
+ "o4",
59
+ "o5"
60
+ ]
61
+ },
62
+ {
63
+ "key": "claude",
64
+ "file": "claude-color.svg",
65
+ "label": "Anthropic Claude",
66
+ "upstreamPath": "packages/static-svg/svg/claude-color.svg",
67
+ "modified": false,
68
+ "providers": [
69
+ "anthropic"
70
+ ],
71
+ "prefixes": [
72
+ "claude-"
73
+ ],
74
+ "exact": []
75
+ },
76
+ {
77
+ "key": "gemini",
78
+ "file": "gemini-color.svg",
79
+ "label": "Google Gemini",
80
+ "upstreamPath": "packages/static-svg/svg/gemini-color.svg",
81
+ "modified": false,
82
+ "providers": [
83
+ "google",
84
+ "google-vertex",
85
+ "vertex"
86
+ ],
87
+ "prefixes": [
88
+ "gemini-",
89
+ "gemma-"
90
+ ],
91
+ "exact": []
92
+ },
93
+ {
94
+ "key": "meta",
95
+ "file": "meta-color.svg",
96
+ "label": "Meta Llama",
97
+ "upstreamPath": "packages/static-svg/svg/meta-color.svg",
98
+ "modified": false,
99
+ "providers": [
100
+ "meta",
101
+ "meta-llama"
102
+ ],
103
+ "prefixes": [
104
+ "llama-",
105
+ "meta-llama"
106
+ ],
107
+ "exact": []
108
+ },
109
+ {
110
+ "key": "zhipu",
111
+ "file": "zhipu-color.svg",
112
+ "label": "Zhipu GLM",
113
+ "upstreamPath": "packages/static-svg/svg/zhipu-color.svg",
114
+ "modified": false,
115
+ "providers": [
116
+ "zhipu",
117
+ "zhipuai",
118
+ "zai",
119
+ "bigmodel"
120
+ ],
121
+ "prefixes": [
122
+ "glm-",
123
+ "chatglm-"
124
+ ],
125
+ "exact": []
126
+ },
127
+ {
128
+ "key": "grok",
129
+ "file": "grok.svg",
130
+ "label": "xAI Grok",
131
+ "upstreamPath": "packages/static-svg/svg/grok.svg",
132
+ "modified": true,
133
+ "providers": [
134
+ "xai"
135
+ ],
136
+ "prefixes": [
137
+ "grok-"
138
+ ],
139
+ "exact": [
140
+ "grok"
141
+ ]
142
+ },
143
+ {
144
+ "key": "qwen",
145
+ "file": "qwen-color.svg",
146
+ "label": "Qwen",
147
+ "upstreamPath": "packages/static-svg/svg/qwen-color.svg",
148
+ "modified": false,
149
+ "providers": [
150
+ "qwen",
151
+ "alibaba",
152
+ "dashscope",
153
+ "bailian"
154
+ ],
155
+ "prefixes": [
156
+ "qwen",
157
+ "qwq-",
158
+ "qvq-"
159
+ ],
160
+ "exact": []
161
+ },
162
+ {
163
+ "key": "doubao",
164
+ "file": "doubao-color.svg",
165
+ "label": "Doubao",
166
+ "upstreamPath": "packages/static-svg/svg/doubao-color.svg",
167
+ "modified": false,
168
+ "providers": [
169
+ "doubao",
170
+ "bytedance",
171
+ "volcengine",
172
+ "ark"
173
+ ],
174
+ "prefixes": [
175
+ "doubao-"
176
+ ],
177
+ "exact": []
178
+ },
179
+ {
180
+ "key": "kimi",
181
+ "file": "kimi-color.svg",
182
+ "label": "Moonshot Kimi",
183
+ "upstreamPath": "packages/static-svg/svg/kimi-color.svg",
184
+ "modified": false,
185
+ "providers": [
186
+ "moonshot",
187
+ "moonshotai"
188
+ ],
189
+ "prefixes": [
190
+ "kimi-",
191
+ "moonshot-"
192
+ ],
193
+ "exact": [
194
+ "kimi"
195
+ ]
196
+ },
197
+ {
198
+ "key": "minimax",
199
+ "file": "minimax-color.svg",
200
+ "label": "MiniMax",
201
+ "upstreamPath": "packages/static-svg/svg/minimax-color.svg",
202
+ "modified": false,
203
+ "providers": [
204
+ "minimax"
205
+ ],
206
+ "prefixes": [
207
+ "minimax-",
208
+ "abab"
209
+ ],
210
+ "exact": []
211
+ }
212
+ ]
213
+ }
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Meta</title><path d="M6.897 4h-.024l-.031 2.615h.022c1.715 0 3.046 1.357 5.94 6.246l.175.297.012.02 1.62-2.438-.012-.019a48.763 48.763 0 00-1.098-1.716 28.01 28.01 0 00-1.175-1.629C10.413 4.932 8.812 4 6.896 4z" fill="url(#lobe-icons-meta-0-_R_0_)"></path><path d="M6.873 4C4.95 4.01 3.247 5.258 2.02 7.17a4.352 4.352 0 00-.01.017l2.254 1.231.011-.017c.718-1.083 1.61-1.774 2.568-1.785h.021L6.896 4h-.023z" fill="url(#lobe-icons-meta-1-_R_0_)"></path><path d="M2.019 7.17l-.011.017C1.2 8.447.598 9.995.274 11.664l-.005.022 2.534.6.004-.022c.27-1.467.786-2.828 1.456-3.845l.011-.017L2.02 7.17z" fill="url(#lobe-icons-meta-2-_R_0_)"></path><path d="M2.807 12.264l-2.533-.6-.005.022c-.177.918-.267 1.851-.269 2.786v.023l2.598.233v-.023a12.591 12.591 0 01.21-2.44z" fill="url(#lobe-icons-meta-3-_R_0_)"></path><path d="M2.677 15.537a5.462 5.462 0 01-.079-.813v-.022L0 14.468v.024a8.89 8.89 0 00.146 1.652l2.535-.585a4.106 4.106 0 01-.004-.022z" fill="url(#lobe-icons-meta-4-_R_0_)"></path><path d="M3.27 16.89c-.284-.31-.484-.756-.589-1.328l-.004-.021-2.535.585.004.021c.192 1.01.568 1.85 1.106 2.487l.014.017 2.018-1.745a2.106 2.106 0 01-.015-.016z" fill="url(#lobe-icons-meta-5-_R_0_)"></path><path d="M10.78 9.654c-1.528 2.35-2.454 3.825-2.454 3.825-2.035 3.2-2.739 3.917-3.871 3.917a1.545 1.545 0 01-1.186-.508l-2.017 1.744.014.017C2.01 19.518 3.058 20 4.356 20c1.963 0 3.374-.928 5.884-5.33l1.766-3.13a41.283 41.283 0 00-1.227-1.886z" fill="#0082FB"></path><path d="M13.502 5.946l-.016.016c-.4.43-.786.908-1.16 1.416.378.483.768 1.024 1.175 1.63.48-.743.928-1.345 1.367-1.807l.016-.016-1.382-1.24z" fill="url(#lobe-icons-meta-6-_R_0_)"></path><path d="M20.918 5.713C19.853 4.633 18.583 4 17.225 4c-1.432 0-2.637.787-3.723 1.944l-.016.016 1.382 1.24.016-.017c.715-.747 1.408-1.12 2.176-1.12.826 0 1.6.39 2.27 1.075l.015.016 1.589-1.425-.016-.016z" fill="#0082FB"></path><path d="M23.998 14.125c-.06-3.467-1.27-6.566-3.064-8.396l-.016-.016-1.588 1.424.015.016c1.35 1.392 2.277 3.98 2.361 6.971v.023h2.292v-.022z" fill="url(#lobe-icons-meta-7-_R_0_)"></path><path d="M23.998 14.15v-.023h-2.292v.022c.004.14.006.282.006.424 0 .815-.121 1.474-.368 1.95l-.011.022 1.708 1.782.013-.02c.62-.96.946-2.293.946-3.91 0-.083 0-.165-.002-.247z" fill="url(#lobe-icons-meta-8-_R_0_)"></path><path d="M21.344 16.52l-.011.02c-.214.402-.519.67-.917.787l.778 2.462a3.493 3.493 0 00.438-.182 3.558 3.558 0 001.366-1.218l.044-.065.012-.02-1.71-1.784z" fill="url(#lobe-icons-meta-9-_R_0_)"></path><path d="M19.92 17.393c-.262 0-.492-.039-.718-.14l-.798 2.522c.449.153.927.222 1.46.222.492 0 .943-.073 1.352-.215l-.78-2.462c-.167.05-.341.075-.517.073z" fill="url(#lobe-icons-meta-10-_R_0_)"></path><path d="M18.323 16.534l-.014-.017-1.836 1.914.016.017c.637.682 1.246 1.105 1.937 1.337l.797-2.52c-.291-.125-.573-.353-.9-.731z" fill="url(#lobe-icons-meta-11-_R_0_)"></path><path d="M18.309 16.515c-.55-.642-1.232-1.712-2.303-3.44l-1.396-2.336-.011-.02-1.62 2.438.012.02.989 1.668c.959 1.61 1.74 2.774 2.493 3.585l.016.016 1.834-1.914a2.353 2.353 0 01-.014-.017z" fill="url(#lobe-icons-meta-12-_R_0_)"></path><defs><linearGradient id="lobe-icons-meta-0-_R_0_" x1="75.897%" x2="26.312%" y1="89.199%" y2="12.194%"><stop offset=".06%" stop-color="#0867DF"></stop><stop offset="45.39%" stop-color="#0668E1"></stop><stop offset="85.91%" stop-color="#0064E0"></stop></linearGradient><linearGradient id="lobe-icons-meta-1-_R_0_" x1="21.67%" x2="97.068%" y1="75.874%" y2="23.985%"><stop offset="13.23%" stop-color="#0064DF"></stop><stop offset="99.88%" stop-color="#0064E0"></stop></linearGradient><linearGradient id="lobe-icons-meta-2-_R_0_" x1="38.263%" x2="60.895%" y1="89.127%" y2="16.131%"><stop offset="1.47%" stop-color="#0072EC"></stop><stop offset="68.81%" stop-color="#0064DF"></stop></linearGradient><linearGradient id="lobe-icons-meta-3-_R_0_" x1="47.032%" x2="52.15%" y1="90.19%" y2="15.745%"><stop offset="7.31%" stop-color="#007CF6"></stop><stop offset="99.43%" stop-color="#0072EC"></stop></linearGradient><linearGradient id="lobe-icons-meta-4-_R_0_" x1="52.155%" x2="47.591%" y1="58.301%" y2="37.004%"><stop offset="7.31%" stop-color="#007FF9"></stop><stop offset="100%" stop-color="#007CF6"></stop></linearGradient><linearGradient id="lobe-icons-meta-5-_R_0_" x1="37.689%" x2="61.961%" y1="12.502%" y2="63.624%"><stop offset="7.31%" stop-color="#007FF9"></stop><stop offset="100%" stop-color="#0082FB"></stop></linearGradient><linearGradient id="lobe-icons-meta-6-_R_0_" x1="34.808%" x2="62.313%" y1="68.859%" y2="23.174%"><stop offset="27.99%" stop-color="#007FF8"></stop><stop offset="91.41%" stop-color="#0082FB"></stop></linearGradient><linearGradient id="lobe-icons-meta-7-_R_0_" x1="43.762%" x2="57.602%" y1="6.235%" y2="98.514%"><stop offset="0%" stop-color="#0082FB"></stop><stop offset="99.95%" stop-color="#0081FA"></stop></linearGradient><linearGradient id="lobe-icons-meta-8-_R_0_" x1="60.055%" x2="39.88%" y1="4.661%" y2="69.077%"><stop offset="6.19%" stop-color="#0081FA"></stop><stop offset="100%" stop-color="#0080F9"></stop></linearGradient><linearGradient id="lobe-icons-meta-9-_R_0_" x1="30.282%" x2="61.081%" y1="59.32%" y2="33.244%"><stop offset="0%" stop-color="#027AF3"></stop><stop offset="100%" stop-color="#0080F9"></stop></linearGradient><linearGradient id="lobe-icons-meta-10-_R_0_" x1="20.433%" x2="82.112%" y1="50.001%" y2="50.001%"><stop offset="0%" stop-color="#0377EF"></stop><stop offset="99.94%" stop-color="#0279F1"></stop></linearGradient><linearGradient id="lobe-icons-meta-11-_R_0_" x1="40.303%" x2="72.394%" y1="35.298%" y2="57.811%"><stop offset=".19%" stop-color="#0471E9"></stop><stop offset="100%" stop-color="#0377EF"></stop></linearGradient><linearGradient id="lobe-icons-meta-12-_R_0_" x1="32.254%" x2="68.003%" y1="19.719%" y2="84.908%"><stop offset="27.65%" stop-color="#0867DF"></stop><stop offset="100%" stop-color="#0471E9"></stop></linearGradient></defs></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Minimax</title><defs><linearGradient id="lobe-icons-minimax-_R_0_" x1="0%" x2="100.182%" y1="50.057%" y2="50.057%"><stop offset="0%" stop-color="#E2167E"></stop><stop offset="100%" stop-color="#FE603C"></stop></linearGradient></defs><path d="M16.278 2c1.156 0 2.093.927 2.093 2.07v12.501a.74.74 0 00.744.709.74.74 0 00.743-.709V9.099a2.06 2.06 0 012.071-2.049A2.06 2.06 0 0124 9.1v6.561a.649.649 0 01-.652.645.649.649 0 01-.653-.645V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v7.472a2.037 2.037 0 01-2.048 2.026 2.037 2.037 0 01-2.048-2.026v-12.5a.785.785 0 00-.788-.753.785.785 0 00-.789.752l-.001 15.904A2.037 2.037 0 0113.441 22a2.037 2.037 0 01-2.048-2.026V18.04c0-.356.292-.645.652-.645.36 0 .652.289.652.645v1.934c0 .263.142.506.372.638.23.131.514.131.744 0a.734.734 0 00.372-.638V4.07c0-1.143.937-2.07 2.093-2.07zm-5.674 0c1.156 0 2.093.927 2.093 2.07v11.523a.648.648 0 01-.652.645.648.648 0 01-.652-.645V4.07a.785.785 0 00-.789-.78.785.785 0 00-.789.78v14.013a2.06 2.06 0 01-2.07 2.048 2.06 2.06 0 01-2.071-2.048V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v3.8a2.06 2.06 0 01-2.071 2.049A2.06 2.06 0 010 12.9v-1.378c0-.357.292-.646.652-.646.36 0 .653.29.653.646V12.9c0 .418.343.757.766.757s.766-.339.766-.757V9.099a2.06 2.06 0 012.07-2.048 2.06 2.06 0 012.071 2.048v8.984c0 .419.343.758.767.758.423 0 .766-.339.766-.758V4.07c0-1.143.937-2.07 2.093-2.07z" fill="url(#lobe-icons-minimax-_R_0_)" fill-rule="nonzero"></path></svg>
@@ -0,0 +1 @@
1
+ <svg fill="#8a8f98" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenAI</title><path d="M21.55 10.004a5.416 5.416 0 00-.478-4.501c-1.217-2.09-3.662-3.166-6.05-2.66A5.59 5.59 0 0010.831 1C8.39.995 6.224 2.546 5.473 4.838A5.553 5.553 0 001.76 7.496a5.487 5.487 0 00.691 6.5 5.416 5.416 0 00.477 4.502c1.217 2.09 3.662 3.165 6.05 2.66A5.586 5.586 0 0013.168 23c2.443.006 4.61-1.546 5.361-3.84a5.553 5.553 0 003.715-2.66 5.488 5.488 0 00-.693-6.497v.001zm-8.381 11.558a4.199 4.199 0 01-2.675-.954c.034-.018.093-.05.132-.074l4.44-2.53a.71.71 0 00.364-.623v-6.176l1.877 1.069c.02.01.033.029.036.05v5.115c-.003 2.274-1.87 4.118-4.174 4.123zM4.192 17.78a4.059 4.059 0 01-.498-2.763c.032.02.09.055.131.078l4.44 2.53c.225.13.504.13.73 0l5.42-3.088v2.138a.068.068 0 01-.027.057L9.9 19.288c-1.999 1.136-4.552.46-5.707-1.51h-.001zM3.023 8.216A4.15 4.15 0 015.198 6.41l-.002.151v5.06a.711.711 0 00.364.624l5.42 3.087-1.876 1.07a.067.067 0 01-.063.005l-4.489-2.559c-1.995-1.14-2.679-3.658-1.53-5.63h.001zm15.417 3.54l-5.42-3.088L14.896 7.6a.067.067 0 01.063-.006l4.489 2.557c1.998 1.14 2.683 3.662 1.529 5.633a4.163 4.163 0 01-2.174 1.807V12.38a.71.71 0 00-.363-.623zm1.867-2.773a6.04 6.04 0 00-.132-.078l-4.44-2.53a.731.731 0 00-.729 0l-5.42 3.088V7.325a.068.068 0 01.027-.057L14.1 4.713c2-1.137 4.555-.46 5.707 1.513.487.833.664 1.809.499 2.757h.001zm-11.741 3.81l-1.877-1.068a.065.065 0 01-.036-.051V6.559c.001-2.277 1.873-4.122 4.181-4.12.976 0 1.92.338 2.671.954-.034.018-.092.05-.131.073l-4.44 2.53a.71.71 0 00-.365.623l-.003 6.173v.002zm1.02-2.168L12 9.25l2.414 1.375v2.75L12 14.75l-2.415-1.375v-2.75z"></path></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Qwen</title><path d="M12.604 1.34c.393.69.784 1.382 1.174 2.075a.18.18 0 00.157.091h5.552c.174 0 .322.11.446.327l1.454 2.57c.19.337.24.478.024.837-.26.43-.513.864-.76 1.3l-.367.658c-.106.196-.223.28-.04.512l2.652 4.637c.172.301.111.494-.043.77-.437.785-.882 1.564-1.335 2.34-.159.272-.352.375-.68.37-.777-.016-1.552-.01-2.327.016a.099.099 0 00-.081.05 575.097 575.097 0 01-2.705 4.74c-.169.293-.38.363-.725.364-.997.003-2.002.004-3.017.002a.537.537 0 01-.465-.271l-1.335-2.323a.09.09 0 00-.083-.049H4.982c-.285.03-.553-.001-.805-.092l-1.603-2.77a.543.543 0 01-.002-.54l1.207-2.12a.198.198 0 000-.197 550.951 550.951 0 01-1.875-3.272l-.79-1.395c-.16-.31-.173-.496.095-.965.465-.813.927-1.625 1.387-2.436.132-.234.304-.334.584-.335a338.3 338.3 0 012.589-.001.124.124 0 00.107-.063l2.806-4.895a.488.488 0 01.422-.246c.524-.001 1.053 0 1.583-.006L11.704 1c.341-.003.724.032.9.34zm-3.432.403a.06.06 0 00-.052.03L6.254 6.788a.157.157 0 01-.135.078H3.253c-.056 0-.07.025-.041.074l5.81 10.156c.025.042.013.062-.034.063l-2.795.015a.218.218 0 00-.2.116l-1.32 2.31c-.044.078-.021.118.068.118l5.716.008c.046 0 .08.02.104.061l1.403 2.454c.046.081.092.082.139 0l5.006-8.76.783-1.382a.055.055 0 01.096 0l1.424 2.53a.122.122 0 00.107.062l2.763-.02a.04.04 0 00.035-.02.041.041 0 000-.04l-2.9-5.086a.108.108 0 010-.113l.293-.507 1.12-1.977c.024-.041.012-.062-.035-.062H9.2c-.059 0-.073-.026-.043-.077l1.434-2.505a.107.107 0 000-.114L9.225 1.774a.06.06 0 00-.053-.031zm6.29 8.02c.046 0 .058.02.034.06l-.832 1.465-2.613 4.585a.056.056 0 01-.05.029.058.058 0 01-.05-.029L8.498 9.841c-.02-.034-.01-.052.028-.054l.216-.012 6.722-.012z" fill="url(#lobe-icons-qwen-_R_0_)" fill-rule="nonzero"></path><defs><linearGradient id="lobe-icons-qwen-_R_0_" x1="0%" x2="100%" y1="0%" y2="0%"><stop offset="0%" stop-color="#6336E7" stop-opacity=".84"></stop><stop offset="100%" stop-color="#6F69F7" stop-opacity=".84"></stop></linearGradient></defs></svg>
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Zhipu</title><path d="M11.991 23.503a.24.24 0 00-.244.248.24.24 0 00.244.249.24.24 0 00.245-.249.24.24 0 00-.22-.247l-.025-.001zM9.671 5.365a1.697 1.697 0 011.099 2.132l-.071.172-.016.04-.018.054c-.07.16-.104.32-.104.498-.035.71.47 1.279 1.186 1.314h.366c1.309.053 2.338 1.173 2.286 2.523-.052 1.332-1.152 2.38-2.478 2.327h-.174c-.715.018-1.274.64-1.239 1.368 0 .124.018.23.053.337.209.373.54.658.96.8.75.23 1.517-.125 1.9-.782l.018-.035c.402-.64 1.17-.96 1.92-.711.854.284 1.378 1.226 1.099 2.167a1.661 1.661 0 01-2.077 1.102 1.711 1.711 0 01-.907-.711l-.017-.035c-.2-.323-.463-.58-.851-.711l-.056-.018a1.646 1.646 0 00-1.954.746 1.66 1.66 0 01-1.065.764 1.677 1.677 0 01-1.989-1.279c-.209-.906.332-1.83 1.257-2.043a1.51 1.51 0 01.296-.035h.018c.68-.071 1.151-.622 1.116-1.333a1.307 1.307 0 00-.227-.693 2.515 2.515 0 01-.366-1.403 2.39 2.39 0 01.366-1.208c.14-.195.21-.444.227-.693.018-.71-.506-1.261-1.186-1.332l-.07-.018a1.43 1.43 0 01-.299-.07l-.05-.019a1.7 1.7 0 01-1.047-2.114 1.68 1.68 0 012.094-1.101zm-5.575 10.11c.26-.264.639-.367.994-.27.355.096.633.379.728.74.095.362-.007.748-.267 1.013-.402.41-1.053.41-1.455 0a1.062 1.062 0 010-1.482zm14.845-.294c.359-.09.738.024.992.297.254.274.344.665.237 1.025-.107.36-.396.634-.756.718-.551.128-1.1-.22-1.23-.781a1.05 1.05 0 01.757-1.26zm-.064-4.39c.314.32.49.753.49 1.206 0 .452-.176.886-.49 1.206-.315.32-.74.5-1.185.5-.444 0-.87-.18-1.184-.5a1.727 1.727 0 010-2.412 1.654 1.654 0 012.369 0zm-11.243.163c.364.484.447 1.128.218 1.691a1.665 1.665 0 01-2.188.923c-.855-.36-1.26-1.358-.907-2.228a1.68 1.68 0 011.33-1.038c.593-.08 1.183.169 1.547.652zm11.545-4.221c.368 0 .708.2.892.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.892.524c-.568 0-1.03-.47-1.03-1.048 0-.579.462-1.048 1.03-1.048zm-14.358 0c.368 0 .707.2.891.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.891.524c-.569 0-1.03-.47-1.03-1.048 0-.579.461-1.048 1.03-1.048zm10.031-1.475c.925 0 1.675.764 1.675 1.706s-.75 1.705-1.675 1.705-1.674-.763-1.674-1.705c0-.942.75-1.706 1.674-1.706zm-2.626-.684c.362-.082.653-.356.761-.718a1.062 1.062 0 00-.238-1.028 1.017 1.017 0 00-.996-.294c-.547.14-.881.7-.752 1.257.13.558.675.907 1.225.783zm0 16.876c.359-.087.644-.36.75-.72a1.062 1.062 0 00-.237-1.019 1.018 1.018 0 00-.985-.301 1.037 1.037 0 00-.762.717c-.108.361-.017.754.239 1.028.245.263.606.377.953.305l.043-.01zM17.19 3.5a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64a.631.631 0 00-.628.64c0 .355.28.64.628.64zm-10.38 0a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64a.631.631 0 00-.628.64c0 .355.279.64.628.64zm-5.182 7.852a.631.631 0 00-.628.64c0 .354.28.639.628.639a.63.63 0 00.627-.606l.001-.034a.62.62 0 00-.628-.64zm5.182 9.13a.631.631 0 00-.628.64c0 .355.279.64.628.64a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm10.38.018a.631.631 0 00-.628.64c0 .355.28.64.628.64a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64zm5.182-9.148a.631.631 0 00-.628.64c0 .354.279.639.628.639a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm-.384-4.992a.24.24 0 00.244-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249c0 .142.122.249.244.249zM11.991.497a.24.24 0 00.245-.248A.24.24 0 0011.99 0a.24.24 0 00-.244.249c0 .133.108.236.223.247l.021.001zM2.011 6.36a.24.24 0 00.245-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249.24.24 0 00.244.249zm0 11.263a.24.24 0 00-.243.248.24.24 0 00.244.249.24.24 0 00.244-.249.252.252 0 00-.244-.248zm19.995-.018a.24.24 0 00-.245.248.24.24 0 00.245.25.24.24 0 00.244-.25.252.252 0 00-.244-.248z" fill="#3859FF" fill-rule="nonzero"></path></svg>
Binary file
Binary file
Binary file
@@ -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, 1)
413
- day.turns += 1
414
- day.perWs.set(wsId, (day.perWs.get(wsId) || 0) + 1)
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,