Skip to content

fix: 限制联网搜索重试并恢复 Chat 复制 - #164

Merged
wangkailang merged 2 commits into
mainfrom
codex/web-search-guard-chat-clipboard
Jul 31, 2026
Merged

fix: 限制联网搜索重试并恢复 Chat 复制#164
wangkailang merged 2 commits into
mainfrom
codex/web-search-guard-chat-clipboard

Conversation

@wangkailang

Copy link
Copy Markdown
Owner

改动概览

联网搜索 P0

  • Tavily 的相对时间范围与绝对日期参数互斥,避免同时发送 time_rangestart_date / end_date 导致 400。
  • 将缺少凭据、HTTP 错误和网络错误转换为结构化的 successretryablestatushint 结果。
  • 仅对网络异常、408、429 和 5xx 执行一次内部短重试;4xx 参数错误不再盲目重试。
  • 增加单次运行级保护:最多 4 次搜索;重复同一失败调用或连续失败 2 次后,熔断本次运行的联网搜索。

联网搜索 P1

  • 将搜索错误、状态码、可重试性和处理建议投影到模型上下文。
  • 熔断后从后续 step 的可用工具中移除 webSearch,引导模型基于已有证据继续或说明限制。
  • 补充搜索工具、运行级保护以及主 Chat 接线的回归测试。

Chat 复制

  • 通过受信任的 preload 暴露 Electron 原生系统剪贴板写入能力,不放宽浏览器 guest 的 deny-by-default 权限策略。
  • Chat 消息和 Markdown 代码块统一使用原生剪贴板桥接。
  • 仅在实际写入成功后展示“已复制”,并补充消息及代码块复制回归测试。

验证

  • pnpm lint:通过
  • pnpm typecheck:通过
  • pnpm test:382 个测试文件、3546 项测试通过
  • pnpm build:通过

- make Tavily date filters mutually exclusive, expose structured retryability, and retry transient failures once

- add a per-run web-search call budget, duplicate-failure detection, and consecutive-failure circuit breaker

- project search failures into model-visible guidance so the agent stops repeating invalid calls

- route message and Markdown code copying through the trusted native preload clipboard bridge

- add regression coverage for search guarding, main-chat wiring, and clipboard behavior
Copilot AI review requested due to automatic review settings July 31, 2026 06:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

该 PR 主要聚焦两条主线:一是让 Tavily webSearch 的失败/重试行为更可控(结构化失败结果、仅一次短重试、单次运行级熔断与工具移除);二是恢复 Chat 与代码块复制能力(通过受信任的 preload 桥接到 Electron 原生剪贴板,而不是依赖可能被 guest 权限策略拦截的 Web Clipboard API)。

Changes:

  • webSearch:避免相对时间参数与绝对日期参数同时下发;将网络/HTTP/缺少凭据等失败转换为结构化输出,并仅对可重试场景执行一次内部短重试。
  • 主 Chat 路径:接入单次运行级 WebSearchRunGuard 熔断(预算上限、重复失败调用拦截、连续失败熔断),并将“工具可用性/提示”投影到 step policy。
  • Chat/Markdown 复制:统一改为 window.filework.clipboard.writeText preload 桥接,并补充对应回归测试。

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/renderer/components/chat/ChatPanel.tsx Chat 消息复制改为走 preload 剪贴板桥接,并在失败时记录 warn。
src/renderer/components/chat/tests/ChatPanel.rendering.test.tsx 覆盖“消息复制走 preload 而非 navigator.clipboard”的回归测试。
src/renderer/components/ai-elements/markdown-code-block.tsx 代码块复制改为走 preload 剪贴板桥接。
src/renderer/components/ai-elements/tests/markdown-code-block.test.tsx 新增代码块复制走 preload 的测试。
src/preload/index.ts window.filework 暴露 clipboard.writeText,桥接到 Electron clipboard
src/main/ipc/ai-handlers.ts 主 chat 执行链路接入 WebSearchRunGuard:beforeAnyToolCall 门控 + onToolResult 观测 + step policy。
src/main/ipc/tests/ai-handlers-media-runtime.test.ts 新增测试验证 run guard 在主 chat 的接线与熔断后的 activeTools 调整。
src/main/core/agent/tools/web-search.ts Tavily 请求参数互斥处理、结构化错误输出、一次内部短重试与可重试性标注。
src/main/core/agent/tools/model-output.ts 将 webSearch 的结构化失败信息(error/status/retryable/hint)投影进模型上下文。
src/main/core/agent/research-loop-guard.ts 新增 WebSearchRunGuard:单次运行 webSearch 预算/失败熔断/工具移除策略。
src/main/core/agent/tests/web-search.test.ts 覆盖结构化失败投影、绝对日期优先、400 非重试、503 内部一次重试等行为。
src/main/core/agent/tests/research-loop-guard.test.ts 覆盖 WebSearchRunGuard:重复失败调用拦截、连续失败熔断、预算上限等行为。

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +111 to +126
const waitForRetry = (signal: AbortSignal): Promise<void> =>
new Promise((resolve, reject) => {
if (signal.aborted) {
reject(signal.reason);
return;
}
const timer = setTimeout(resolve, TRANSIENT_RETRY_DELAY_MS);
signal.addEventListener(
"abort",
() => {
clearTimeout(timer);
reject(signal.reason);
},
{ once: true },
);
});

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 93b79aa. waitForRetry now keeps a stable onAbort reference and removes it before resolving a completed retry delay. Added a regression test that verifies the exact registered callback is removed. Verified with lint, typecheck, build, and the full test suite (3547 tests).

- remove the task abort listener when a retry delay completes normally

- verify cleanup uses the same callback reference registered for the delay
@wangkailang
wangkailang merged commit 8834725 into main Jul 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants