fix(web): consume provider_capability telemetry silently (refs #939 part A)#943
Conversation
…2653#939 part A) When kimi-cli (and future providers) emit system_info with `type: provider_capability`, the chat dispatch chain had no specific branch. The message fell through to the default render path, displaying the raw JSON as a system bubble — the user saw "thinking → unavailable" as if it were an error. This mirrors the F210-H1 pattern (agy_trajectory_progress): consume the telemetry silently and store it on the invocation snapshot for any future UI surface that wants to show capability status. Changes: - Add ProviderCapabilityReport type + providerCapabilities field on CatInvocationInfo (chat-types.ts). - Dispatch branch for type === 'provider_capability' that read-merges into invocation.providerCapabilities and marks the message consumed (no addMessage). - 5-case vitest suite covering: silent consumption, multi-cap merge, latest-wins, status coercion. Part of the 3-way split for zts212653#939 (sub-issues A/B/C): - C: PR zts212653#942 (kimi auth dual-path) — merged. - B: caller-attribution for unrecognised errors — TBD. - A: this PR (telemetry misrendered as error).
|
Thanks for taking the front-end Part A. First-pass inbound gate from our side:
Next pass will verify the current head against the Part A contract: provider_capability is consumed only as system_info telemetry, real error events still render, invocation snapshot merging preserves existing fields/multiple capabilities, and the targeted useAgentMessages tests plus the relevant hook test family pass. [砚砚/gpt-5.5🐾] |
zts212653
left a comment
There was a problem hiding this comment.
Code review pass for the Part A implementation at 7057a29c.
What I verified:
provider_capabilityis consumed only as system telemetry and no longer falls through toaddMessage.- Real
system_infopayloads that are notprovider_capabilitykeep the existing rendering path. - Multiple capabilities for the same cat are read-merge-written into
providerCapabilitieswithout clobbering each other. parsed.catId ?? msg.catIdmatches nearby telemetry handler patterns.
Local verification in an isolated worktree:
cd packages/web
node node_modules/vitest/vitest.mjs run src/hooks/__tests__/useAgentMessages-provider-capability.test.tsx
# 5 tests passed
node node_modules/vitest/vitest.mjs run src/hooks/__tests__/useAgentMessages-*.test.ts*
# 24 files / 276 tests passedThis is still not merge-gateable until the PR title/body stop using closing keywords for the umbrella issue. Please change fixes #939 / Closes #939 to Refs #939 or Part of #939, and update the status table entry that says #942 is merged. After that wording fix, I do not see a code blocker for this PR.
[砚砚/gpt-5.5🐾]
zts212653
left a comment
There was a problem hiding this comment.
Approving — second pass after the maintainer wording cleanup + branch update.
Verification:
- Code review pass for the Part A implementation at
7057a29cwas completed in my earlier comment chain (砚砚/gpt-5.5 review at #943 (review)... —provider_capabilityconsumed only as system telemetry, multiple capabilities merged without clobbering, parsed.catId resolution matches existing patterns, useAgentMessages-* family 24 files / 276 tests pass). - Commit chain since:
7057a29c(initial, reviewed) →9a700196(merge from main by author) →9b8a621c(merge from main via maintainer update-branch). No code delta since the reviewed SHA — both intermediate commits are pure main-integration merge commits. - Title/body wording cleanup at this iteration:
fixes #939 part A→refs #939 part A(avoids premature umbrella close), and the status table line that incorrectly said✅ PR #942 (merged)is now🔄 PR #942 (open, CI red, awaiting fix)— the only PR in the cluster actually merged so far is #944 (Kimi CLI binary fallback, today).
CI on 9b8a621c is currently blocked on the first-time-contributor workflow approval (CI + Windows Smoke). Approving the runs now. Will squash-merge once CI passes.
[宪宪/opus-4.7🐾]
…653#939 part A) (zts212653#943) Refs zts212653#939 (part A only). The umbrella issue zts212653#939 stays open until parts B and C are also addressed. Inbound review chain (community PR by @enihcam, FIRST_TIME_CONTRIBUTOR; self-review API blocks formal state on shared maintainer account so comments are the trail): - 砚砚/gpt-5.5 code review pass on 7057a29 — provider_capability consumed only as system telemetry, multiple capabilities merge without clobbering, parsed.catId resolution matches existing patterns, useAgentMessages-* family 24 files / 276 tests pass - 宪宪/opus-4.7 second-pass APPROVED on 9b8a621 — metadata wording cleanup (fixes zts212653#939 → refs zts212653#939; status table corrected — zts212653#944 not zts212653#942 is the merged member of the zts212653#939 cluster); no code delta since 7057a29 (newer commits are pure merge-from-main commits) CI 5/5 pass: Build / Lint / Test (Public) / Test (Windows) / Directory Size Guard. Opensource-ops B Patch self-merge: 4 conditions all met (accepted zts212653#939, safe-cherry-pick scope, CI 5/5 green, no toolchain/security impact — web frontend telemetry rendering only). Thanks @enihcam for the careful F210-H1 pattern reuse and the targeted 5-case test file. Co-authored-by: enihcam <enihcam@users.noreply.github.com>
zts212653#991 — drift-resolve sync skips new skills due to preserveGlobalCascade. The condition in updateConfigAfterSync incorrectly skipped ALL skills without local policy, including newly discovered ones. Add existingProjectSkills guard so only skills already in the project config are eligible for the cascade-preserve skip. zts212653#966 — provider_capability missing in background dispatch chain. PR zts212653#943 added the foreground handler for provider_capability system_info but missed the background mirror in consumeBackgroundSystemInfo. Kimi invocations running through background callbacks (A2A handoffs, unviewed threads) still surfaced raw-JSON "thinking → unavailable" bubbles. Add the matching background handler following the F210-H1 dual-handler pattern. Skill tab UI — sync status and batch toggle on the same line. The "✓ Skill 同步一致" text and the batch enable/disable toggle were on separate lines with redundant label text. Combine them into one flex row (sync status left, toggle right) and unify the element order between the global and project tabs so the project tab matches the global layout (only adding the project selector dropdown). Closes zts212653#991 Closes zts212653#966 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The condition in updateConfigAfterSync incorrectly skipped ALL skills without local policy, including newly discovered ones. Add existingProjectSkills guard so only skills already in the project config are eligible for the cascade-preserve skip. PR #943 added the foreground handler for provider_capability system_info but missed the background mirror in consumeBackgroundSystemInfo. Kimi invocations running through background callbacks (A2A handoffs, unviewed threads) still surfaced raw-JSON "thinking → unavailable" bubbles. Add the matching background handler following the F210-H1 dual-handler pattern. Skill tab UI — sync status and batch toggle on the same line. The "✓ Skill 同步一致" text and the batch enable/disable toggle were on separate lines with redundant label text. Combine them into one flex row (sync status left, toggle right) and unify the element order between the global and project tabs so the project tab matches the global layout (only adding the project selector dropdown). Closes #991 Closes #966 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The condition in updateConfigAfterSync incorrectly skipped ALL skills without local policy, including newly discovered ones. Add existingProjectSkills guard so only skills already in the project config are eligible for the cascade-preserve skip. PR #943 added the foreground handler for provider_capability system_info but missed the background mirror in consumeBackgroundSystemInfo. Kimi invocations running through background callbacks (A2A handoffs, unviewed threads) still surfaced raw-JSON "thinking → unavailable" bubbles. Add the matching background handler following the F210-H1 dual-handler pattern. Skill tab UI — sync status and batch toggle on the same line. The "✓ Skill 同步一致" text and the batch enable/disable toggle were on separate lines with redundant label text. Combine them into one flex row (sync status left, toggle right) and unify the element order between the global and project tabs so the project tab matches the global layout (only adding the project selector dropdown). Closes #991 Closes #966 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…stency (#993) * fix: batch fix #991 + #966 + Skill tab UI consistency The condition in updateConfigAfterSync incorrectly skipped ALL skills without local policy, including newly discovered ones. Add existingProjectSkills guard so only skills already in the project config are eligible for the cascade-preserve skip. PR #943 added the foreground handler for provider_capability system_info but missed the background mirror in consumeBackgroundSystemInfo. Kimi invocations running through background callbacks (A2A handoffs, unviewed threads) still surfaced raw-JSON "thinking → unavailable" bubbles. Add the matching background handler following the F210-H1 dual-handler pattern. Skill tab UI — sync status and batch toggle on the same line. The "✓ Skill 同步一致" text and the batch enable/disable toggle were on separate lines with redundant label text. Combine them into one flex row (sync status left, toggle right) and unify the element order between the global and project tabs so the project tab matches the global layout (only adding the project selector dropdown). Closes #991 Closes #966 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(#991): cascade-safe new skill registration + #966 background tests P1 fix: Restore original preserveGlobalCascade condition for ALL inherited-only skills (not just existing ones). New skills are collected into cascadeNewSkills and registered in capabilities.json WITHOUT mountPaths — so resolveEffectiveSkillMountPaths falls through to global policy, preserving #962 cascade intent. mount-rules-route.test.js 23/23. P2 fix: Add 4 background regression tests for #966 provider_capability handler in consumeBackgroundSystemInfo: - consumed=true, no addMessageToThread (no raw JSON bubble) - Multi-capability merge without clobbering (read-merge-write) - Unknown status coerces to 'unavailable' - Empty-string catId fallback via || (msg.catId used) Closes #991 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(#995): connector plugin routes use allowMissingOwner for single-user mode requirePluginWriteAccess and requirePluginListAccess used requireConfiguredOwner: true, which blocked IM connector install/list in local single-user mode (no DEFAULT_OWNER_USER_ID). Changed to allowMissingOwner: true — consistent with plugin-routes.ts and the unified owner gate pattern from #794. Closes #995 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(#995): flip connector plugin auth tests for allowMissingOwner Old tests asserted 403 when DEFAULT_OWNER_USER_ID was unset — encoding the regression behavior. New tests assert pass-through: install reaches file validation (400 No file uploaded), list returns 200 with plugin data. Existing coverage for session-auth, same-origin, cross-origin, and configured non-owner rejection is preserved (13 other tests unchanged). Red→Green: 15/15 pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve pre-existing brand guard violations + orphaned F207 ROADMAP ref - Remove F207 row from ROADMAP (feature doc deleted for PII in #988, ROADMAP reference left behind → check:features failure on every branch) - Port upstream brand strings to fork values: "Clowder AI" → "Cat Café" in layout.tsx, SplitPaneView.tsx, manifest.json, ChatContainerHeader.tsx, api-client.ts comment - Fix connector-gateway-bootstrap.ts frontend port fallback: 3003 → 3001 (fork uses 3001, upstream uses 3003) - Fix brand expectation typo in intake-from-opensource.sh: must_contain was checking for 3003 instead of 3001 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add missing check:biome-version script + JSDoc for owner gate pattern Two pre-existing gaps resolved: 1. package.json: add check:biome-version script referenced by .githooks/pre-commit (introduced in sync #956 but never added to upstream package.json, breaking local commits). 2. capability-write-guards.ts: promote inline comments to JSDoc on requireCapabilityWriteOwner, documenting the #794 unified owner gate pattern (allowMissingOwner for writes vs requireConfiguredOwner for data-visibility). Prevents future recurrence of #995. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(#992): recover stale ACP lease on session re-acquire instead of throwing On Windows, closing the console during an active ACP prompt leaves the child process alive but the lease unreleased (async generator finally block never runs). The next acquire with the same sessionId hit "already active on its owning process" and blocked forever. Fix: when acquire() finds a session-owned entry with leaseCount > 0 on a non-multiplexing carrier, force-release the orphaned lease instead of throwing. This is safe because the same sessionId being re-acquired proves the previous consumer is gone — the lease is a zombie. Red→Green: new test simulates the zombie scenario (acquire + remember session + skip release + re-acquire same sessionId). 24/24 pool tests pass. Closes #992 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(#992): add lease generation guard against late stale release Review P1 from @codex: the force-release path reset leaseCount but the old lease's release() closure still held a reference to the same entry. A late-arriving release (async generator finally) would decrement the new lease's count, triggering premature idle eviction. Fix: add leaseGeneration counter to PoolEntry. createLease captures the current generation at creation time; release() checks for mismatch and becomes a no-op if the generation has been bumped by a force-release. Also properly transitions through idle state in the force-release path so idleProcessCount stays balanced. Red→Green: new test simulates late release after stale recovery — verifies metrics stay non-negative, new lease survives idle TTL, and normal release still works. 25/25 pool tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(#794): add requireLocalCapabilityWriteRequest to connector-plugins The connector-plugins routes were missing layer 1 (loopback guard) of the #794 three-layer security pattern. Both requirePluginWriteAccess and requirePluginListAccess now match the reference implementation in plugin-routes.ts: loopback guard → session auth → owner gate. Tests updated to reflect the tightened security boundary: - Remote-IP tests now expect 403 (loopback rejection) - Cross-origin tests match the loopback guard error - List endpoint tests provide loopback-valid origin headers - Two new tests verify proxy-forwarded loopback rejection (X-Forwarded-For) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * revert(brand): rollback user-visible brand strings from 2eeb332 Reverts the brand changes from commit 2eeb332 that incorrectly replaced "Clowder AI" with "Cat Café" in the clowder-ai repo. Per maintainer review on PR #993, the correct brand mapping is: cat-cafe repo → "Cat Café", clowder-ai repo → "Clowder AI". Reverted files: manifest.json, layout.tsx, ChatContainerHeader.tsx, SplitPaneView.tsx, api-client.ts, connector-gateway-bootstrap.ts. Also disables conflicting BRAND_EXPECTATIONS entries in intake-from-opensource.sh that enforced cat-cafe brand terms in the clowder-ai repo (mirrored verbatim without per-repo parameterization), and fixes a bug in the Phase 2 brand guard skip logic where `echo "${array[*]}"` joined all entries on one line, causing the `^` anchor to only match the first array element. Brand guard parameterization tracked for a separate follow-up PR. [宪宪/claude-opus-4-6🐾] * fix(#1002): deliver maintainer PR reviews instead of silently dropping them ReviewFeedbackTaskSpec applied decideDelivery() from community-delivery-policy, which silences OWNER/MEMBER activity — correct for Repo Inbox (F168) where own team's activity is noise, but wrong for PR review tracking where the cat explicitly registered to receive ALL reviewer feedback including maintainers. Remove decideDelivery() calls from both comment and review filtering paths. The existing isEchoComment + isNoiseComment + isEchoReview filters are sufficient — they correctly filter self-authored echoes without silencing maintainer reviews. Closes #1002 [宪宪/claude-opus-4-6🐾] * test(#1002): fix thread-rotation test for OWNER delivery change Update review-feedback-thread-rotation test to expect OWNER comments in newComments (no longer filtered after #1002 decideDelivery removal). The routing audit behavior is unchanged — OWNER feedback is now delivered alongside it. [宪宪/claude-opus-4-6🐾] * fix(brand-guard): align test with disabled 3003 port expectation The BRAND_EXPECTATIONS entry for connector-gateway-bootstrap.ts was disabled in this PR (3003 is the correct public frontend port for the clowder-ai repo, not cat-cafe contamination). The test still asserted 3003 should be flagged — flip it to assert brand guard now allows it. Addresses codex P2 review finding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Lysander Su <773678591@qq.com>
…653#939 part A) (zts212653#943) Refs zts212653#939 (part A only). The umbrella issue zts212653#939 stays open until parts B and C are also addressed. Inbound review chain (community PR by @enihcam, FIRST_TIME_CONTRIBUTOR; self-review API blocks formal state on shared maintainer account so comments are the trail): - 砚砚/gpt-5.5 code review pass on 7057a29 — provider_capability consumed only as system telemetry, multiple capabilities merge without clobbering, parsed.catId resolution matches existing patterns, useAgentMessages-* family 24 files / 276 tests pass - 宪宪/opus-4.7 second-pass APPROVED on 9b8a621 — metadata wording cleanup (fixes zts212653#939 → refs zts212653#939; status table corrected — zts212653#944 not zts212653#942 is the merged member of the zts212653#939 cluster); no code delta since 7057a29 (newer commits are pure merge-from-main commits) CI 5/5 pass: Build / Lint / Test (Public) / Test (Windows) / Directory Size Guard. Opensource-ops B Patch self-merge: 4 conditions all met (accepted zts212653#939, safe-cherry-pick scope, CI 5/5 green, no toolchain/security impact — web frontend telemetry rendering only). Thanks @enihcam for the careful F210-H1 pattern reuse and the targeted 5-case test file. Co-authored-by: enihcam <enihcam@users.noreply.github.com>
…653#995 + zts212653#1002 + Skill tab UI consistency (zts212653#993) * fix: batch fix zts212653#991 + zts212653#966 + Skill tab UI consistency The condition in updateConfigAfterSync incorrectly skipped ALL skills without local policy, including newly discovered ones. Add existingProjectSkills guard so only skills already in the project config are eligible for the cascade-preserve skip. PR zts212653#943 added the foreground handler for provider_capability system_info but missed the background mirror in consumeBackgroundSystemInfo. Kimi invocations running through background callbacks (A2A handoffs, unviewed threads) still surfaced raw-JSON "thinking → unavailable" bubbles. Add the matching background handler following the F210-H1 dual-handler pattern. Skill tab UI — sync status and batch toggle on the same line. The "✓ Skill 同步一致" text and the batch enable/disable toggle were on separate lines with redundant label text. Combine them into one flex row (sync status left, toggle right) and unify the element order between the global and project tabs so the project tab matches the global layout (only adding the project selector dropdown). Closes zts212653#991 Closes zts212653#966 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(zts212653#991): cascade-safe new skill registration + zts212653#966 background tests P1 fix: Restore original preserveGlobalCascade condition for ALL inherited-only skills (not just existing ones). New skills are collected into cascadeNewSkills and registered in capabilities.json WITHOUT mountPaths — so resolveEffectiveSkillMountPaths falls through to global policy, preserving zts212653#962 cascade intent. mount-rules-route.test.js 23/23. P2 fix: Add 4 background regression tests for zts212653#966 provider_capability handler in consumeBackgroundSystemInfo: - consumed=true, no addMessageToThread (no raw JSON bubble) - Multi-capability merge without clobbering (read-merge-write) - Unknown status coerces to 'unavailable' - Empty-string catId fallback via || (msg.catId used) Closes zts212653#991 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(zts212653#995): connector plugin routes use allowMissingOwner for single-user mode requirePluginWriteAccess and requirePluginListAccess used requireConfiguredOwner: true, which blocked IM connector install/list in local single-user mode (no DEFAULT_OWNER_USER_ID). Changed to allowMissingOwner: true — consistent with plugin-routes.ts and the unified owner gate pattern from zts212653#794. Closes zts212653#995 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(zts212653#995): flip connector plugin auth tests for allowMissingOwner Old tests asserted 403 when DEFAULT_OWNER_USER_ID was unset — encoding the regression behavior. New tests assert pass-through: install reaches file validation (400 No file uploaded), list returns 200 with plugin data. Existing coverage for session-auth, same-origin, cross-origin, and configured non-owner rejection is preserved (13 other tests unchanged). Red→Green: 15/15 pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve pre-existing brand guard violations + orphaned F207 ROADMAP ref - Remove F207 row from ROADMAP (feature doc deleted for PII in zts212653#988, ROADMAP reference left behind → check:features failure on every branch) - Port upstream brand strings to fork values: "Clowder AI" → "Cat Café" in layout.tsx, SplitPaneView.tsx, manifest.json, ChatContainerHeader.tsx, api-client.ts comment - Fix connector-gateway-bootstrap.ts frontend port fallback: 3003 → 3001 (fork uses 3001, upstream uses 3003) - Fix brand expectation typo in intake-from-opensource.sh: must_contain was checking for 3003 instead of 3001 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add missing check:biome-version script + JSDoc for owner gate pattern Two pre-existing gaps resolved: 1. package.json: add check:biome-version script referenced by .githooks/pre-commit (introduced in sync zts212653#956 but never added to upstream package.json, breaking local commits). 2. capability-write-guards.ts: promote inline comments to JSDoc on requireCapabilityWriteOwner, documenting the zts212653#794 unified owner gate pattern (allowMissingOwner for writes vs requireConfiguredOwner for data-visibility). Prevents future recurrence of zts212653#995. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(zts212653#992): recover stale ACP lease on session re-acquire instead of throwing On Windows, closing the console during an active ACP prompt leaves the child process alive but the lease unreleased (async generator finally block never runs). The next acquire with the same sessionId hit "already active on its owning process" and blocked forever. Fix: when acquire() finds a session-owned entry with leaseCount > 0 on a non-multiplexing carrier, force-release the orphaned lease instead of throwing. This is safe because the same sessionId being re-acquired proves the previous consumer is gone — the lease is a zombie. Red→Green: new test simulates the zombie scenario (acquire + remember session + skip release + re-acquire same sessionId). 24/24 pool tests pass. Closes zts212653#992 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(zts212653#992): add lease generation guard against late stale release Review P1 from @codex: the force-release path reset leaseCount but the old lease's release() closure still held a reference to the same entry. A late-arriving release (async generator finally) would decrement the new lease's count, triggering premature idle eviction. Fix: add leaseGeneration counter to PoolEntry. createLease captures the current generation at creation time; release() checks for mismatch and becomes a no-op if the generation has been bumped by a force-release. Also properly transitions through idle state in the force-release path so idleProcessCount stays balanced. Red→Green: new test simulates late release after stale recovery — verifies metrics stay non-negative, new lease survives idle TTL, and normal release still works. 25/25 pool tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(zts212653#794): add requireLocalCapabilityWriteRequest to connector-plugins The connector-plugins routes were missing layer 1 (loopback guard) of the zts212653#794 three-layer security pattern. Both requirePluginWriteAccess and requirePluginListAccess now match the reference implementation in plugin-routes.ts: loopback guard → session auth → owner gate. Tests updated to reflect the tightened security boundary: - Remote-IP tests now expect 403 (loopback rejection) - Cross-origin tests match the loopback guard error - List endpoint tests provide loopback-valid origin headers - Two new tests verify proxy-forwarded loopback rejection (X-Forwarded-For) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * revert(brand): rollback user-visible brand strings from 2eeb332 Reverts the brand changes from commit 2eeb332 that incorrectly replaced "Clowder AI" with "Cat Café" in the clowder-ai repo. Per maintainer review on PR zts212653#993, the correct brand mapping is: cat-cafe repo → "Cat Café", clowder-ai repo → "Clowder AI". Reverted files: manifest.json, layout.tsx, ChatContainerHeader.tsx, SplitPaneView.tsx, api-client.ts, connector-gateway-bootstrap.ts. Also disables conflicting BRAND_EXPECTATIONS entries in intake-from-opensource.sh that enforced cat-cafe brand terms in the clowder-ai repo (mirrored verbatim without per-repo parameterization), and fixes a bug in the Phase 2 brand guard skip logic where `echo "${array[*]}"` joined all entries on one line, causing the `^` anchor to only match the first array element. Brand guard parameterization tracked for a separate follow-up PR. [宪宪/claude-opus-4-6🐾] * fix(zts212653#1002): deliver maintainer PR reviews instead of silently dropping them ReviewFeedbackTaskSpec applied decideDelivery() from community-delivery-policy, which silences OWNER/MEMBER activity — correct for Repo Inbox (F168) where own team's activity is noise, but wrong for PR review tracking where the cat explicitly registered to receive ALL reviewer feedback including maintainers. Remove decideDelivery() calls from both comment and review filtering paths. The existing isEchoComment + isNoiseComment + isEchoReview filters are sufficient — they correctly filter self-authored echoes without silencing maintainer reviews. Closes zts212653#1002 [宪宪/claude-opus-4-6🐾] * test(zts212653#1002): fix thread-rotation test for OWNER delivery change Update review-feedback-thread-rotation test to expect OWNER comments in newComments (no longer filtered after zts212653#1002 decideDelivery removal). The routing audit behavior is unchanged — OWNER feedback is now delivered alongside it. [宪宪/claude-opus-4-6🐾] * fix(brand-guard): align test with disabled 3003 port expectation The BRAND_EXPECTATIONS entry for connector-gateway-bootstrap.ts was disabled in this PR (3003 is the correct public frontend port for the clowder-ai repo, not cat-cafe contamination). The test still asserted 3003 should be flagged — flip it to assert brand guard now allows it. Addresses codex P2 review finding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Lysander Su <773678591@qq.com>
Summary
When
kimi-cli(and future providers) emitsystem_infowithtype: provider_capability, the chat dispatch chain had no specific branch for this telemetry. The message fell through to the default render path, displaying the raw JSON as a system bubble — the user saw"thinking → unavailable"as if it were an error.This PR is the part A of the 3-way split for #939 (kimi auth dual-path + telemetry/UX fixups). It mirrors the F210-H1 pattern (
agy_trajectory_progress): consume the telemetry silently and store it on the invocation snapshot for any future UI surface that wants to surface capability status.Three-way split for #939
CAT_CAFE_KIMI_API_KEY/CAT_CAFE_KIMI_OAUTH_TOKEN/ native credential file)未识别的CLI错误)provider_capabilitymisrendered as errorChanges
packages/web/src/stores/chat-types.ts(+18 lines)ProviderCapabilityReporttype (status,reason,provider,receivedAt)providerCapabilities?: Record<string, ProviderCapabilityReport>field onCatInvocationInfopackages/web/src/hooks/useAgentMessages.ts(+30 lines)parsed.type === 'provider_capability'(placed afteragy_trajectory_progress)invocation.providerCapabilitiesso multiple capabilities coexist and later reports replace earlier ones (latest-wins)consumed = true→ noaddMessage→ no user-visible bubblestatus→'unavailable'; missing fields →'unknown'/''packages/web/src/hooks/__tests__/useAgentMessages-provider-capability.test.tsx(+274 lines, new file)kimi thinking: unavailable→ noaddMessage,setCatInvocationcalled withproviderCapabilities.thinkingimage_input: limited→ noaddMessage, snapshot stored underimage_input'unavailable'rather than rendering a bubbleTest results
Biome lint
What this does NOT do
KimiAgentService.tsalready emitsprovider_capabilitycorrectly — line 321-338 forimage_input, line 402-418 forthinking).Reviewer checklist
parsed.catId ?? msg.catIdresolution matches existing patterns (agy-progress branch).useChatStore.getState()is correct (the existingagy_trajectory_progressbranch also usesuseChatStore.getState().catInvocations?.[catId]?...).Date.now()forreceivedAtis acceptable for an in-memory snapshot (no clock skew concerns).Test plan for reviewer
cd packages/web node node_modules/vitest/vitest.mjs run src/hooks/__tests__/useAgentMessages-provider-capability.test.tsxRefs #939 (part A only). The umbrella issue #939 stays open until parts B and C are also addressed.
Maintainer note (2026-06-17): the status table below incorrectly listed PR #942 as merged; in reality #942 is still open with red CI. PR #944 (Kimi CLI binary fallback) is the only #939-cluster PR merged so far. Closing keyword in title/body changed from
fixestorefsso #939 does not auto-close on this part-A merge.