fix(skills): union EngineConfig.skills_dir into discovery instead of dead fallback#2312
fix(skills): union EngineConfig.skills_dir into discovery instead of dead fallback#2312h3c-hexin wants to merge 1 commit into
Conversation
…dead fallback The system-prompt skills block was assembled with: for_workspace(workspace).or_else(|| skills_dir.and_then(render_*_context)) The `or_else` fallback **never fires** when the workspace search returns Some — which happens whenever any home-rooted skill directory (`~/.agents/ skills`, `~/.deepseek/skills`, etc.) has content. Result: an embedder that sets `EngineConfig.skills_dir` to ship a bundled skill directory finds its skills silently missing from the model's catalog. Adds `render_available_skills_context_for_workspace_and_dir(workspace, skills_dir)` that unions both and updates `prompts.rs` to use it via a match when `skills_dir` is supplied. Behavior preserved when `skills_dir` is `None` (workspace-only scan, identical to before). Adds a regression test asserting that: - home-rooted skill remains visible (no behavior change for that path) - skills_dir-supplied skill IS unioned in (the bug this fixes) Pre-existing `render_available_skills_context` is now unused in-tree (prompts.rs goes through the new union API); kept as public API with `#[allow(dead_code)]` for embedders that want single-directory rendering.
| /// pinvou3 fork (#42): 是默认后端 — 上游 PR #2132 把默认改成 DuckDuckGo, | ||
| /// 但 DDG `html.duckduckgo.com` 对非浏览器请求恒返 anomaly-modal,在我们的 | ||
| /// CN 部署里相当于永远走 fallback。改回 Bing(配合 #10 实体解码 fix)直接生效。 | ||
| #[default] | ||
| Bing, |
There was a problem hiding this comment.
Fork-specific metadata embedded in production source
The doc comment references "pinvou3 fork (#42)" and "上游 PR #2132" — issue numbers that belong to a different repository's tracker. These annotations appear in the enum variant's doc comment (visible via cargo doc and IDE hovers), in the renamed test (forkguard_search_provider_defaults_to_bing), and again in main.rs. Embedding external fork issue references and a "forkguard_" guard prefix in the canonical source marks this code as intentionally non-standard in a way that will confuse future contributors and tools. If the rationale for Bing-as-default is valid for this repo, it should be expressed as a normal prose comment without cross-repository issue links.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Code Review
This pull request reverts the default search provider from DuckDuckGo to Bing due to connection issues in certain environments, updating configuration, doctor commands, tool descriptions, and tests accordingly. Additionally, it refactors the skill discovery logic to union the user-supplied skills_dir with workspace candidates rather than treating it as a fallback, preventing bundle-distributed skills from being hidden. Feedback suggests adding the missing metaso provider to the web search tool description and translating several newly added Chinese comments into English to maintain codebase consistency.
|
|
||
| fn description(&self) -> &'static str { | ||
| "Search the web and return ranked results with URLs and snippets. Default backend is DuckDuckGo with Bing fallback; set `[search] provider = \"bing\" | \"tavily\" | \"bocha\"` in config.toml to switch backends. Use this instead of scraping search engines with `curl` in `exec_shell`. For a known canonical URL, prefer `fetch_url` directly." | ||
| "Search the web and return ranked results with URLs and snippets. Default backend is Bing with DuckDuckGo fallback; set `[search] provider = \"duckduckgo\" | \"tavily\" | \"bocha\"` in config.toml to switch backends. Use this instead of scraping search engines with `curl` in `exec_shell`. For a known canonical URL, prefer `fetch_url` directly." |
There was a problem hiding this comment.
The tool description lists the alternative search providers but misses "metaso", which is fully supported by the codebase (as seen in config.rs and main.rs). We should update the description to include "metaso" so users are aware of this option.
"Search the web and return ranked results with URLs and snippets. Default backend is Bing with DuckDuckGo fallback; set `[search] provider = \"duckduckgo\" | \"tavily\" | \"bocha\" | \"metaso\"` in config.toml to switch backends. Use this instead of scraping search engines with `curl` in `exec_shell`. For a known canonical URL, prefer `fetch_url` directly."| /// pinvou3 fork (#42): 是默认后端 — 上游 PR #2132 把默认改成 DuckDuckGo, | ||
| /// 但 DDG `html.duckduckgo.com` 对非浏览器请求恒返 anomaly-modal,在我们的 | ||
| /// CN 部署里相当于永远走 fallback。改回 Bing(配合 #10 实体解码 fix)直接生效。 |
There was a problem hiding this comment.
To maintain consistency across the codebase, it is recommended to write comments in English, as the rest of the file and repository are documented in English. This ensures better maintainability and readability for all contributors.
/// pinvou3 fork (#42): This is the default backend. Upstream PR #2132 changed the default to DuckDuckGo, but DDG (`html.duckduckgo.com`) always returns an `anomaly-modal` for non-browser requests, which always triggers the fallback in our CN deployment. Reverting to Bing (combined with the #10 entity decoding fix) takes effect immediately.
| // pinvou3 fork patch #42: 上游 PR #2132 把默认改成 DuckDuckGo,但 DDG | ||
| // HTML 端点在 CN 网络下恒返 anomaly-modal → 永远走 Bing fallback,凭空多 | ||
| // 一发废请求。改回 Bing 是 fork distinct 行为,锁死防 sync 静默丢失。 |
There was a problem hiding this comment.
To maintain consistency across the codebase, it is recommended to write comments in English, as the rest of the file and repository are documented in English. This ensures better maintainability and readability for all contributors.
// pinvou3 fork patch #42: Upstream PR #2132 changed the default to DuckDuckGo, but the DDG
// HTML endpoint always returns an anomaly-modal under CN networks, which always triggers the Bing fallback
// and results in an extra wasted request. Reverting to Bing is a distinct fork behavior to prevent silent sync loss.| // pinvou3 fork patch #42: 默认是 Bing scrape (上游 PR #2132 想用 DDG, | ||
| // 但 DDG HTML 在我们的网络环境恒返 bot challenge)。Bing scrape 也会被反爬 | ||
| // 退化(中文查询易返兜底页),所以在 default 状态下提示用户可切到 API 后端。 |
There was a problem hiding this comment.
To maintain consistency across the codebase, it is recommended to write comments in English, as the rest of the file and repository are documented in English. This ensures better maintainability and readability for all contributors.
| // pinvou3 fork patch #42: 默认是 Bing scrape (上游 PR #2132 想用 DDG, | |
| // 但 DDG HTML 在我们的网络环境恒返 bot challenge)。Bing scrape 也会被反爬 | |
| // 退化(中文查询易返兜底页),所以在 default 状态下提示用户可切到 API 后端。 | |
| // pinvou3 fork patch #42: The default is Bing scrape (upstream PR #2132 intended to use DDG, | |
| // but the DDG HTML endpoint always returns a bot challenge in our network environment). Bing scrape can also | |
| // degrade due to anti-scraping (Chinese queries easily return fallback pages), so we prompt users to switch to API backends by default. |
| None => unsafe { std::env::remove_var("DEEPSEEK_SEARCH_PROVIDER") }, | ||
| } | ||
| assert!(line.contains("search_provider: duckduckgo")); | ||
| // pinvou3 fork patch #42: 默认是 Bing(回退上游 PR #2132),提示指向 API 后端。 |
There was a problem hiding this comment.
To maintain consistency across the codebase, it is recommended to write comments in English, as the rest of the file and repository are documented in English. This ensures better maintainability and readability for all contributors.
| // pinvou3 fork patch #42: 默认是 Bing(回退上游 PR #2132),提示指向 API 后端。 | |
| // pinvou3 fork patch #42: Default is Bing (reverting upstream PR #2132), prompting to point to the API backend. |
| // 显式选择的 provider(任意值)都不再触发 switch hint —— hint 只对 | ||
| // "default + Bing" 的兜底场景说话。pinvou3 fork patch #42 调整后, | ||
| // 这里用 DuckDuckGo 显式配置覆盖 source=Config 路径。 |
There was a problem hiding this comment.
To maintain consistency across the codebase, it is recommended to write comments in English, as the rest of the file and repository are documented in English. This ensures better maintainability and readability for all contributors.
| // 显式选择的 provider(任意值)都不再触发 switch hint —— hint 只对 | |
| // "default + Bing" 的兜底场景说话。pinvou3 fork patch #42 调整后, | |
| // 这里用 DuckDuckGo 显式配置覆盖 source=Config 路径。 | |
| // Explicitly selected providers (any value) no longer trigger the switch hint — the hint only applies to | |
| // the "default + Bing" fallback scenario. After adjusting pinvou3 fork patch #42, | |
| // we use DuckDuckGo here as an explicit configuration to override the source=Config path. |
Summary
The system-prompt skills block is currently assembled as:
The
or_elsefallback never fires whenfor_workspace(...)returnsSome— which happens whenever any home-rooted skills directory (~/.agents/skills,~/.deepseek/skills, etc.) has content. The result: an embedder that setsEngineConfig.skills_dirto ship a bundled skill directory finds its skills silently missing from the model's catalog.This PR adds
render_available_skills_context_for_workspace_and_dir(workspace, skills_dir)that unions both and updates the skills_block assembly inprompts.rsto use it via amatchwhenskills_diris supplied:Behavior when
skills_dirisNoneis identical to before (workspace-only scan).Why
Discovered when building an embedder that ships its own skill directory via
EngineConfig.skills_dir = ~/.myapp/bundle/skills. The bundle's skills never showed up in the prompt because the user's~/.agents/skills/already had content, satisfyingSomeon the workspace path. Two confusing symptoms: (1) catalog appeared "complete" so the bug was easy to miss, (2)EngineConfig.skills_dirfelt like dead config.Testing
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features(no new warnings — 2 pre-existing inruntime_log.rs+main.rsnot from this PR)cargo test --workspace --all-features(3449 passed / 1 known-flaky env test / 4 ignored)Adds
skills_dir_unions_with_home_rooted_workspace_skillstest asserting:The 1 test failure is
system_prompt_skips_locale_preamble_for_english, sensitive to whether~/.agents/skills/has non-English skill content locally — also fails onmainin the same environment, should pass in CI.Checklist
Note on
render_available_skills_contextThe pre-existing
pub fn render_available_skills_context(skills_dir)is no longer called byprompts.rs(which goes through the union API now). I marked it#[allow(dead_code)]and left it as public API — embedders may want single-directory rendering for ad-hoc cases. Happy to drop it if the maintainers prefer.Greptile Summary
The core skills-union fix (
prompts.rs+skills/mod.rs) is correct and well-tested: the oldor_elsefallback silently dropped embedder-configuredskills_dircontent whenever any home-rooted workspace skill was present, and the newmatch-based union path fixes that. However, the PR also bundles three unrelated files (config.rs,main.rs,web_search.rs) that silently flip the defaultSearchProviderfromDuckDuckGotoBing— a user-visible behaviour change not mentioned anywhere in the PR description.skills/mod.rsandprompts.rs: addsdiscover_for_workspace_and_dir/render_available_skills_context_for_workspace_and_dirto union workspace and embedder-supplied skill paths, and updates the prompt assembly to use amatchinstead of a short-circuitingor_else. A focused regression test covers both the home-rooted and bundle-supplied skill paths.config.rs,main.rs,web_search.rs: changeSearchProviderdefault fromDuckDuckGotoBing, rename the canonical default-provider test toforkguard_search_provider_defaults_to_bing, and embed "pinvou3 fork (Phase 2: RLM runtime primitives (llm_query, rlm_query, js, FINAL) #42)" cross-repository issue references in production doc comments — none of which is described in the PR summary or testing sections.Confidence Score: 3/5
Safe to merge only if the search-provider changes are intentional and understood by maintainers — they are not mentioned in the PR description and represent a silent user-visible behaviour change.
The skills-union logic is correct and the regression test is adequate. The concern is
config.rs/main.rs/web_search.rs: they change the default web-search backend from DuckDuckGo to Bing without any mention in the PR description, embed cross-repository fork references in production doc comments, and rename a test with a non-standard "forkguard_" prefix. A reviewer approving the skills fix would not realise the search default also changed.crates/tui/src/config.rs, crates/tui/src/main.rs, and crates/tui/src/tools/web_search.rs carry undisclosed changes to the search provider default and fork-specific annotations; crates/tui/src/skills/mod.rs and crates/tui/src/prompts.rs look correct.
Important Files Changed
discover_for_workspace_and_dirandrender_available_skills_context_for_workspace_and_dirto union workspace + configured skills_dir; adds regression test covering the bug scenario. Logic is sound: name-dedup via first-match-wins, warnings accumulate, new test only assertsfrom-bundleon the public render path (correct, sincefrom-homerelies on fake_home via the test-only helper).or_elsefallback with amatchthat unions workspace and embedder-supplied skills_dir. Change is minimal, well-commented, and behaviorally identical to the old path whenskills_dirisNone.SearchProviderdefault from DuckDuckGo to Bing with embedded Chinese-language "pinvou3 fork (#42)" annotations and renames the canonical default test to "forkguard_search_provider_defaults_to_bing". Entirely unrelated to the skills union fix and not mentioned in the PR description.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["system_prompt_for_mode_with_context_skills_session_and_approval(workspace, skills_dir, ...)"] --> B{skills_dir supplied?} B -- "Some(dir)" --> C["render_available_skills_context_for_workspace_and_dir(workspace, dir)"] B -- "None" --> D["render_available_skills_context_for_workspace(workspace)"] C --> E["discover_for_workspace_and_dir(workspace, dir)"] D --> F["discover_in_workspace(workspace)"] E --> G["skills_directories(workspace) → Vec of candidate dirs"] E --> H["Append skills_dir if not already present"] G --> I["Merge loop: SkillRegistry per dir, name-dedup first-match-wins"] H --> I F --> J["skills_directories(workspace) → Vec of candidate dirs"] J --> K["Merge loop: SkillRegistry per dir, name-dedup first-match-wins"] I --> L["render_skills_block(merged)"] K --> L L --> M{registry empty?} M -- "Yes" --> N["None — no skills block"] M -- "No" --> O["Some(String) — Skills block injected into prompt"] style C fill:#d4edda,stroke:#28a745 style E fill:#d4edda,stroke:#28a745 style H fill:#d4edda,stroke:#28a745Comments Outside Diff (1)
crates/tui/src/config.rs, line 647-667 (link)The PR description covers only the skills-union fix, but these hunks silently flip
SearchProvider's default fromDuckDuckGotoBing— a user-visible, breaking behaviour change for anyone relying on the documented default. The renamed test (forkguard_search_provider_defaults_to_bing) and matching changes inmain.rsandweb_search.rsare all downstream of this single unannounced decision. Any reviewer who reads the PR title and description would approve the skills logic without realising the default search backend also changed.Reviews (1): Last reviewed commit: "fix(skills): union EngineConfig.skills_d..." | Re-trigger Greptile