Skip to content
This repository was archived by the owner on Jul 30, 2026. It is now read-only.

fix(core): retain usage without provider attribution - #164

Merged
makoMakoGo merged 7 commits into
personal/local-clientsfrom
codex/fix-provider-independent-usage
Jul 18, 2026
Merged

fix(core): retain usage without provider attribution#164
makoMakoGo merged 7 commits into
personal/local-clientsfrom
codex/fix-provider-independent-usage

Conversation

@makoMakoGo

@makoMakoGo makoMakoGo commented Jul 18, 2026

Copy link
Copy Markdown
Owner

背景

部分本地 session parser 把 provider 归属当成 usage 合法性的前置条件:即使记录已经包含非空 model、有效时间戳和完整 token,只要 provider 缺失或模型族推断失败,usage 仍可能被丢弃。provider 只是归属与分组元数据,不应覆盖 model 和 token 事实。

Kimi Code 进一步暴露了这个问题:usage.record 保存 model alias;较新的 per-agent wire 会在前序 llm.request 中记录物理 model、alias 和传输协议,而当前 config.toml 既可变也不是历史快照。

改动

  • 统一本地 usage 身份规则:优先保留显式 provider,否则按 model family 推断,仍无法推断时使用 unknown;provider 失败不再丢弃有效 model/token。
  • 更新相关 parser 和 adapter revision,并补充缺失 provider、未知模型族、overflow、source 隔离及缓存失效回归用例。
  • 保留真正承担 ownership、过滤或去重职责的字段约束;例如 Zed 缺少 usage owner 时仍作为来源完整性问题处理。
  • Kimi 按 agent wire 的记录顺序维护 alias 身份:使用同 alias 最近的前序 llm.request.model,无请求证据时才尝试当前 config 的精确映射,最后保留 raw alias。
  • Kimi 的 llm.request.provider 仅视为传输协议,不作为模型所有者;重试请求不会重复生成 usage,未来请求也不会回填更早记录。
  • 当前 Kimi config 仅作为可选身份增强与缓存依赖;缺失映射不会再删除历史 token。旧版根目录 Kimi CLI session 格式仍不在支持范围内。
  • 新增 docs/facts/kimi-code.md,记录已核验的当前存储布局、wire shape、请求与 usage 因果关系及真实语料快照。
  • 将过时 ADR 0011、0021 的有效决策分别合并到现有 pricing 与 source ingestion ADR,删除重复文档。

影响

能够确定 model 和 token 的 usage 会稳定进入聚合;provider 推断或 unknown 属于成功归一化,不会污染 source health。缺失 model、无效时间戳、非法 token、来源不可读或真正缺少 ownership 证据仍会按原有完整性合同显示。

验证

  • cargo test --workspace
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • git diff --check
  • bun run build:core
  • 使用本机真实 Kimi Code main-agent 与 swarm wire 数据验证物理 model 映射、raw alias 保留和 token 总量
  • 手工检查 Overview、Daily、Hourly、Stats、Agents、Sessions 与 Usage 视图;整体 source health 为 complete,除 Clean 外其余指标为 0

Summary by CodeRabbit

  • 新功能

    • 改进模型与提供方识别:保留有效用量,即使提供方无法确定也会标记为 unknown
    • 支持更可靠的 Kimi 模型别名与请求顺序解析。
    • 改进配置缺失、损坏或不完整时的用量保留与缓存处理。
    • 新增“无法验证用量归属”的健康状态分类。
  • Bug 修复

    • 修复未知模型、缺少提供方或不完整配置导致用量被错误丢弃的问题。
    • 改进 OpenCode、Zed 等来源的错误隔离与健康报告。
  • 文档

    • 更新模型身份、定价、缓存、CLI 与客户端扫描规则。
    • 补充 Kimi Code 本地会话格式说明。

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@makoMakoGo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd3a8bfd-fd54-41a2-80d4-6dd1550e544f

📥 Commits

Reviewing files that changed from the base of the PR and between 47aa0bd and 251814a.

📒 Files selected for processing (17)
  • crates/tokscale-core/src/adapters/cache.rs
  • crates/tokscale-core/src/adapters/discover.rs
  • crates/tokscale-core/src/adapters/file.rs
  • crates/tokscale-core/src/adapters/kiro.rs
  • crates/tokscale-core/src/adapters/mod.rs
  • crates/tokscale-core/src/adapters/omp.rs
  • crates/tokscale-core/src/adapters/vscode_tasks.rs
  • crates/tokscale-core/src/lib_tests.rs
  • crates/tokscale-core/src/local_clients.rs
  • crates/tokscale-core/src/message_cache.rs
  • crates/tokscale-core/src/scanner.rs
  • crates/tokscale-core/src/sessions/commandcode.rs
  • crates/tokscale-core/src/sessions/kimi.rs
  • docs/clients.md
  • docs/facts/command-code.md
  • docs/facts/droid.md
  • docs/facts/kimi-code.md

Walkthrough

该 PR 统一了 provider attribution 处理:有效模型与 token 记录在 provider 缺失或推断失败时继续保留,并以规范化 provider 或 unknown 表示。同时更新 Kimi、Antigravity、多个会话解析器、缓存依赖语义、ParserVersion 修订号、健康分类及相关文档。

Changes

Provider attribution 与会话解析

Layer / File(s) Summary
Provider identity contract
crates/tokscale-core/src/provider_identity.rs, crates/tokscale-core/src/source_health.rs
新增统一 provider 解析与 unknown 回退;以 UnverifiedUsageOwner 替代 MissingProvider
Session parser integration
crates/tokscale-core/src/sessions/*
多个客户端在 provider 缺失或未知时保留 usage,并将 provider_id 设置为显式值、推断值或 unknown
Kimi and Antigravity identity handling
crates/tokscale-core/src/sessions/kimi.rs, crates/tokscale-core/src/sessions/antigravity_cli.rs
Kimi 使用有序 llm.request 别名解析后续 usage;Antigravity 保留 backend 或原始模型观测。
Cache and parser revisions
crates/tokscale-core/src/adapters/*
更新多项 ParserVersion 修订号,并区分必需与可选依赖以控制缓存和健康状态。
Contracts and documentation
AGENTS.md, CONTEXT.md, docs/adr/*, docs/clients.md, docs/facts/kimi-code.md
补充模型观测、provider attribution、缓存边界、Kimi 存储事实及定价来源说明。

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ClientSource
  participant SessionParser
  participant ProviderIdentity
  participant UnifiedMessage
  ClientSource->>SessionParser: usage record with model and optional provider
  SessionParser->>ProviderIdentity: source_provider_id(raw provider, model)
  ProviderIdentity-->>SessionParser: explicit provider, inferred provider, or unknown
  SessionParser->>UnifiedMessage: retain tokens and attach provider_id
Loading

Possibly related PRs

Poem

小兔捧着 token 跳,
provider 缺席也不恼。
模型原样先留下,
不知归属写 unknown。
Kimi 请求牵别名,
缓存版本换新装。

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次核心变更:在缺少 provider attribution 时保留 usage。
Docstring Coverage ✅ Passed Docstring coverage is 80.38% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-provider-independent-usage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/tokscale-core/src/sessions/opencode.rs (1)

228-233: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

保留已发布的 provider 语义错误变体。

从公共枚举移除 MissingProviderIdEmptyProviderId 会使引用这些变体的下游代码无法编译。它们可以停止产生,但应继续保留并标记弃用,除非本次发布明确包含破坏性 API 版本升级。

建议修改
 pub enum OpenCodeMessageSemanticError {
     #[error("modelID is missing or null")]
     MissingModelId,
     #[error("modelID must not be empty or whitespace")]
     EmptyModelId,
+    #[deprecated(note = "provider attribution is now optional")]
+    #[error("providerID is missing or null")]
+    MissingProviderId,
+    #[deprecated(note = "provider attribution is now optional")]
+    #[error("providerID must not be empty or whitespace")]
+    EmptyProviderId,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/tokscale-core/src/sessions/opencode.rs` around lines 228 - 233, 在
OpenCodeMessageSemanticError 公共枚举中保留 MissingProviderId 和 EmptyProviderId
变体,不要删除它们;为这两个已停止产生的变体添加弃用标记,并保持现有 modelID 相关变体不变,以兼容引用旧 API 的下游代码。
crates/tokscale-core/src/sessions/kilo.rs (1)

226-232: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

请始终通过中央解析器处理显式 providerID

当前分支会原样保留 "unknown""<provider>" 等非空占位值,导致已知模型无法回推真实 provider。请将原始值直接传给 source_provider_id

建议修改
-        let provider = msg
-            .provider_id
-            .as_deref()
-            .map(str::trim)
-            .filter(|provider| !provider.is_empty())
-            .map(str::to_string)
-            .unwrap_or_else(|| provider_identity::source_provider_id("", &model_id));
+        let provider = provider_identity::source_provider_id(
+            msg.provider_id.as_deref().unwrap_or_default(),
+            &model_id,
+        );

As per coding guidelines,provider attribution 应集中推断,并在推断失败时使用 unknown

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/tokscale-core/src/sessions/kilo.rs` around lines 226 - 232, Update the
provider resolution in the session handling flow to always pass the raw optional
provider_id value through provider_identity::source_provider_id, rather than
preserving non-empty placeholders such as "unknown" or "<provider>". Keep the
centralized resolver responsible for attribution and its existing unknown
fallback behavior.

Source: Coding guidelines

🧹 Nitpick comments (1)
crates/tokscale-core/src/adapters/file.rs (1)

552-579: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

补充“配置从缺失变为存在”的缓存失效回归。

当前测试只证明缺失配置时可以写缓存,未验证随后创建 config.toml 会触发 miss。该路径若回归,会持续返回缓存中的 active-model/unknown,忽略新配置的模型和 provider。

建议补充的断言
         assert_eq!(messages[0].model_id.as_ref(), "active-model");
+        assert_eq!(messages[0].provider_id.as_ref(), "unknown");
         assert_eq!(messages[0].tokens.input, 10);
         assert_eq!(messages[0].tokens.output, 2);
         assert!(cache
             .get_meta(&wire_path, KIMI_ADAPTER.parser_version)
             .unwrap()
             .is_some());
+
+        write_file(
+            &config_path,
+            r#"[models.active-model]
+provider = "openai"
+model = "gpt-5"
+"#,
+        );
+        let changed_unit = KIMI_ADAPTER.discover_checked(&ctx).unwrap().pop().unwrap();
+        let crate::adapters::CacheHitPlan::Miss(changed_unit) =
+            KIMI_ADAPTER.plan_cache_hit(changed_unit, &cache).unwrap()
+        else {
+            panic!("new Kimi config must invalidate the absent-dependency cache");
+        };
+        let changed_messages =
+            fold_with_adapter(&KIMI_ADAPTER, vec![changed_unit], &mut cache);
+        assert_eq!(changed_messages[0].model_id.as_ref(), "gpt-5");
+        assert_eq!(changed_messages[0].provider_id.as_ref(), "openai");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/tokscale-core/src/adapters/file.rs` around lines 552 - 579, Extend
kimi_missing_config_keeps_usage_and_caches_the_absent_dependency to create
config.toml after the initial scan/cache write, then scan and fold the same wire
data again with the existing cache. Assert the dependency change causes a cache
miss and the resulting message uses the configured model and provider instead of
the previously cached active-model/unknown values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/tokscale-core/src/sessions/kimi.rs`:
- Around line 301-323: 在解析 alias 映射并插入 aliases 的逻辑中,不要将 provider 视为必填字段;只要 model
非空就保留 ModelIdentity。复用中央 provider 推断逻辑为可选 provider 赋值,推断失败时使用 unknown,避免 opaque
alias 被当作模型 ID。同步更新相关测试,使 alias 使用 opaque 名称并覆盖缺失 provider 的映射与分组定价行为。

In `@docs/clients.md`:
- Around line 119-123: 明确 Kimi Code 的关联规则:preceding llm.request 必须限定为同一 alias
的最近一个有效前置请求。更新该段文档,说明不得使用任意其他 alias 的请求或后续请求回填更早的 usage,并保持 alias 按 agent wire
顺序解析的契约。

---

Outside diff comments:
In `@crates/tokscale-core/src/sessions/kilo.rs`:
- Around line 226-232: Update the provider resolution in the session handling
flow to always pass the raw optional provider_id value through
provider_identity::source_provider_id, rather than preserving non-empty
placeholders such as "unknown" or "<provider>". Keep the centralized resolver
responsible for attribution and its existing unknown fallback behavior.

In `@crates/tokscale-core/src/sessions/opencode.rs`:
- Around line 228-233: 在 OpenCodeMessageSemanticError 公共枚举中保留 MissingProviderId
和 EmptyProviderId 变体,不要删除它们;为这两个已停止产生的变体添加弃用标记,并保持现有 modelID 相关变体不变,以兼容引用旧 API
的下游代码。

---

Nitpick comments:
In `@crates/tokscale-core/src/adapters/file.rs`:
- Around line 552-579: Extend
kimi_missing_config_keeps_usage_and_caches_the_absent_dependency to create
config.toml after the initial scan/cache write, then scan and fold the same wire
data again with the existing cache. Assert the dependency change causes a cache
miss and the resulting message uses the configured model and provider instead of
the previously cached active-model/unknown values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e12a1ca5-d9c1-4669-a287-ad3ad892b7c7

📥 Commits

Reviewing files that changed from the base of the PR and between bf6f7d4 and 47aa0bd.

📒 Files selected for processing (52)
  • AGENTS.md
  • CONTEXT.md
  • crates/tokscale-core/src/adapters/antigravity.rs
  • crates/tokscale-core/src/adapters/codebuddy.rs
  • crates/tokscale-core/src/adapters/codebuff.rs
  • crates/tokscale-core/src/adapters/file.rs
  • crates/tokscale-core/src/adapters/goose.rs
  • crates/tokscale-core/src/adapters/hermes.rs
  • crates/tokscale-core/src/adapters/junie.rs
  • crates/tokscale-core/src/adapters/kilo.rs
  • crates/tokscale-core/src/adapters/mod.rs
  • crates/tokscale-core/src/adapters/omp.rs
  • crates/tokscale-core/src/adapters/openclaw.rs
  • crates/tokscale-core/src/adapters/pi.rs
  • crates/tokscale-core/src/adapters/vscode_tasks.rs
  • crates/tokscale-core/src/adapters/warp.rs
  • crates/tokscale-core/src/provider_identity.rs
  • crates/tokscale-core/src/scanner.rs
  • crates/tokscale-core/src/sessions/amp.rs
  • crates/tokscale-core/src/sessions/antigravity_cli.rs
  • crates/tokscale-core/src/sessions/codebuddy.rs
  • crates/tokscale-core/src/sessions/codebuff.rs
  • crates/tokscale-core/src/sessions/commandcode.rs
  • crates/tokscale-core/src/sessions/copilot.rs
  • crates/tokscale-core/src/sessions/droid.rs
  • crates/tokscale-core/src/sessions/goose.rs
  • crates/tokscale-core/src/sessions/hermes.rs
  • crates/tokscale-core/src/sessions/junie.rs
  • crates/tokscale-core/src/sessions/kilo.rs
  • crates/tokscale-core/src/sessions/kimi.rs
  • crates/tokscale-core/src/sessions/mux.rs
  • crates/tokscale-core/src/sessions/openclaw.rs
  • crates/tokscale-core/src/sessions/opencode.rs
  • crates/tokscale-core/src/sessions/pi.rs
  • crates/tokscale-core/src/sessions/roocode.rs
  • crates/tokscale-core/src/sessions/warp.rs
  • crates/tokscale-core/src/sessions/zed.rs
  • crates/tokscale-core/src/source_health.rs
  • docs/adr/0001-no-silent-fallback.md
  • docs/adr/0008-single-copy-memory-pipeline.md
  • docs/adr/0011-token-derived-local-cost.md
  • docs/adr/0013-pricing-source-authority.md
  • docs/adr/0019-current-format-only-local-storage.md
  • docs/adr/0020-strict-source-identity-and-error-contract.md
  • docs/adr/0021-isolated-source-failure-domains.md
  • docs/adr/0022-deterministic-cli-command-semantics.md
  • docs/cli.md
  • docs/clients.md
  • docs/facts/kimi-code.md
  • docs/pricing.md
  • docs/upstream/2026-06-22.md
  • docs/upstream/2026-07-10.md
💤 Files with no reviewable changes (2)
  • docs/adr/0011-token-derived-local-cost.md
  • docs/adr/0021-isolated-source-failure-domains.md

Comment thread crates/tokscale-core/src/sessions/kimi.rs Outdated
Comment thread docs/clients.md Outdated
@codspeed-hq

codspeed-hq Bot commented Jul 18, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 27 untouched benchmarks


Comparing codex/fix-provider-independent-usage (251814a) with personal/local-clients (a9ba64e)

Open in CodSpeed

@makoMakoGo

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04544b4855

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tokscale-core/src/adapters/file.rs Outdated
Comment thread crates/tokscale-core/src/provider_identity.rs
Comment thread crates/tokscale-core/src/adapters/file.rs
Represent unavailable optional related inputs in source snapshots so inventory preparation and refresh retain the primary source. Force a partial uncached scan and invalidate stale shards, while required and primary input failures remain unavailable.
@makoMakoGo
makoMakoGo merged commit 513278c into personal/local-clients Jul 18, 2026
8 checks passed
@makoMakoGo
makoMakoGo deleted the codex/fix-provider-independent-usage branch July 18, 2026 11:20
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant