fix(search): Cindy AI 搜索把余额耗尽(429 + ExceededBudget)误报为限流,改用共享额度判定并给充值引导 - #4026
Conversation
|
| Filename | Overview |
|---|---|
| apps/desktop/src/main/mcp-integrations/cindyProxySearch.ts | 调整 429 额度耗尽分类和提示文案,并新增响应体诊断摘要;摘要记录任意上游正文带来非标准敏感内容落盘风险。 |
| apps/desktop/src/main/mcp-integrations/tests/cindyProxySearch.test.ts | 覆盖预算耗尽、普通限流、充值文案以及已知 principal/密钥格式的日志脱敏与长度限制。 |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[搜索上游返回非 2xx] --> B{HTTP 状态}
B -->|401 / 403| C[AUTH_REJECTED]
B -->|429| D{正文命中确定性额度耗尽信号?}
D -->|是| E[QUOTA_EXHAUSTED<br/>提示充值或切换渠道]
D -->|否| F[RATE_LIMITED<br/>提示稍后重试]
B -->|其他状态| G{402 或宽松额度措辞?}
G -->|是| E
G -->|否| H[按状态映射其他错误]
A --> I[生成脱敏且最长 160 字符的 bodyDigest]
I --> J[写入本机诊断日志]
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/main/mcp-integrations/cindyProxySearch.ts:431
**响应正文可能写入日志**
如果上游错误响应回显用户查询、使用非标准字段名携带凭证,或包含其他敏感内容,通用脱敏器可能无法识别这些数据。此处会将它们原样保留在 `bodyDigest` 的前 160 个字符中,并写入本机日志。当前测试只覆盖 `aigw:` principal 和 `sk-` 密钥;建议仅记录允许名单中的结构化诊断字段,例如错误码、`spend` 和 `budget`,而不是记录任意响应正文。
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(search): Cindy AI 搜索把余额耗尽(429 + Exce..." | Re-trigger Greptile
MagicLizi
left a comment
There was a problem hiding this comment.
安全与隐私门未通过:发现疑似真实 API key(类型 sk-api-key),不能合入。
请处理:
apps/desktop/src/main/mcp-integrations/__tests__/cindyProxySearch.test.ts:364—sk-api-keyapps/desktop/src/main/mcp-integrations/__tests__/cindyProxySearch.test.ts:398—sk-api-key
要求:
- 从分支历史中彻底移除这些内容(只追加一个删除 commit 不够,泄露内容仍留在可达历史里)
- 立即轮换已出现在远端的凭证——推到 GitHub 即视为已泄露
- 测试请改用明显占位符 / mock,不要再放真实或仿真可调用的 key
本条为 P0,修完并清理历史后再请求审查。
…引导 (makecindy#4024) cindyProxySearch.classifyHttpFailure 自维护了一份宽松额度正则,而网关预算闸 实际以 HTTP 429 + ExceededBudget 拒绝,正则无一命中,落入 429 分支归为 RATE_LIMITED,用户被引导「稍后再试」但永远不会恢复。 改为复用 @cindy/maker-shared 的 matchesDeterministicUsageExhaustionText (与对话 Error Banner / 终端限流重试同一 SSoT):429 只认严格额度信号, 非 429 保留原宽松措辞;额度耗尽文案明确「余额不足,请充值后再试」并保留 BYO 渠道提示。 拒绝日志新增允许名单式的结构化正文摘要(review):只从 JSON 正文抽取短标识 形态的 error/code/type 与数值 spend/budget,其余只记 json/length;非 JSON 正文只记长度,不落盘任意上游正文。测试用的凭证占位符不使用密钥形态。 Fixes makecindy#4024 Signed-off-by: ficowang <fico@xd.com>
98f7d9d to
5cd1ddb
Compare
|
@MagicLizi 安全门已处理(head 5cd1ddb):
请重新跑安全门与审查。 |
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
代码重审通过:当前 head 未发现 P0/P1。429+ExceededBudget 按共享额度判定为余额耗尽并给充值引导,普通限流不升级;日志只记允许名单摘要。
|
网关把余额耗尽和瞬时限流挤在同一个 429 里,这次终于拆开了:该充值的会看到充值,该等一会儿的不会被赶去付钱。日志也只留允许名单,不把查询和身份写进去。 |
这次改了什么
摘要
Cindy AI 余额耗尽时,Web Search 插件的搜索调用被归类为
RATE_LIMITED,用户看到「请求过于频繁,请稍后再试」——但实际是余额为 0,按提示等待永远不会恢复,也不指向充值;同一客户端的对话链路对同一网关错误却能正确显示「余额不足,请充值」。根因:
apps/desktop/src/main/mcp-integrations/cindyProxySearch.ts的classifyHttpFailure自维护了一份宽松额度正则(quota|credit|balance|insufficient|exhausted|spend limit),而网关预算闸的实际响应形态是 HTTP 429 +ExceededBudget(仓内errorRedaction.test.ts/terminal-rate-limit-retry.test.ts均以此为样本),正则无一命中,于是落入status === 429分支。本 PR 让搜索链路复用仓库已有的 SSoT
matchesDeterministicUsageExhaustionText(@cindy/maker-shared/error-redaction,对话 Error Banner、终端限流重试、providerErrors已在用):HTTP 429 只认该严格信号(ExceededBudget/budget_exceeded等)→QUOTA_EXHAUSTED;非 429 状态保留原宽松措辞与 402;普通 429(rate limit/Too Many Requests,即便正文带credits refill之类措辞)仍为RATE_LIMITED。额度耗尽文案改为「Cindy AI 余额不足,请充值后再试,或在插件设置中改用自己的搜索渠道」。非 2xx 的拒绝日志新增bodyDigest:经redactSensitiveText脱敏(凭证、aigw:principal)后压成单行并截断到 160 字,只进本机诊断日志,不回传插件/用户。变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
cindyProxySearch.ts的分类顺序与文案、脱敏响应体摘要日志;cindyProxySearch.test.ts新增/扩展用例。errorCode+message,是否新增入口按 dash-s-cindy 的意见留作单独产品/API 决策);cindySlot的 binding 消费与重试语义(未触碰)。QUOTA_EXHAUSTED与「余额不足,请充值后再试」提示,不再误导为限流。CindyProxySearchErrorCode枚举不变,仅 429 + 明确额度信号的归类从RATE_LIMITED改为既有的QUOTA_EXHAUSTED。UI 变化
mcp-integrations的错误分类、文案字符串与日志,无 renderer、布局、样式改动;提示文案经插件原有 message 通道展示,不新增界面元素。怎么验证的
自动验证
手工验证
未在真实余额为 0 的账号上端到端复测(本机账号有余额)。分类逻辑以 issue 中的真实网关日志形态(429、无 requestId、百毫秒级延迟)与仓内
ExceededBudget测试样本为准。未执行的验证
message,无 UI 改动)。风险
风险分类
影响与回滚
cindy/web-search)的 HTTP 非 2xx 分类与拒绝日志;Brave / Tavily BYO 路径不经此函数。ExceededBudget/budget_exceeded/insufficient quota等明确措辞的额度拒绝仍会归为限流(与修复前一致,未变差);带明确措辞的瞬时限流理论上可能被判为额度耗尽,但共享判定的注释与既有消费方(Error Banner / 终端重试)已按此口径运行,风险与它们同级。bodyDigest经共享脱敏后截断,与mediaRequestLog等既有用法同一函数;不含 query(query 不在响应体中)与 Authorization。